Netdev List
 help / color / mirror / Atom feed
* [PATCH v4 0/4] net: phy: realtek: Enable configuration of RTL8211E LEDs
From: Matthias Kaehlcke @ 2019-08-01 19:07 UTC (permalink / raw)
  To: David S . Miller, Rob Herring, Mark Rutland, Andrew Lunn,
	Florian Fainelli, Heiner Kallweit
  Cc: netdev, devicetree, linux-kernel, Douglas Anderson,
	Matthias Kaehlcke

The Realtek RTL8211E allows customization of the PHY LED behavior,
like which LEDs are on for certain link speeds and which LEDs blink
when there is traffic. By default EEE LED mode is enabled, in which
a blinking LED is on for 400ms and off for 2s. This series adds a
generic device tree binding for configuring PHY LEDs and adds LED
configuration support for the RTL8211E PHY.

Certain registers of the RTL8211E can only be accessed through
a vendor specific extended page mechanism. Extended pages need
to be accessed for the LED configuration. This series adds helpers
to facilitate accessing extended pages.

Matthias Kaehlcke (4):
  dt-bindings: net: phy: Add subnode for LED configuration
  net: phy: Add function to retrieve LED configuration from the DT
  net: phy: realtek: Add helpers for accessing RTL8211E extension pages
  net: phy: realtek: configure RTL8211E LEDs

 .../devicetree/bindings/net/ethernet-phy.yaml |  47 +++++
 drivers/net/phy/phy_device.c                  |  50 ++++++
 drivers/net/phy/realtek.c                     | 169 ++++++++++++++++--
 include/linux/phy.h                           |  15 ++
 4 files changed, 266 insertions(+), 15 deletions(-)

-- 
2.22.0.770.g0f2c4a37fd-goog


^ permalink raw reply

* [PATCH v4 2/4] net: phy: Add function to retrieve LED configuration from the DT
From: Matthias Kaehlcke @ 2019-08-01 19:07 UTC (permalink / raw)
  To: David S . Miller, Rob Herring, Mark Rutland, Andrew Lunn,
	Florian Fainelli, Heiner Kallweit
  Cc: netdev, devicetree, linux-kernel, Douglas Anderson,
	Matthias Kaehlcke
In-Reply-To: <20190801190759.28201-1-mka@chromium.org>

Add a phylib function for retrieving PHY LED configuration that
is specified in the device tree using the generic binding. LEDs
can be configured to be 'on' for a certain link speed or to blink
when there is TX/RX activity.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v4:
- patch added to the series
---
 drivers/net/phy/phy_device.c | 50 ++++++++++++++++++++++++++++++++++++
 include/linux/phy.h          | 15 +++++++++++
 2 files changed, 65 insertions(+)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 6b5cb87f3866..b4b48de45712 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2188,6 +2188,56 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv)
 	return phydrv->config_intr && phydrv->ack_interrupt;
 }
 
+int of_get_phy_led_cfg(struct phy_device *phydev, int led,
+		       struct phy_led_config *cfg)
+{
+	struct device_node *np, *child;
+	const char *trigger;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_OF_MDIO))
+		return -ENOENT;
+
+	np = of_find_node_by_name(phydev->mdio.dev.of_node, "leds");
+	if (!np)
+		return -ENOENT;
+
+	for_each_child_of_node(np, child) {
+		u32 val;
+
+		if (!of_property_read_u32(child, "reg", &val)) {
+			if (val == (u32)led)
+				break;
+		}
+	}
+
+	if (!child)
+		return -ENOENT;
+
+	ret = of_property_read_string(child, "linux,default-trigger",
+				      &trigger);
+	if (ret)
+		return ret;
+
+	if (!strcmp(trigger, "phy_link_10m_active")) {
+		cfg->trigger = PHY_LED_LINK_10M;
+	} else if (!strcmp(trigger, "phy_link_100m_active")) {
+		cfg->trigger = PHY_LED_LINK_100M;
+	} else if (!strcmp(trigger, "phy_link_1g_active")) {
+		cfg->trigger = PHY_LED_LINK_1G;
+	} else if (!strcmp(trigger, "phy_link_10g_active")) {
+		cfg->trigger = PHY_LED_LINK_10G;
+	}  else if (!strcmp(trigger, "phy_activity")) {
+		cfg->trigger = PHY_LED_ACTIVITY;
+	} else {
+		phydev_warn(phydev, "trigger '%s' for LED%d is invalid\n",
+			    trigger, led);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * phy_probe - probe and init a PHY device
  * @dev: device to probe and init
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 462b90b73f93..b4693415be31 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1176,6 +1176,21 @@ int phy_ethtool_set_link_ksettings(struct net_device *ndev,
 				   const struct ethtool_link_ksettings *cmd);
 int phy_ethtool_nway_reset(struct net_device *ndev);
 
+enum phy_led_trigger {
+	PHY_LED_LINK_10M,
+	PHY_LED_LINK_100M,
+	PHY_LED_LINK_1G,
+	PHY_LED_LINK_10G,
+	PHY_LED_ACTIVITY,
+};
+
+struct phy_led_config {
+	enum phy_led_trigger trigger;
+};
+
+int of_get_phy_led_cfg(struct phy_device *phydev, int led,
+		       struct phy_led_config *cfg);
+
 #if IS_ENABLED(CONFIG_PHYLIB)
 int __init mdio_bus_init(void);
 void mdio_bus_exit(void);
-- 
2.22.0.770.g0f2c4a37fd-goog


^ permalink raw reply related

* [PATCH v4 1/4] dt-bindings: net: phy: Add subnode for LED configuration
From: Matthias Kaehlcke @ 2019-08-01 19:07 UTC (permalink / raw)
  To: David S . Miller, Rob Herring, Mark Rutland, Andrew Lunn,
	Florian Fainelli, Heiner Kallweit
  Cc: netdev, devicetree, linux-kernel, Douglas Anderson,
	Matthias Kaehlcke
In-Reply-To: <20190801190759.28201-1-mka@chromium.org>

The LED behavior of some Ethernet PHYs is configurable. Add an
optional 'leds' subnode with a child node for each LED to be
configured. The binding aims to be compatible with the common
LED binding (see devicetree/bindings/leds/common.txt).

A LED can be configured to be 'on' when a link with a certain speed
is active, or to blink on RX/TX activity. For the configuration to
be effective it needs to be supported by the hardware and the
corresponding PHY driver.

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v4:
- patch added to the series
---
 .../devicetree/bindings/net/ethernet-phy.yaml | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/ethernet-phy.yaml b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
index f70f18ff821f..81c5aacc89a5 100644
--- a/Documentation/devicetree/bindings/net/ethernet-phy.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-phy.yaml
@@ -153,6 +153,38 @@ properties:
       Delay after the reset was deasserted in microseconds. If
       this property is missing the delay will be skipped.
 
+patternProperties:
+  "^leds$":
+    type: object
+    description:
+      Subnode with configuration of the PHY LEDs.
+
+    patternProperties:
+      "^led@[0-9]+$":
+        type: object
+        description:
+          Subnode with the configuration of a single PHY LED.
+
+    properties:
+      reg:
+        description:
+          The ID number of the LED, typically corresponds to a hardware ID.
+        $ref: "/schemas/types.yaml#/definitions/uint32"
+
+      linux,default-trigger:
+        description:
+          This parameter, if present, is a string specifying the trigger
+          assigned to the LED. Supported triggers are:
+            "phy_link_10m_active" - LED will be on when a 10Mb/s link is active
+            "phy_link_100m_active" - LED will be on when a 100Mb/s link is active
+            "phy_link_1g_active" - LED will be on when a 1Gb/s link is active
+            "phy_link_10g_active" - LED will be on when a 10Gb/s link is active
+            "phy_activity" - LED will blink when data is received or transmitted
+        $ref: "/schemas/types.yaml#/definitions/string"
+
+    required:
+      - reg
+
 required:
   - reg
 
@@ -173,5 +205,20 @@ examples:
             reset-gpios = <&gpio1 4 1>;
             reset-assert-us = <1000>;
             reset-deassert-us = <2000>;
+
+            leds {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                led@0 {
+                    reg = <0>;
+                    linux,default-trigger = "phy_link_1g_active";
+                };
+
+                led@1 {
+                    reg = <1>;
+                    linux,default-trigger = "phy_activity";
+                };
+            };
         };
     };
-- 
2.22.0.770.g0f2c4a37fd-goog


^ permalink raw reply related

* [PATCH v4 4/4] net: phy: realtek: configure RTL8211E LEDs
From: Matthias Kaehlcke @ 2019-08-01 19:07 UTC (permalink / raw)
  To: David S . Miller, Rob Herring, Mark Rutland, Andrew Lunn,
	Florian Fainelli, Heiner Kallweit
  Cc: netdev, devicetree, linux-kernel, Douglas Anderson,
	Matthias Kaehlcke
In-Reply-To: <20190801190759.28201-1-mka@chromium.org>

Configure the RTL8211E LEDs behavior when the device tree property
'realtek,led-modes' is specified.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v4:
- use the generic PHY LED binding
- keep default/current configuration if none is specified
- added rtl8211e_disable_eee_led_mode()
  - was previously in separate patch, however since we always want to
    disable EEE LED mode when a LED configuration is specified it makes
    sense to just add the function here.
- don't call phy_restore_page() in rtl8211e_config_leds() if
  selection of the extended page failed.
- use phydev_warn() instead of phydev_err() if LED configuration
  fails since we don't bail out
- use hex number to specify page for consistency
- add hex number to comment about ext page 44 to facilitate searching
---
 drivers/net/phy/realtek.c | 121 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 1 deletion(-)

diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index e09d3b0da2c7..46e3d77d41b6 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -9,8 +9,11 @@
  * Copyright (c) 2004 Freescale Semiconductor, Inc.
  */
 #include <linux/bitops.h>
-#include <linux/phy.h>
+#include <linux/bits.h>
 #include <linux/module.h>
+#include <linux/phy.h>
+
+#define RTL821x_NUM_LEDS			3
 
 #define RTL821x_PHYSR				0x11
 #define RTL821x_PHYSR_DUPLEX			BIT(13)
@@ -26,6 +29,19 @@
 #define RTL821x_EXT_PAGE_SELECT			0x1e
 #define RTL821x_PAGE_SELECT			0x1f
 
+/* RTL8211E page 5 */
+#define RTL8211E_EEE_LED_MODE1			0x05
+#define RTL8211E_EEE_LED_MODE2			0x06
+
+/* RTL8211E extension page 44 (0x2c) */
+#define RTL8211E_LACR				0x1a
+#define RLT8211E_LACR_LEDACTCTRL_SHIFT		4
+#define RLT8211E_LACR_LEDACTCTRL_MASK		GENMASK(6, 4)
+#define RTL8211E_LCR				0x1c
+#define RTL8211E_LCR_LEDCTRL_MASK		(GENMASK(2, 0) | \
+						 GENMASK(6, 4) | \
+						 GENMASK(10, 8))
+
 #define RTL8211F_INSR				0x1d
 
 #define RTL8211F_TX_DELAY			BIT(8)
@@ -83,6 +99,105 @@ static int rtl8211e_modify_ext_paged(struct phy_device *phydev, int page,
 	return phy_restore_page(phydev, oldpage, ret);
 }
 
+static void rtl8211e_disable_eee_led_mode(struct phy_device *phydev)
+{
+	int oldpage;
+	int err = 0;
+
+	oldpage = phy_select_page(phydev, 5);
+	if (oldpage < 0)
+		goto out;
+
+	/* write magic values to disable EEE LED mode */
+	err = __phy_write(phydev, RTL8211E_EEE_LED_MODE1, 0x8b82);
+	if (err)
+		goto out;
+
+	err = __phy_write(phydev, RTL8211E_EEE_LED_MODE2, 0x052b);
+
+out:
+	phy_restore_page(phydev, oldpage, err);
+}
+
+static int rtl8211e_config_leds(struct phy_device *phydev)
+{
+	int i, oldpage, ret;
+	u16 lacr_bits = 0, lcr_bits = 0;
+	u16 lacr_mask = RLT8211E_LACR_LEDACTCTRL_MASK;
+	u16 lcr_mask = RTL8211E_LCR_LEDCTRL_MASK;
+	bool eed_led_mode_disabled = false;
+
+	for (i = 0; i < RTL821x_NUM_LEDS; i++) {
+		struct phy_led_config cfg;
+
+		ret = of_get_phy_led_cfg(phydev, i, &cfg);
+		if (ret) {
+			lacr_mask &= ~BIT(4 + i);
+			lcr_mask &= ~GENMASK((i * 4) + 2, i * 4);
+			continue;
+		}
+
+		if (!eed_led_mode_disabled) {
+			rtl8211e_disable_eee_led_mode(phydev);
+			eed_led_mode_disabled = true;
+		}
+
+		switch (cfg.trigger) {
+		case PHY_LED_LINK_10M:
+			lcr_bits |= 1 << (i * 4);
+			break;
+
+		case PHY_LED_LINK_100M:
+			lcr_bits |= 2 << (i * 4);
+			break;
+
+		case PHY_LED_LINK_1G:
+			lcr_bits |= 4 << (i * 4);
+			break;
+
+		case PHY_LED_ACTIVITY:
+			lacr_bits |= BIT(RLT8211E_LACR_LEDACTCTRL_SHIFT + i);
+			break;
+
+		default:
+			phydev_warn(phydev,
+				    "unknown trigger for LED%d: %d\n",
+				    i, cfg.trigger);
+		}
+	}
+
+	oldpage = rtl8211e_select_ext_page(phydev, 0x2c);
+	if (oldpage < 0) {
+		phydev_err(phydev, "failed to select extended page: %d\n", oldpage);
+		return oldpage;
+	}
+
+	if (lacr_mask == 0)
+		goto skip_lacr;
+
+	ret = __phy_modify(phydev, RTL8211E_LACR,
+			   lacr_mask, lacr_bits);
+	if (ret) {
+		phydev_err(phydev, "failed to write LACR reg: %d\n",
+			   ret);
+		goto err;
+	}
+
+skip_lacr:
+	if (lcr_mask == 0)
+		goto skip_lcr;
+
+	ret = __phy_modify(phydev, RTL8211E_LCR,
+			   lcr_mask, lcr_bits);
+	if (ret)
+		phydev_err(phydev, "failed to write LCR reg: %d\n",
+			   ret);
+
+skip_lcr:
+err:
+	return phy_restore_page(phydev, oldpage, ret);
+}
+
 static int rtl8201_ack_interrupt(struct phy_device *phydev)
 {
 	int err;
@@ -217,6 +332,10 @@ static int rtl8211e_config_init(struct phy_device *phydev)
 	int ret;
 	u16 val;
 
+	ret = rtl8211e_config_leds(phydev);
+	if (ret)
+		phydev_warn(phydev, "LED configuration failed: %d\n", ret);
+
 	/* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
 	switch (phydev->interface) {
 	case PHY_INTERFACE_MODE_RGMII:
-- 
2.22.0.770.g0f2c4a37fd-goog


^ permalink raw reply related

* [PATCH v4 3/4] net: phy: realtek: Add helpers for accessing RTL8211E extension pages
From: Matthias Kaehlcke @ 2019-08-01 19:07 UTC (permalink / raw)
  To: David S . Miller, Rob Herring, Mark Rutland, Andrew Lunn,
	Florian Fainelli, Heiner Kallweit
  Cc: netdev, devicetree, linux-kernel, Douglas Anderson,
	Matthias Kaehlcke
In-Reply-To: <20190801190759.28201-1-mka@chromium.org>

The RTL8211E has extension pages, which can be accessed after
selecting a page through a custom method. Add a function to
modify bits in a register of an extension page and a helper for
selecting an ext page. Use rtl8211e_modify_ext_paged() in
rtl8211e_config_init() instead of doing things 'manually'.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v4:
- don't add constant RTL8211E_EXT_PAGE, it's only used once,
  use a literal instead
- pass 'oldpage' to phy_restore_page() in rtl8211e_select_ext_page(),
  not 'page'
- return 'oldpage' in rtl8211e_select_ext_page()
- use __phy_modify() in rtl8211e_modify_ext_paged() instead of
  reimplementing __phy_modify_changed()
- in rtl8211e_modify_ext_paged() return directly when
  rtl8211e_select_ext_page() fails
---
 drivers/net/phy/realtek.c | 48 +++++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index a669945eb829..e09d3b0da2c7 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -53,6 +53,36 @@ static int rtl821x_write_page(struct phy_device *phydev, int page)
 	return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
 }
 
+static int rtl8211e_select_ext_page(struct phy_device *phydev, int page)
+{
+	int ret, oldpage;
+
+	oldpage = phy_select_page(phydev, 7);
+	if (oldpage < 0)
+		return oldpage;
+
+	ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, page);
+	if (ret)
+		return phy_restore_page(phydev, oldpage, ret);
+
+	return oldpage;
+}
+
+static int rtl8211e_modify_ext_paged(struct phy_device *phydev, int page,
+				     u32 regnum, u16 mask, u16 set)
+{
+	int ret = 0;
+	int oldpage;
+
+	oldpage = rtl8211e_select_ext_page(phydev, page);
+	if (oldpage < 0)
+		return oldpage;
+
+	ret = __phy_modify(phydev, regnum, mask, set);
+
+	return phy_restore_page(phydev, oldpage, ret);
+}
+
 static int rtl8201_ack_interrupt(struct phy_device *phydev)
 {
 	int err;
@@ -184,7 +214,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)
 
 static int rtl8211e_config_init(struct phy_device *phydev)
 {
-	int ret = 0, oldpage;
+	int ret;
 	u16 val;
 
 	/* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
@@ -213,19 +243,9 @@ static int rtl8211e_config_init(struct phy_device *phydev)
 	 * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet
 	 * for details).
 	 */
-	oldpage = phy_select_page(phydev, 0x7);
-	if (oldpage < 0)
-		goto err_restore_page;
-
-	ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
-	if (ret)
-		goto err_restore_page;
-
-	ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
-			   val);
-
-err_restore_page:
-	return phy_restore_page(phydev, oldpage, ret);
+	return rtl8211e_modify_ext_paged(phydev, 0xa4, 0x1c,
+					 RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
+					 val);
 }
 
 static int rtl8211b_suspend(struct phy_device *phydev)
-- 
2.22.0.770.g0f2c4a37fd-goog


^ permalink raw reply related

* [PATCH net-next 06/15] selftests: Add ipv6 tcp tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add IPv6 tcp tests to fcnal-test.sh. Covers the permutations of directly
connected addresses, routed destinations, VRF and non-VRF, and expected
failures for both clients and servers. Includes permutations with
net.ipv4.tcp_l3mdev_accept set to 0 and 1.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 370 +++++++++++++++++++++++++++++-
 1 file changed, 369 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index f9e2f1464dcd..97291c6d17c5 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -1304,6 +1304,373 @@ ipv6_ping()
 }
 
 ################################################################################
+# IPv6 TCP
+
+ipv6_tcp_novrf()
+{
+	local a
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		run_cmd nettest -6 -s &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+	done
+
+	# verify TCP reset received
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	#
+	# client
+	#
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV}
+	do
+		log_start
+		run_cmd_nsb nettest -6 -s &
+		sleep 1
+		run_cmd nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "Client"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV}
+	do
+		log_start
+		run_cmd_nsb nettest -6 -s &
+		sleep 1
+		run_cmd nettest -6 -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 0 "Client, device bind"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -6 -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "No server, device client"
+	done
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ::1
+	do
+		log_start
+		run_cmd nettest -6 -s &
+		sleep 1
+		run_cmd nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "Global server, local connection"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -r ${a} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, unbound client, local connection"
+
+	for a in ${NSA_LO_IP6} ::1
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since addresses on loopback are out of device scope"
+		run_cmd nettest -6 -s -d ${NSA_DEV} &
+		sleep 1
+		run_cmd nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "Device server, unbound client, local connection"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s &
+	sleep 1
+	run_cmd nettest -6 -r ${a} -d ${NSA_DEV} -0 ${a}
+	log_test_addr ${a} $? 0 "Global server, device client, local connection"
+
+	for a in ${NSA_LO_IP6} ::1
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since addresses on loopback are out of device scope"
+		run_cmd nettest -6 -s &
+		sleep 1
+		run_cmd nettest -6 -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "Global server, device client, local connection"
+	done
+
+	for a in ${NSA_IP6} ${NSA_LINKIP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd nettest -6  -d ${NSA_DEV} -r ${a}
+		log_test_addr ${a} $? 0 "Device server, device client, local conn"
+	done
+
+	for a in ${NSA_IP6} ${NSA_LINKIP6}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -6 -d ${NSA_DEV} -r ${a}
+		log_test_addr ${a} $? 1 "No server, device client, local conn"
+	done
+}
+
+ipv6_tcp_vrf()
+{
+	local a
+
+	# disable global server
+	log_subsection "Global server disabled"
+
+	set_sysctl net.ipv4.tcp_l3mdev_accept=0
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since global server with VRF is disabled"
+		run_cmd nettest -6 -s &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "Global server"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+	done
+
+	# link local is always bound to ingress device
+	a=${NSA_LINKIP6}%${NSB_DEV}
+	log_start
+	run_cmd nettest -6 -s -d ${VRF} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -6 -r ${a}
+	log_test_addr ${a} $? 0 "VRF server"
+
+	for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "Device server"
+	done
+
+	# verify TCP reset received
+	for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	# local address tests
+	a=${NSA_IP6}
+	log_start
+	show_hint "Should fail 'Connection refused' since global server with VRF is disabled"
+	run_cmd nettest -6 -s &
+	sleep 1
+	run_cmd nettest -6 -r ${a} -d ${NSA_DEV}
+	log_test_addr ${a} $? 1 "Global server, local connection"
+
+	#
+	# enable VRF global server
+	#
+	log_subsection "VRF Global server enabled"
+	set_sysctl net.ipv4.tcp_l3mdev_accept=1
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -2 ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+	done
+
+	# For LLA, child socket is bound to device
+	a=${NSA_LINKIP6}%${NSB_DEV}
+	log_start
+	run_cmd nettest -6 -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -6 -r ${a}
+	log_test_addr ${a} $? 0 "Global server"
+
+	log_start
+	run_cmd nettest -6 -s -d ${VRF} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -6 -r ${a}
+	log_test_addr ${a} $? 0 "VRF server"
+
+	for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 0 "Device server"
+	done
+
+	# verify TCP reset received
+	for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	# local address tests
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		show_hint "Fails 'No route to host' since client is not in VRF"
+		run_cmd nettest -6 -s -2 ${VRF} &
+		sleep 1
+		run_cmd nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "Global server, local connection"
+	done
+
+
+	#
+	# client
+	#
+	for a in ${NSB_IP6} ${NSB_LO_IP6}
+	do
+		log_start
+		run_cmd_nsb nettest -6 -s &
+		sleep 1
+		run_cmd nettest -6 -r ${a} -d ${VRF}
+		log_test_addr ${a} $? 0 "Client, VRF bind"
+	done
+
+	a=${NSB_LINKIP6}
+	log_start
+	show_hint "Fails since VRF device does not allow linklocal addresses"
+	run_cmd_nsb nettest -6 -s &
+	sleep 1
+	run_cmd nettest -6 -r ${a} -d ${VRF}
+	log_test_addr ${a} $? 1 "Client, VRF bind"
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}
+	do
+		log_start
+		run_cmd_nsb nettest -6 -s &
+		sleep 1
+		run_cmd nettest -6 -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 0 "Client, device bind"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -6 -r ${a} -d ${VRF}
+		log_test_addr ${a} $? 1 "No server, VRF client"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -6 -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "No server, device client"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6} ::1
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd nettest -6 -r ${a} -d ${VRF} -0 ${a}
+		log_test_addr ${a} $? 0 "VRF server, VRF client, local connection"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s -d ${VRF} -2 ${VRF} &
+	sleep 1
+	run_cmd nettest -6 -r ${a} -d ${NSA_DEV} -0 ${a}
+	log_test_addr ${a} $? 0 "VRF server, device client, local connection"
+
+	a=${NSA_IP6}
+	log_start
+	show_hint "Should fail since unbound client is out of VRF scope"
+	run_cmd nettest -6 -s -d ${VRF} &
+	sleep 1
+	run_cmd nettest -6 -r ${a}
+	log_test_addr ${a} $? 1 "VRF server, unbound client, local connection"
+
+	log_start
+	run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -r ${a} -d ${VRF} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, VRF client, local connection"
+
+	for a in ${NSA_IP6} ${NSA_LINKIP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd nettest -6 -r ${a} -d ${NSA_DEV} -0 ${a}
+		log_test_addr ${a} $? 0 "Device server, device client, local connection"
+	done
+}
+
+ipv6_tcp()
+{
+	log_section "IPv6/TCP"
+
+	which nettest >/dev/null
+	if [ $? -ne 0 ]; then
+		log_error "nettest not found; skipping tests"
+		return
+	fi
+
+	log_subsection "No VRF"
+	setup
+
+	# tcp_l3mdev_accept should have no affect without VRF;
+	# run tests with it enabled and disabled to verify
+	log_subsection "tcp_l3mdev_accept disabled"
+	set_sysctl net.ipv4.tcp_l3mdev_accept=0
+	ipv6_tcp_novrf
+	log_subsection "tcp_l3mdev_accept enabled"
+	set_sysctl net.ipv4.tcp_l3mdev_accept=1
+	ipv6_tcp_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv6_tcp_vrf
+}
+
+################################################################################
 # usage
 
 usage()
@@ -1324,7 +1691,7 @@ EOF
 # main
 
 TESTS_IPV4="ipv4_ping ipv4_tcp"
-TESTS_IPV6="ipv6_ping"
+TESTS_IPV6="ipv6_ping ipv6_tcp"
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -1366,6 +1733,7 @@ do
 	ipv4_tcp|tcp)    ipv4_tcp;;
 
 	ipv6_ping|ping6) ipv6_ping;;
+	ipv6_tcp|tcp6)   ipv6_tcp;;
 
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 08/15] selftests: Add ipv6 udp tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add IPv6 udp tests to fcnal-test.sh. Covers the permutations of directly
connected addresses, routed destinations, VRF and non-VRF, and expected
failures for both clients and servers. Includes permutations with
net.ipv4.udp_l3mdev_accept set to 0 and 1.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 492 +++++++++++++++++++++++++++++-
 1 file changed, 491 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index afe9eb55d04a..2a2e692bc242 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -2049,6 +2049,495 @@ ipv6_tcp()
 }
 
 ################################################################################
+# IPv6 UDP
+
+ipv6_udp_novrf()
+{
+	local a
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		run_cmd nettest -6 -D -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+
+		log_start
+		run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "Device server"
+	done
+
+	a=${NSA_LO_IP6}
+	log_start
+	run_cmd nettest -6 -D -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -6 -D -r ${a}
+	log_test_addr ${a} $? 0 "Global server"
+
+	# should fail since loopback address is out of scope for a device
+	# bound server, but it does not - hence this is more documenting
+	# behavior.
+	#log_start
+	#show_hint "Should fail since loopback address is out of scope"
+	#run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+	#sleep 1
+	#run_cmd_nsb nettest -6 -D -r ${a}
+	#log_test_addr ${a} $? 1 "Device server"
+
+	# negative test - should fail
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since there is no server"
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	#
+	# client
+	#
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV}
+	do
+		log_start
+		run_cmd_nsb nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -0 ${NSA_IP6}
+		log_test_addr ${a} $? 0 "Client"
+
+		log_start
+		run_cmd_nsb nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -0 ${NSA_IP6}
+		log_test_addr ${a} $? 0 "Client, device bind"
+
+		log_start
+		run_cmd_nsb nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -C -0 ${NSA_IP6}
+		log_test_addr ${a} $? 0 "Client, device send via cmsg"
+
+		log_start
+		run_cmd_nsb nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -S -0 ${NSA_IP6}
+		log_test_addr ${a} $? 0 "Client, device bind via IPV6_UNICAST_IF"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 1 "No server, unbound client"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "No server, device client"
+	done
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ::1
+	do
+		log_start
+		run_cmd nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -0 ${a} -1 ${a}
+		log_test_addr ${a} $? 0 "Global server, local connection"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s -D -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -r ${a}
+	log_test_addr ${a} $? 0 "Device server, unbound client, local connection"
+
+	for a in ${NSA_LO_IP6} ::1
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since address is out of device scope"
+		run_cmd nettest -6 -s -D -d ${NSA_DEV} &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 1 "Device server, local connection"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s -D &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device client, local connection"
+
+	log_start
+	run_cmd nettest -6 -s -D &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -C -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device send via cmsg, local connection"
+
+	log_start
+	run_cmd nettest -6 -s -D &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -S -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device client via IPV6_UNICAST_IF, local connection"
+
+	for a in ${NSA_LO_IP6} ::1
+	do
+		log_start
+		show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope"
+		run_cmd nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "Global server, device client, local connection"
+
+		log_start
+		show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope"
+		run_cmd nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -C
+		log_test_addr ${a} $? 1 "Global server, device send via cmsg, local connection"
+
+		log_start
+		show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope"
+		run_cmd nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -r ${a} -d ${NSA_DEV} -S
+		log_test_addr ${a} $? 1 "Global server, device client via IP_UNICAST_IF, local connection"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -D -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, device client, local conn"
+
+	log_start
+	show_hint "Should fail 'Connection refused'"
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 1 "No server, device client, local conn"
+
+	# LLA to GUA
+	run_cmd_nsb ip -6 addr del ${NSB_IP6}/64 dev ${NSB_DEV}
+	run_cmd_nsb ip -6 ro add ${NSA_IP6}/128 dev ${NSB_DEV}
+	log_start
+	run_cmd nettest -6 -s -D &
+	sleep 1
+	run_cmd_nsb nettest -6 -D -r ${NSA_IP6}
+	log_test $? 0 "UDP in - LLA to GUA"
+
+	run_cmd_nsb ip -6 ro del ${NSA_IP6}/128 dev ${NSB_DEV}
+	run_cmd_nsb ip -6 addr add ${NSB_IP6}/64 dev ${NSB_DEV} nodad
+}
+
+ipv6_udp_vrf()
+{
+	local a
+
+	# disable global server
+	log_subsection "Global server disabled"
+	set_sysctl net.ipv4.udp_l3mdev_accept=0
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since global server is disabled"
+		run_cmd nettest -6 -D -s &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 1 "Global server"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "Enslaved device server"
+	done
+
+	# negative test - should fail
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since there is no server"
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since global server is disabled"
+		run_cmd nettest -6 -D -s &
+		sleep 1
+		run_cmd nettest -6 -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 1 "Global server, VRF client, local conn"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -d ${VRF} -s &
+		sleep 1
+		run_cmd nettest -6 -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 0 "VRF server, VRF client, local conn"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	show_hint "Should fail 'Connection refused' since global server is disabled"
+	run_cmd nettest -6 -D -s &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 1 "Global server, device client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, device client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Enslaved device server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Enslaved device server, device client, local conn"
+
+	# disable global server
+	log_subsection "Global server enabled"
+	set_sysctl net.ipv4.udp_l3mdev_accept=1
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 0 "Enslaved device server"
+	done
+
+	# negative test - should fail
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd_nsb nettest -6 -D -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	#
+	# client tests
+	#
+	log_start
+	run_cmd_nsb nettest -6 -D -s &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${NSB_IP6}
+	log_test $? 0 "VRF client"
+
+	# negative test - should fail
+	log_start
+	run_cmd nettest -6 -D -d ${VRF} -r ${NSB_IP6}
+	log_test $? 1 "No server, VRF client"
+
+	log_start
+	run_cmd_nsb nettest -6 -D -s &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_IP6}
+	log_test $? 0 "Enslaved device client"
+
+	# negative test - should fail
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_IP6}
+	log_test $? 1 "No server, enslaved device client"
+
+	#
+	# local address tests
+	#
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -D -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Global server, VRF client, local conn"
+
+	#log_start
+	run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, VRF client, local conn"
+
+
+	a=${VRF_IP6}
+	log_start
+	run_cmd nettest -6 -D -s -2 ${VRF} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Global server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${VRF} -s -2 ${VRF} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, VRF client, local conn"
+
+	# negative test - should fail
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 1 "No server, VRF client, local conn"
+	done
+
+	# device to global IP
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -D -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${VRF} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, device client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Device server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Device server, device client, local conn"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 1 "No server, device client, local conn"
+
+
+	# link local addresses
+	log_start
+	run_cmd nettest -6 -D -s &
+	sleep 1
+	run_cmd_nsb nettest -6 -D -d ${NSB_DEV} -r ${NSA_LINKIP6}
+	log_test $? 0 "Global server, linklocal IP"
+
+	log_start
+	run_cmd_nsb nettest -6 -D -d ${NSB_DEV} -r ${NSA_LINKIP6}
+	log_test $? 1 "No server, linklocal IP"
+
+
+	log_start
+	run_cmd_nsb nettest -6 -D -s &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_LINKIP6}
+	log_test $? 0 "Enslaved device client, linklocal IP"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSB_LINKIP6}
+	log_test $? 1 "No server, device client, peer linklocal IP"
+
+
+	log_start
+	run_cmd nettest -6 -D -s &
+	sleep 1
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSA_LINKIP6}
+	log_test $? 0 "Enslaved device client, local conn - linklocal IP"
+
+	log_start
+	run_cmd nettest -6 -D -d ${NSA_DEV} -r ${NSA_LINKIP6}
+	log_test $? 1 "No server, device client, local conn  - linklocal IP"
+
+	# LLA to GUA
+	run_cmd_nsb ip -6 addr del ${NSB_IP6}/64 dev ${NSB_DEV}
+	run_cmd_nsb ip -6 ro add ${NSA_IP6}/128 dev ${NSB_DEV}
+	log_start
+	run_cmd nettest -6 -s -D &
+	sleep 1
+	run_cmd_nsb nettest -6 -D -r ${NSA_IP6}
+	log_test $? 0 "UDP in - LLA to GUA"
+
+	run_cmd_nsb ip -6 ro del ${NSA_IP6}/128 dev ${NSB_DEV}
+	run_cmd_nsb ip -6 addr add ${NSB_IP6}/64 dev ${NSB_DEV} nodad
+}
+
+ipv6_udp()
+{
+        # should not matter, but set to known state
+        set_sysctl net.ipv4.udp_early_demux=1
+
+        log_section "IPv6/UDP"
+        log_subsection "No VRF"
+        setup
+
+        # udp_l3mdev_accept should have no affect without VRF;
+        # run tests with it enabled and disabled to verify
+        log_subsection "udp_l3mdev_accept disabled"
+        set_sysctl net.ipv4.udp_l3mdev_accept=0
+        ipv6_udp_novrf
+        log_subsection "udp_l3mdev_accept enabled"
+        set_sysctl net.ipv4.udp_l3mdev_accept=1
+        ipv6_udp_novrf
+
+        log_subsection "With VRF"
+        setup "yes"
+        ipv6_udp_vrf
+}
+
+################################################################################
 # usage
 
 usage()
@@ -2069,7 +2558,7 @@ EOF
 # main
 
 TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp"
-TESTS_IPV6="ipv6_ping ipv6_tcp"
+TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp"
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -2113,6 +2602,7 @@ do
 
 	ipv6_ping|ping6) ipv6_ping;;
 	ipv6_tcp|tcp6)   ipv6_tcp;;
+	ipv6_udp|udp6)   ipv6_udp;;
 
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 09/15] selftests: Add ipv4 address bind tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add address bind tests to fcnal-test.sh. Verifies socket binding to
local addresses for raw, tcp and udp including device and VRF cases.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 111 +++++++++++++++++++++++++++++-
 1 file changed, 110 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 2a2e692bc242..6023ee1c6980 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -1401,6 +1401,114 @@ ipv4_udp()
 }
 
 ################################################################################
+# IPv4 address bind
+#
+# verifies ability or inability to bind to an address / device
+
+ipv4_addr_bind_novrf()
+{
+	#
+	# raw socket
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP}
+	do
+		log_start
+		run_cmd nettest -s -R -P icmp -l ${a} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address"
+
+		log_start
+		run_cmd nettest -s -R -P icmp -l ${a} -d ${NSA_DEV} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind"
+	done
+
+	#
+	# tcp sockets
+	#
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -l ${a} -r ${NSB_IP} -t1 -b
+	log_test_addr ${a} $? 0 "TCP socket bind to local address"
+
+	log_start
+	run_cmd nettest -l ${a} -r ${NSB_IP} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind"
+
+	# Sadly, the kernel allows binding a socket to a device and then
+	# binding to an address not on the device. The only restriction
+	# is that the address is valid in the L3 domain. So this test
+	# passes when it really should not
+	#a=${NSA_LO_IP}
+	#log_start
+	#show_hint "Should fail with 'Cannot assign requested address'"
+	#run_cmd nettest -s -l ${a} -d ${NSA_DEV} -t1 -b
+	#log_test_addr ${a} $? 1 "TCP socket bind to out of scope local address"
+}
+
+ipv4_addr_bind_vrf()
+{
+	#
+	# raw socket
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest -s -R -P icmp -l ${a} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address"
+
+		log_start
+		run_cmd nettest -s -R -P icmp -l ${a} -d ${NSA_DEV} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind"
+		log_start
+		run_cmd nettest -s -R -P icmp -l ${a} -d ${VRF} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address after VRF bind"
+	done
+
+	a=${NSA_LO_IP}
+	log_start
+	show_hint "Address on loopback is out of VRF scope"
+	run_cmd nettest -s -R -P icmp -l ${a} -d ${VRF} -b
+	log_test_addr ${a} $? 1 "Raw socket bind to out of scope address after VRF bind"
+
+	#
+	# tcp sockets
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest -s -l ${a} -d ${VRF} -t1 -b
+		log_test_addr ${a} $? 0 "TCP socket bind to local address"
+
+		log_start
+		run_cmd nettest -s -l ${a} -d ${NSA_DEV} -t1 -b
+		log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind"
+	done
+
+	a=${NSA_LO_IP}
+	log_start
+	show_hint "Address on loopback out of scope for VRF"
+	run_cmd nettest -s -l ${a} -d ${VRF} -t1 -b
+	log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for VRF"
+
+	log_start
+	show_hint "Address on loopback out of scope for device in VRF"
+	run_cmd nettest -s -l ${a} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for device bind"
+}
+
+ipv4_addr_bind()
+{
+	log_section "IPv4 address binds"
+
+	log_subsection "No VRF"
+	setup
+	ipv4_addr_bind_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv4_addr_bind_vrf
+}
+
+################################################################################
 # IPv6
 
 ipv6_ping_novrf()
@@ -2557,7 +2665,7 @@ EOF
 ################################################################################
 # main
 
-TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp"
+TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind"
 TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp"
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -2599,6 +2707,7 @@ do
 	ipv4_ping|ping)  ipv4_ping;;
 	ipv4_tcp|tcp)    ipv4_tcp;;
 	ipv4_udp|udp)    ipv4_udp;;
+	ipv4_bind|bind)  ipv4_addr_bind;;
 
 	ipv6_ping|ping6) ipv6_ping;;
 	ipv6_tcp|tcp6)   ipv6_tcp;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 02/15] selftests: Setup for functional tests for fib and socket lookups
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Initial commit for functional test suite for fib and socket lookups.
This commit contains the namespace setup, networking config, test options
and other basic infrastructure.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/Makefile      |   2 +-
 tools/testing/selftests/net/fcnal-test.sh | 520 ++++++++++++++++++++++++++++++
 2 files changed, 521 insertions(+), 1 deletion(-)
 create mode 100755 tools/testing/selftests/net/fcnal-test.sh

diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index ba9ee36c9e94..70f2d6656170 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -10,7 +10,7 @@ TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh ip_defrag.sh
 TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh
 TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_any.sh
 TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
-TEST_PROGS += tcp_fastopen_backup_key.sh
+TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh
 TEST_PROGS_EXTENDED := in_netns.sh
 TEST_GEN_FILES =  socket nettest
 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
new file mode 100755
index 000000000000..22cfbd2fd09c
--- /dev/null
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -0,0 +1,520 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved.
+#
+# IPv4 and IPv6 functional tests focusing on VRF and routing lookups
+# for various permutations:
+#   1. icmp, tcp, udp and netfilter
+#   2. client, server, no-server
+#   3. global address on interface
+#   4. global address on 'lo'
+#   5. remote and local traffic
+#   6. VRF and non-VRF permutations
+#
+# Setup:
+#                     ns-A     |     ns-B
+# No VRF case:
+#    [ lo ]         [ eth1 ]---|---[ eth1 ]      [ lo ]
+#                                                remote address
+# VRF case:
+#         [ red ]---[ eth1 ]---|---[ eth1 ]      [ lo ]
+#
+# ns-A:
+#     eth1: 172.16.1.1/24, 2001:db8:1::1/64
+#       lo: 127.0.0.1/8, ::1/128
+#           172.16.2.1/32, 2001:db8:2::1/128
+#      red: 127.0.0.1/8, ::1/128
+#           172.16.3.1/32, 2001:db8:3::1/128
+#
+# ns-B:
+#     eth1: 172.16.1.2/24, 2001:db8:1::2/64
+#      lo2: 127.0.0.1/8, ::1/128
+#           172.16.2.2/32, 2001:db8:2::2/128
+#
+# server / client nomenclature relative to ns-A
+
+VERBOSE=0
+
+NSA_DEV=eth1
+NSB_DEV=eth1
+VRF=red
+VRF_TABLE=1101
+
+# IPv4 config
+NSA_IP=172.16.1.1
+NSB_IP=172.16.1.2
+VRF_IP=172.16.3.1
+
+# IPv6 config
+NSA_IP6=2001:db8:1::1
+NSB_IP6=2001:db8:1::2
+VRF_IP6=2001:db8:3::1
+
+NSA_LO_IP=172.16.2.1
+NSB_LO_IP=172.16.2.2
+NSA_LO_IP6=2001:db8:2::1
+NSB_LO_IP6=2001:db8:2::2
+
+MCAST=ff02::1
+# set after namespace create
+NSA_LINKIP6=
+NSB_LINKIP6=
+
+NSA=ns-A
+NSB=ns-B
+
+NSA_CMD="ip netns exec ${NSA}"
+NSB_CMD="ip netns exec ${NSB}"
+
+which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
+
+################################################################################
+# utilities
+
+log_test()
+{
+	local rc=$1
+	local expected=$2
+	local msg="$3"
+
+	[ "${VERBOSE}" = "1" ] && echo
+
+	if [ ${rc} -eq ${expected} ]; then
+		nsuccess=$((nsuccess+1))
+		printf "TEST: %-70s  [ OK ]\n" "${msg}"
+	else
+		nfail=$((nfail+1))
+		printf "TEST: %-70s  [FAIL]\n" "${msg}"
+		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+			echo
+			echo "hit enter to continue, 'q' to quit"
+			read a
+			[ "$a" = "q" ] && exit 1
+		fi
+	fi
+
+	if [ "${PAUSE}" = "yes" ]; then
+		echo
+		echo "hit enter to continue, 'q' to quit"
+		read a
+		[ "$a" = "q" ] && exit 1
+	fi
+
+	kill_procs
+}
+
+log_test_addr()
+{
+	local addr=$1
+	local rc=$2
+	local expected=$3
+	local msg="$4"
+	local astr
+
+	astr=$(addr2str ${addr})
+	log_test $rc $expected "$msg - ${astr}"
+}
+
+log_section()
+{
+	echo
+	echo "###########################################################################"
+	echo "$*"
+	echo "###########################################################################"
+	echo
+}
+
+log_subsection()
+{
+	echo
+	echo "#################################################################"
+	echo "$*"
+	echo
+}
+
+log_start()
+{
+	# make sure we have no test instances running
+	kill_procs
+
+	if [ "${VERBOSE}" = "1" ]; then
+		echo
+		echo "#######################################################"
+	fi
+}
+
+log_debug()
+{
+	if [ "${VERBOSE}" = "1" ]; then
+		echo
+		echo "$*"
+		echo
+	fi
+}
+
+show_hint()
+{
+	if [ "${VERBOSE}" = "1" ]; then
+		echo "HINT: $*"
+		echo
+	fi
+}
+
+kill_procs()
+{
+	killall nettest ping ping6 >/dev/null 2>&1
+	sleep 1
+}
+
+do_run_cmd()
+{
+	local cmd="$*"
+	local out
+
+	if [ "$VERBOSE" = "1" ]; then
+		echo "COMMAND: ${cmd}"
+	fi
+
+	out=$($cmd 2>&1)
+	rc=$?
+	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
+		echo "$out"
+	fi
+
+	return $rc
+}
+
+run_cmd()
+{
+	do_run_cmd ${NSA_CMD} $*
+}
+
+run_cmd_nsb()
+{
+	do_run_cmd ${NSB_CMD} $*
+}
+
+setup_cmd()
+{
+	local cmd="$*"
+	local rc
+
+	run_cmd ${cmd}
+	rc=$?
+	if [ $rc -ne 0 ]; then
+		# show user the command if not done so already
+		if [ "$VERBOSE" = "0" ]; then
+			echo "setup command: $cmd"
+		fi
+		echo "failed. stopping tests"
+		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+			echo
+			echo "hit enter to continue"
+			read a
+		fi
+		exit $rc
+	fi
+}
+
+setup_cmd_nsb()
+{
+	local cmd="$*"
+	local rc
+
+	run_cmd_nsb ${cmd}
+	rc=$?
+	if [ $rc -ne 0 ]; then
+		# show user the command if not done so already
+		if [ "$VERBOSE" = "0" ]; then
+			echo "setup command: $cmd"
+		fi
+		echo "failed. stopping tests"
+		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+			echo
+			echo "hit enter to continue"
+			read a
+		fi
+		exit $rc
+	fi
+}
+
+# set sysctl values in NS-A
+set_sysctl()
+{
+	echo "SYSCTL: $*"
+	echo
+	run_cmd sysctl -q -w $*
+}
+
+################################################################################
+# Setup for tests
+
+addr2str()
+{
+	case "$1" in
+	127.0.0.1) echo "loopback";;
+	::1) echo "IPv6 loopback";;
+
+	${NSA_IP})	echo "ns-A IP";;
+	${NSA_IP6})	echo "ns-A IPv6";;
+	${NSA_LO_IP})	echo "ns-A loopback IP";;
+	${NSA_LO_IP6})	echo "ns-A loopback IPv6";;
+	${NSA_LINKIP6}|${NSA_LINKIP6}%*) echo "ns-A IPv6 LLA";;
+
+	${NSB_IP})	echo "ns-B IP";;
+	${NSB_IP6})	echo "ns-B IPv6";;
+	${NSB_LO_IP})	echo "ns-B loopback IP";;
+	${NSB_LO_IP6})	echo "ns-B loopback IPv6";;
+	${NSB_LINKIP6}|${NSB_LINKIP6}%*) echo "ns-B IPv6 LLA";;
+
+	${VRF_IP})	echo "VRF IP";;
+	${VRF_IP6})	echo "VRF IPv6";;
+
+	${MCAST}%*)	echo "multicast IP";;
+
+	*) echo "unknown";;
+	esac
+}
+
+get_linklocal()
+{
+	local ns=$1
+	local dev=$2
+	local addr
+
+	addr=$(ip -netns ${ns} -6 -br addr show dev ${dev} | \
+	awk '{
+		for (i = 3; i <= NF; ++i) {
+			if ($i ~ /^fe80/)
+				print $i
+		}
+	}'
+	)
+	addr=${addr/\/*}
+
+	[ -z "$addr" ] && return 1
+
+	echo $addr
+
+	return 0
+}
+
+################################################################################
+# create namespaces and vrf
+
+create_vrf()
+{
+	local ns=$1
+	local vrf=$2
+	local table=$3
+	local addr=$4
+	local addr6=$5
+
+	ip -netns ${ns} link add ${vrf} type vrf table ${table}
+	ip -netns ${ns} link set ${vrf} up
+	ip -netns ${ns} route add vrf ${vrf} unreachable default metric 8192
+	ip -netns ${ns} -6 route add vrf ${vrf} unreachable default metric 8192
+
+	ip -netns ${ns} addr add 127.0.0.1/8 dev ${vrf}
+	ip -netns ${ns} -6 addr add ::1 dev ${vrf} nodad
+	if [ "${addr}" != "-" ]; then
+		ip -netns ${ns} addr add dev ${vrf} ${addr}
+	fi
+	if [ "${addr6}" != "-" ]; then
+		ip -netns ${ns} -6 addr add dev ${vrf} ${addr6}
+	fi
+
+	ip -netns ${ns} ru del pref 0
+	ip -netns ${ns} ru add pref 32765 from all lookup local
+	ip -netns ${ns} -6 ru del pref 0
+	ip -netns ${ns} -6 ru add pref 32765 from all lookup local
+}
+
+create_ns()
+{
+	local ns=$1
+	local addr=$2
+	local addr6=$3
+
+	ip netns add ${ns}
+
+	ip -netns ${ns} link set lo up
+	if [ "${addr}" != "-" ]; then
+		ip -netns ${ns} addr add dev lo ${addr}
+	fi
+	if [ "${addr6}" != "-" ]; then
+		ip -netns ${ns} -6 addr add dev lo ${addr6}
+	fi
+
+	ip -netns ${ns} ro add unreachable default metric 8192
+	ip -netns ${ns} -6 ro add unreachable default metric 8192
+
+	ip netns exec ${ns} sysctl -qw net.ipv4.ip_forward=1
+	ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
+	ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.forwarding=1
+	ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.forwarding=1
+}
+
+# create veth pair to connect namespaces and apply addresses.
+connect_ns()
+{
+	local ns1=$1
+	local ns1_dev=$2
+	local ns1_addr=$3
+	local ns1_addr6=$4
+	local ns2=$5
+	local ns2_dev=$6
+	local ns2_addr=$7
+	local ns2_addr6=$8
+
+	ip -netns ${ns1} li add ${ns1_dev} type veth peer name tmp
+	ip -netns ${ns1} li set ${ns1_dev} up
+	ip -netns ${ns1} li set tmp netns ${ns2} name ${ns2_dev}
+	ip -netns ${ns2} li set ${ns2_dev} up
+
+	if [ "${ns1_addr}" != "-" ]; then
+		ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr}
+		ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr}
+	fi
+
+	if [ "${ns1_addr6}" != "-" ]; then
+		ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr6}
+		ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr6}
+	fi
+}
+
+cleanup()
+{
+	# explicit cleanups to check those code paths
+	ip netns | grep -q ${NSA}
+	if [ $? -eq 0 ]; then
+		ip -netns ${NSA} link delete ${VRF}
+		ip -netns ${NSA} ro flush table ${VRF_TABLE}
+
+		ip -netns ${NSA} addr flush dev ${NSA_DEV}
+		ip -netns ${NSA} -6 addr flush dev ${NSA_DEV}
+		ip -netns ${NSA} link set dev ${NSA_DEV} down
+		ip -netns ${NSA} link del dev ${NSA_DEV}
+
+		ip netns del ${NSA}
+	fi
+
+	ip netns del ${NSB}
+}
+
+setup()
+{
+	local with_vrf=${1}
+
+	# make sure we are starting with a clean slate
+	kill_procs
+	cleanup 2>/dev/null
+
+	log_debug "Configuring network namespaces"
+	set -e
+
+	create_ns ${NSA} ${NSA_LO_IP}/32 ${NSA_LO_IP6}/128
+	create_ns ${NSB} ${NSB_LO_IP}/32 ${NSB_LO_IP6}/128
+	connect_ns ${NSA} ${NSA_DEV} ${NSA_IP}/24 ${NSA_IP6}/64 \
+		   ${NSB} ${NSB_DEV} ${NSB_IP}/24 ${NSB_IP6}/64
+
+	NSA_LINKIP6=$(get_linklocal ${NSA} ${NSA_DEV})
+	NSB_LINKIP6=$(get_linklocal ${NSB} ${NSB_DEV})
+
+	# tell ns-A how to get to remote addresses of ns-B
+	if [ "${with_vrf}" = "yes" ]; then
+		create_vrf ${NSA} ${VRF} ${VRF_TABLE} ${VRF_IP} ${VRF_IP6}
+
+		ip -netns ${NSA} link set dev ${NSA_DEV} vrf ${VRF}
+		ip -netns ${NSA} ro add vrf ${VRF} ${NSB_LO_IP}/32 via ${NSB_IP} dev ${NSA_DEV}
+		ip -netns ${NSA} -6 ro add vrf ${VRF} ${NSB_LO_IP6}/128 via ${NSB_IP6} dev ${NSA_DEV}
+
+		ip -netns ${NSB} ro add ${VRF_IP}/32 via ${NSA_IP} dev ${NSB_DEV}
+		ip -netns ${NSB} -6 ro add ${VRF_IP6}/128 via ${NSA_IP6} dev ${NSB_DEV}
+	else
+		ip -netns ${NSA} ro add ${NSB_LO_IP}/32 via ${NSB_IP} dev ${NSA_DEV}
+		ip -netns ${NSA} ro add ${NSB_LO_IP6}/128 via ${NSB_IP6} dev ${NSA_DEV}
+	fi
+
+
+	# tell ns-B how to get to remote addresses of ns-A
+	ip -netns ${NSB} ro add ${NSA_LO_IP}/32 via ${NSA_IP} dev ${NSB_DEV}
+	ip -netns ${NSB} ro add ${NSA_LO_IP6}/128 via ${NSA_IP6} dev ${NSB_DEV}
+
+	set +e
+
+	sleep 1
+}
+
+################################################################################
+# usage
+
+usage()
+{
+	cat <<EOF
+usage: ${0##*/} OPTS
+
+	-4          IPv4 tests only
+	-6          IPv6 tests only
+	-t <test>   Test name/set to run
+	-p          Pause on fail
+	-P          Pause after each test
+	-v          Be verbose
+EOF
+}
+
+################################################################################
+# main
+
+TESTS_IPV4=""
+TESTS_IPV6=""
+PAUSE_ON_FAIL=no
+PAUSE=no
+
+while getopts :46t:pPvh o
+do
+	case $o in
+		4) TESTS=ipv4;;
+		6) TESTS=ipv6;;
+		t) TESTS=$OPTARG;;
+		p) PAUSE_ON_FAIL=yes;;
+		P) PAUSE=yes;;
+		v) VERBOSE=1;;
+		h) usage; exit 0;;
+		*) usage; exit 1;;
+	esac
+done
+
+# make sure we don't pause twice
+[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
+
+#
+# show user test config
+#
+if [ -z "$TESTS" ]; then
+	TESTS="$TESTS_IPV4 $TESTS_IPV6 $TESTS_OTHER"
+elif [ "$TESTS" = "ipv4" ]; then
+	TESTS="$TESTS_IPV4"
+elif [ "$TESTS" = "ipv6" ]; then
+	TESTS="$TESTS_IPV6"
+fi
+
+declare -i nfail=0
+declare -i nsuccess=0
+
+for t in $TESTS
+do
+	case $t in
+	# setup namespaces and config, but do not run any tests
+	setup)		 setup; exit 0;;
+	vrf_setup)	 setup "yes"; exit 0;;
+
+	help)            echo "Test names: $TESTS"; exit 0;;
+	esac
+done
+
+cleanup 2>/dev/null
+
+printf "\nTests passed: %3d\n" ${nsuccess}
+printf "Tests failed: %3d\n"   ${nfail}
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 05/15] selftests: Add ipv4 tcp tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add tcp tests to fcnal-test.sh. Covers the permutations of directly
connected addresses, routed destinations, VRF and non-VRF, and expected
failures for both clients and servers. Includes permutations with
net.ipv4.tcp_l3mdev_accept set to 0 and 1.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 315 +++++++++++++++++++++++++++++-
 1 file changed, 314 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 4da510f6d625..f9e2f1464dcd 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -712,6 +712,317 @@ ipv4_ping()
 }
 
 ################################################################################
+# IPv4 TCP
+
+ipv4_tcp_novrf()
+{
+	local a
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP}
+	do
+		log_start
+		run_cmd nettest -s &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -d ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -r ${a}
+	log_test_addr ${a} $? 0 "Device server"
+
+	# verify TCP reset sent and received
+	for a in ${NSA_IP} ${NSA_LO_IP}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since there is no server"
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	#
+	# client
+	#
+	for a in ${NSB_IP} ${NSB_LO_IP}
+	do
+		log_start
+		run_cmd_nsb nettest -s &
+		sleep 1
+		run_cmd nettest -r ${a} -0 ${NSA_IP}
+		log_test_addr ${a} $? 0 "Client"
+
+		log_start
+		run_cmd_nsb nettest -s &
+		sleep 1
+		run_cmd nettest -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 0 "Client, device bind"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -r ${a}
+		log_test_addr ${a} $? 1 "No server, unbound client"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "No server, device client"
+	done
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		run_cmd nettest -s &
+		sleep 1
+		run_cmd nettest -r ${a} -0 ${a} -1 ${a}
+		log_test_addr ${a} $? 0 "Global server, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -d ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -r ${a} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, unbound client, local connection"
+
+	for a in ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since addresses on loopback are out of device scope"
+		run_cmd nettest -s -d ${NSA_DEV} &
+		sleep 1
+		run_cmd nettest -r ${a}
+		log_test_addr ${a} $? 1 "Device server, unbound client, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s &
+	sleep 1
+	run_cmd nettest -r ${a} -0 ${a} -d ${NSA_DEV}
+	log_test_addr ${a} $? 0 "Global server, device client, local connection"
+
+	for a in ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Should fail 'No route to host' since addresses on loopback are out of device scope"
+		run_cmd nettest -s &
+		sleep 1
+		run_cmd nettest -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "Global server, device client, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest  -d ${NSA_DEV} -r ${a} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, device client, local connection"
+
+	log_start
+	show_hint "Should fail 'Connection refused'"
+	run_cmd nettest -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 1 "No server, device client, local conn"
+}
+
+ipv4_tcp_vrf()
+{
+	local a
+
+	# disable global server
+	log_subsection "Global server disabled"
+
+	set_sysctl net.ipv4.tcp_l3mdev_accept=0
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since global server with VRF is disabled"
+		run_cmd nettest -s &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 1 "Global server"
+
+		log_start
+		run_cmd nettest -s -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+
+		log_start
+		run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 0 "Device server"
+
+		# verify TCP reset received
+		log_start
+		show_hint "Should fail 'Connection refused' since there is no server"
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	# local address tests
+	# (${VRF_IP} and 127.0.0.1 both timeout)
+	a=${NSA_IP}
+	log_start
+	show_hint "Should fail 'Connection refused' since global server with VRF is disabled"
+	run_cmd nettest -s &
+	sleep 1
+	run_cmd nettest -r ${a} -d ${NSA_DEV}
+	log_test_addr ${a} $? 1 "Global server, local connection"
+
+	#
+	# enable VRF global server
+	#
+	log_subsection "VRF Global server enabled"
+	set_sysctl net.ipv4.tcp_l3mdev_accept=1
+
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		show_hint "client socket should be bound to VRF"
+		run_cmd nettest -s -2 ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+
+		log_start
+		show_hint "client socket should be bound to VRF"
+		run_cmd nettest -s -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+
+		# verify TCP reset received
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	a=${NSA_IP}
+	log_start
+	show_hint "client socket should be bound to device"
+	run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -r ${a}
+	log_test_addr ${a} $? 0 "Device server"
+
+	# local address tests
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		show_hint "Should fail 'No route to host' since client is not bound to VRF"
+		run_cmd nettest -s -2 ${VRF} &
+		sleep 1
+		run_cmd nettest -r ${a}
+		log_test_addr ${a} $? 1 "Global server, local connection"
+	done
+
+	#
+	# client
+	#
+	for a in ${NSB_IP} ${NSB_LO_IP}
+	do
+		log_start
+		run_cmd_nsb nettest -s &
+		sleep 1
+		run_cmd nettest -r ${a} -d ${VRF}
+		log_test_addr ${a} $? 0 "Client, VRF bind"
+
+		log_start
+		run_cmd_nsb nettest -s &
+		sleep 1
+		run_cmd nettest -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 0 "Client, device bind"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -r ${a} -d ${VRF}
+		log_test_addr ${a} $? 1 "No server, VRF client"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "No server, device client"
+	done
+
+	for a in ${NSA_IP} ${VRF_IP} 127.0.0.1
+	do
+		log_start
+		run_cmd nettest -s -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd nettest -r ${a} -d ${VRF} -0 ${a}
+		log_test_addr ${a} $? 0 "VRF server, VRF client, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -d ${VRF} -2 ${VRF} &
+	sleep 1
+	run_cmd nettest -r ${a} -d ${NSA_DEV} -0 ${a}
+	log_test_addr ${a} $? 0 "VRF server, device client, local connection"
+
+	log_start
+	show_hint "Should fail 'No route to host' since client is out of VRF scope"
+	run_cmd nettest -s -d ${VRF} &
+	sleep 1
+	run_cmd nettest -r ${a}
+	log_test_addr ${a} $? 1 "VRF server, unbound client, local connection"
+
+	log_start
+	run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -r ${a} -d ${VRF} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, VRF client, local connection"
+
+	log_start
+	run_cmd nettest -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -r ${a} -d ${NSA_DEV} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, device client, local connection"
+}
+
+ipv4_tcp()
+{
+	log_section "IPv4/TCP"
+
+	which nettest >/dev/null
+	if [ $? -ne 0 ]; then
+		log_error "nettest not found; skipping tests"
+		return
+	fi
+
+	log_subsection "No VRF"
+	setup
+
+	# tcp_l3mdev_accept should have no affect without VRF;
+	# run tests with it enabled and disabled to verify
+	log_subsection "tcp_l3mdev_accept disabled"
+	set_sysctl net.ipv4.tcp_l3mdev_accept=0
+	ipv4_tcp_novrf
+	log_subsection "tcp_l3mdev_accept enabled"
+	set_sysctl net.ipv4.tcp_l3mdev_accept=1
+	ipv4_tcp_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv4_tcp_vrf
+}
+
+################################################################################
 # IPv6
 
 ipv6_ping_novrf()
@@ -1012,7 +1323,7 @@ EOF
 ################################################################################
 # main
 
-TESTS_IPV4="ipv4_ping"
+TESTS_IPV4="ipv4_ping ipv4_tcp"
 TESTS_IPV6="ipv6_ping"
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -1052,6 +1363,8 @@ for t in $TESTS
 do
 	case $t in
 	ipv4_ping|ping)  ipv4_ping;;
+	ipv4_tcp|tcp)    ipv4_tcp;;
+
 	ipv6_ping|ping6) ipv6_ping;;
 
 	# setup namespaces and config, but do not run any tests
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 07/15] selftests: Add ipv4 udp tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add udp tests to fcnal-test.sh. Covers the permutations of directly
connected addresses, routed destinations, VRF and non-VRF, and expected
failures for both clients and servers. Includes permutations with
net.ipv4.udp_l3mdev_accept set to 0 and 1.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 381 +++++++++++++++++++++++++++++-
 1 file changed, 380 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 97291c6d17c5..afe9eb55d04a 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -1023,6 +1023,384 @@ ipv4_tcp()
 }
 
 ################################################################################
+# IPv4 UDP
+
+ipv4_udp_novrf()
+{
+	local a
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP}
+	do
+		log_start
+		run_cmd nettest -D -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+
+		log_start
+		show_hint "Should fail 'Connection refused' since there is no server"
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest -D -r ${a}
+	log_test_addr ${a} $? 0 "Device server"
+
+	#
+	# client
+	#
+	for a in ${NSB_IP} ${NSB_LO_IP}
+	do
+		log_start
+		run_cmd_nsb nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -0 ${NSA_IP}
+		log_test_addr ${a} $? 0 "Client"
+
+		log_start
+		run_cmd_nsb nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV} -0 ${NSA_IP}
+		log_test_addr ${a} $? 0 "Client, device bind"
+
+		log_start
+		run_cmd_nsb nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV} -C -0 ${NSA_IP}
+		log_test_addr ${a} $? 0 "Client, device send via cmsg"
+
+		log_start
+		run_cmd_nsb nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV} -S -0 ${NSA_IP}
+		log_test_addr ${a} $? 0 "Client, device bind via IP_UNICAST_IF"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -D -r ${a}
+		log_test_addr ${a} $? 1 "No server, unbound client"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 1 "No server, device client"
+	done
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		run_cmd nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -0 ${a} -1 ${a}
+		log_test_addr ${a} $? 0 "Global server, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -r ${a}
+	log_test_addr ${a} $? 0 "Device server, unbound client, local connection"
+
+	for a in ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Should fail 'Connection refused' since address is out of device scope"
+		run_cmd nettest -s -D -d ${NSA_DEV} &
+		sleep 1
+		run_cmd nettest -D -r ${a}
+		log_test_addr ${a} $? 1 "Device server, unbound client, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -D &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device client, local connection"
+
+	log_start
+	run_cmd nettest -s -D &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -C -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device send via cmsg, local connection"
+
+	log_start
+	run_cmd nettest -s -D &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -S -r ${a}
+	log_test_addr ${a} $? 0 "Global server, device client via IP_UNICAST_IF, local connection"
+
+	# IPv4 with device bind has really weird behavior - it overrides the
+	# fib lookup, generates an rtable and tries to send the packet. This
+	# causes failures for local traffic at different places
+	for a in ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Should fail since addresses on loopback are out of device scope"
+		run_cmd nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV}
+		log_test_addr ${a} $? 2 "Global server, device client, local connection"
+
+		log_start
+		show_hint "Should fail since addresses on loopback are out of device scope"
+		run_cmd nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV} -C
+		log_test_addr ${a} $? 1 "Global server, device send via cmsg, local connection"
+
+		log_start
+		show_hint "Should fail since addresses on loopback are out of device scope"
+		run_cmd nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -r ${a} -d ${NSA_DEV} -S
+		log_test_addr ${a} $? 1 "Global server, device client via IP_UNICAST_IF, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -D -s -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a} -0 ${a}
+	log_test_addr ${a} $? 0 "Device server, device client, local conn"
+
+	log_start
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 2 "No server, device client, local conn"
+}
+
+ipv4_udp_vrf()
+{
+	local a
+
+	# disable global server
+	log_subsection "Global server disabled"
+	set_sysctl net.ipv4.udp_l3mdev_accept=0
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		show_hint "Fails because ingress is in a VRF and global server is disabled"
+		run_cmd nettest -D -s &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 1 "Global server"
+
+		log_start
+		run_cmd nettest -D -d ${VRF} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+
+		log_start
+		run_cmd nettest -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 0 "Enslaved device server"
+
+		log_start
+		show_hint "Should fail 'Connection refused' since there is no server"
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+
+		log_start
+		show_hint "Should fail 'Connection refused' since global server is out of scope"
+		run_cmd nettest -D -s &
+		sleep 1
+		run_cmd nettest -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 1 "Global server, VRF client, local connection"
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, enslaved device client, local connection"
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Enslaved device server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Enslaved device server, device client, local conn"
+
+	# enable global server
+	log_subsection "Global server enabled"
+	set_sysctl net.ipv4.udp_l3mdev_accept=1
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest -D -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 0 "Global server"
+
+		log_start
+		run_cmd nettest -D -d ${VRF} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 0 "VRF server"
+
+		log_start
+		run_cmd nettest -D -d ${NSA_DEV} -s -2 ${NSA_DEV} &
+		sleep 1
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 0 "Enslaved device server"
+
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd_nsb nettest -D -r ${a}
+		log_test_addr ${a} $? 1 "No server"
+	done
+
+	#
+	# client tests
+	#
+	log_start
+	run_cmd_nsb nettest -D -s &
+	sleep 1
+	run_cmd nettest -d ${VRF} -D -r ${NSB_IP} -1 ${NSA_IP}
+	log_test $? 0 "VRF client"
+
+	log_start
+	run_cmd_nsb nettest -D -s &
+	sleep 1
+	run_cmd nettest -d ${NSA_DEV} -D -r ${NSB_IP} -1 ${NSA_IP}
+	log_test $? 0 "Enslaved device client"
+
+	# negative test - should fail
+	log_start
+	show_hint "Should fail 'Connection refused'"
+	run_cmd nettest -D -d ${VRF} -r ${NSB_IP}
+	log_test $? 1 "No server, VRF client"
+
+	log_start
+	show_hint "Should fail 'Connection refused'"
+	run_cmd nettest -D -d ${NSA_DEV} -r ${NSB_IP}
+	log_test $? 1 "No server, enslaved device client"
+
+	#
+	# local address tests
+	#
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest -D -s -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Global server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -s -D -d ${VRF} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "VRF server, device client, local conn"
+
+	log_start
+	run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${VRF} -r ${a}
+	log_test_addr ${a} $? 0 "Enslaved device server, VRF client, local conn"
+
+	log_start
+	run_cmd nettest -s -D -d ${NSA_DEV} -2 ${NSA_DEV} &
+	sleep 1
+	run_cmd nettest -D -d ${NSA_DEV} -r ${a}
+	log_test_addr ${a} $? 0 "Enslaved device server, device client, local conn"
+
+	for a in ${VRF_IP} 127.0.0.1
+	do
+		log_start
+		run_cmd nettest -D -s -2 ${VRF} &
+		sleep 1
+		run_cmd nettest -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 0 "Global server, VRF client, local conn"
+	done
+
+	for a in ${VRF_IP} 127.0.0.1
+	do
+		log_start
+		run_cmd nettest -s -D -d ${VRF} -2 ${VRF} &
+		sleep 1
+		run_cmd nettest -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 0 "VRF server, VRF client, local conn"
+	done
+
+	# negative test - should fail
+	# verifies ECONNREFUSED
+	for a in ${NSA_IP} ${VRF_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Should fail 'Connection refused'"
+		run_cmd nettest -D -d ${VRF} -r ${a}
+		log_test_addr ${a} $? 1 "No server, VRF client, local conn"
+	done
+}
+
+ipv4_udp()
+{
+	which nettest >/dev/null
+	if [ $? -ne 0 ]; then
+		log_error "nettest not found; skipping tests"
+		return
+	fi
+
+	log_section "IPv4/UDP"
+	log_subsection "No VRF"
+
+	setup
+
+	# udp_l3mdev_accept should have no affect without VRF;
+	# run tests with it enabled and disabled to verify
+	log_subsection "udp_l3mdev_accept disabled"
+	set_sysctl net.ipv4.udp_l3mdev_accept=0
+	ipv4_udp_novrf
+	log_subsection "udp_l3mdev_accept enabled"
+	set_sysctl net.ipv4.udp_l3mdev_accept=1
+	ipv4_udp_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv4_udp_vrf
+}
+
+################################################################################
 # IPv6
 
 ipv6_ping_novrf()
@@ -1690,7 +2068,7 @@ EOF
 ################################################################################
 # main
 
-TESTS_IPV4="ipv4_ping ipv4_tcp"
+TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp"
 TESTS_IPV6="ipv6_ping ipv6_tcp"
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -1731,6 +2109,7 @@ do
 	case $t in
 	ipv4_ping|ping)  ipv4_ping;;
 	ipv4_tcp|tcp)    ipv4_tcp;;
+	ipv4_udp|udp)    ipv4_udp;;
 
 	ipv6_ping|ping6) ipv6_ping;;
 	ipv6_tcp|tcp6)   ipv6_tcp;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 11/15] selftests: Add ipv4 runtime tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add runtime tests where passive (no traffic flowing) and active (with
traffic) sockets are expected to be reset on device deletes.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 185 +++++++++++++++++++++++++++++-
 1 file changed, 184 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 48e74d62e009..b8bdab733ecd 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -1509,6 +1509,188 @@ ipv4_addr_bind()
 }
 
 ################################################################################
+# IPv4 runtime tests
+
+ipv4_rt()
+{
+	local desc="$1"
+	local varg="$2"
+	local with_vrf="yes"
+	local a
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest ${varg} -s &
+		sleep 1
+		run_cmd_nsb nettest ${varg} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, global server"
+
+		setup ${with_vrf}
+	done
+
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest ${varg} -s -d ${VRF} &
+		sleep 1
+		run_cmd_nsb nettest ${varg} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, VRF server"
+
+		setup ${with_vrf}
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest ${varg} -s -d ${NSA_DEV} &
+	sleep 1
+	run_cmd_nsb nettest ${varg} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, enslaved device server"
+
+	setup ${with_vrf}
+
+	#
+	# client test
+	#
+	log_start
+	run_cmd_nsb nettest ${varg} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${VRF} -r ${NSB_IP} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, VRF client"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd_nsb nettest ${varg} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${NSB_IP} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, enslaved device client"
+
+	setup ${with_vrf}
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest ${varg} -s &
+		sleep 1
+		run_cmd nettest ${varg} -d ${VRF} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, global server, VRF client, local"
+
+		setup ${with_vrf}
+	done
+
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest ${varg} -d ${VRF} -s &
+		sleep 1
+		run_cmd nettest ${varg} -d ${VRF} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, VRF server and client, local"
+
+		setup ${with_vrf}
+	done
+
+	a=${NSA_IP}
+	log_start
+	run_cmd nettest ${varg} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, global server, enslaved device client, local"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd nettest ${varg} -d ${VRF} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, VRF server, enslaved device client, local"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd nettest ${varg} -d ${NSA_DEV} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, enslaved device server and client, local"
+}
+
+ipv4_ping_rt()
+{
+	local with_vrf="yes"
+	local a
+
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd_nsb ping -f ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "Device delete with active traffic - ping in"
+
+		setup ${with_vrf}
+	done
+
+	a=${NSB_IP}
+	log_start
+	run_cmd ping -f -I ${VRF} ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "Device delete with active traffic - ping out"
+}
+
+ipv4_runtime()
+{
+	log_section "Run time tests - ipv4"
+
+	setup "yes"
+	ipv4_ping_rt
+
+	setup "yes"
+	ipv4_rt "TCP active socket"  "-n -1"
+
+	setup "yes"
+	ipv4_rt "TCP passive socket" "-i"
+}
+
+################################################################################
 # IPv6
 
 ipv6_ping_novrf()
@@ -2772,7 +2954,7 @@ EOF
 ################################################################################
 # main
 
-TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind"
+TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime"
 TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind"
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -2815,6 +2997,7 @@ do
 	ipv4_tcp|tcp)    ipv4_tcp;;
 	ipv4_udp|udp)    ipv4_udp;;
 	ipv4_bind|bind)  ipv4_addr_bind;;
+	ipv4_runtime)    ipv4_runtime;;
 
 	ipv6_ping|ping6) ipv6_ping;;
 	ipv6_tcp|tcp6)   ipv6_tcp;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 13/15] selftests: Add ipv4 netfilter tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add netfilter tests to send tcp reset or icmp unreachable for a port.
Initial tests are VRF only.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 69 ++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index dcfe0b13dfe9..6f56c91e2d66 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -3120,6 +3120,72 @@ ipv6_runtime()
 }
 
 ################################################################################
+# netfilter blocking connections
+
+netfilter_tcp_reset()
+{
+	local a
+
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest -s &
+		sleep 1
+		run_cmd_nsb nettest -r ${a}
+		log_test_addr ${a} $? 1 "Global server, reject with TCP-reset on Rx"
+	done
+}
+
+netfilter_icmp()
+{
+	local stype="$1"
+	local arg
+	local a
+
+	[ "${stype}" = "UDP" ] && arg="-D"
+
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd nettest ${arg} -s &
+		sleep 1
+		run_cmd_nsb nettest ${arg} -r ${a}
+		log_test_addr ${a} $? 1 "Global ${stype} server, Rx reject icmp-port-unreach"
+	done
+}
+
+ipv4_netfilter()
+{
+	which nettest >/dev/null
+	if [ $? -ne 0 ]; then
+		log_error "nettest not found; skipping tests"
+		return
+	fi
+
+	log_section "IPv4 Netfilter"
+	log_subsection "TCP reset"
+
+	setup "yes"
+	run_cmd iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset
+
+	netfilter_tcp_reset
+
+	log_start
+	log_subsection "ICMP unreachable"
+
+	log_start
+	run_cmd iptables -F
+	run_cmd iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-port-unreachable
+	run_cmd iptables -A INPUT -p udp --dport 12345 -j REJECT --reject-with icmp-port-unreachable
+
+	netfilter_icmp "TCP"
+	netfilter_icmp "UDP"
+
+	log_start
+	iptables -F
+}
+
+################################################################################
 # usage
 
 usage()
@@ -3139,7 +3205,7 @@ EOF
 ################################################################################
 # main
 
-TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime"
+TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime ipv4_netfilter"
 TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime"
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -3183,6 +3249,7 @@ do
 	ipv4_udp|udp)    ipv4_udp;;
 	ipv4_bind|bind)  ipv4_addr_bind;;
 	ipv4_runtime)    ipv4_runtime;;
+	ipv4_netfilter)  ipv4_netfilter;;
 
 	ipv6_ping|ping6) ipv6_ping;;
 	ipv6_tcp|tcp6)   ipv6_tcp;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 12/15] selftests: Add ipv6 runtime tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add IPv6 runtime tests where passive (no traffic flowing) and active
(with traffic) sockets are expected to be reset on device deletes.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 188 +++++++++++++++++++++++++++++-
 1 file changed, 187 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index b8bdab733ecd..dcfe0b13dfe9 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -2935,6 +2935,191 @@ ipv6_addr_bind()
 }
 
 ################################################################################
+# IPv6 runtime tests
+
+ipv6_rt()
+{
+	local desc="$1"
+	local varg="-6 $2"
+	local with_vrf="yes"
+	local a
+
+	#
+	# server tests
+	#
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest ${varg} -s &
+		sleep 1
+		run_cmd_nsb nettest ${varg} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, global server"
+
+		setup ${with_vrf}
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest ${varg} -d ${VRF} -s &
+		sleep 1
+		run_cmd_nsb nettest ${varg} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, VRF server"
+
+		setup ${with_vrf}
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest ${varg} -d ${NSA_DEV} -s &
+		sleep 1
+		run_cmd_nsb nettest ${varg} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, enslaved device server"
+
+		setup ${with_vrf}
+	done
+
+	#
+	# client test
+	#
+	log_start
+	run_cmd_nsb nettest ${varg} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${VRF} -r ${NSB_IP6} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test  0 0 "${desc}, VRF client"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd_nsb nettest ${varg} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${NSB_IP6} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test  0 0 "${desc}, enslaved device client"
+
+	setup ${with_vrf}
+
+
+	#
+	# local address tests
+	#
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest ${varg} -s &
+		sleep 1
+		run_cmd nettest ${varg} -d ${VRF} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, global server, VRF client"
+
+		setup ${with_vrf}
+	done
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest ${varg} -d ${VRF} -s &
+		sleep 1
+		run_cmd nettest ${varg} -d ${VRF} -r ${a} &
+		sleep 3
+		run_cmd ip link del ${VRF}
+		sleep 1
+		log_test_addr ${a} 0 0 "${desc}, VRF server and client"
+
+		setup ${with_vrf}
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest ${varg} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, global server, device client"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd nettest ${varg} -d ${VRF} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, VRF server, device client"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd nettest ${varg} -d ${NSA_DEV} -s &
+	sleep 1
+	run_cmd nettest ${varg} -d ${NSA_DEV} -r ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "${desc}, device server, device client"
+}
+
+ipv6_ping_rt()
+{
+	local with_vrf="yes"
+	local a
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd_nsb ${ping6} -f ${a} &
+	sleep 3
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "Device delete with active traffic - ping in"
+
+	setup ${with_vrf}
+
+	log_start
+	run_cmd ${ping6} -f ${NSB_IP6} -I ${VRF} &
+	sleep 1
+	run_cmd ip link del ${VRF}
+	sleep 1
+	log_test_addr ${a} 0 0 "Device delete with active traffic - ping out"
+}
+
+ipv6_runtime()
+{
+	log_section "Run time tests - ipv6"
+
+	setup "yes"
+	ipv6_ping_rt
+
+	setup "yes"
+	ipv6_rt "TCP active socket"  "-n -1"
+
+	setup "yes"
+	ipv6_rt "TCP passive socket" "-i"
+
+	setup "yes"
+	ipv6_rt "UDP active socket"  "-D -n -1"
+}
+
+################################################################################
 # usage
 
 usage()
@@ -2955,7 +3140,7 @@ EOF
 # main
 
 TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime"
-TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind"
+TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime"
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -3003,6 +3188,7 @@ do
 	ipv6_tcp|tcp6)   ipv6_tcp;;
 	ipv6_udp|udp6)   ipv6_udp;;
 	ipv6_bind|bind6) ipv6_addr_bind;;
+	ipv6_runtime)    ipv6_runtime;;
 
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 10/15] selftests: Add ipv6 address bind tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add IPv6 address bind tests to fcnal-test.sh. Verifies socket binding to
local addresses for raw, tcp and udp including device and VRF cases.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 110 +++++++++++++++++++++++++++++-
 1 file changed, 109 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 6023ee1c6980..48e74d62e009 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -2646,6 +2646,113 @@ ipv6_udp()
 }
 
 ################################################################################
+# IPv6 address bind
+
+ipv6_addr_bind_novrf()
+{
+	#
+	# raw socket
+	#
+	for a in ${NSA_IP6} ${NSA_LO_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address"
+
+		log_start
+		run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${NSA_DEV} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind"
+	done
+
+	#
+	# tcp sockets
+	#
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s -l ${a} -t1 -b
+	log_test_addr ${a} $? 0 "TCP socket bind to local address"
+
+	log_start
+	run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind"
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Should fail with 'Cannot assign requested address'"
+	run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 1 "TCP socket bind to out of scope local address"
+}
+
+ipv6_addr_bind_vrf()
+{
+	#
+	# raw socket
+	#
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${VRF} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address after vrf bind"
+
+		log_start
+		run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${NSA_DEV} -b
+		log_test_addr ${a} $? 0 "Raw socket bind to local address after device bind"
+	done
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Address on loopback is out of VRF scope"
+	run_cmd nettest -6 -s -R -P ipv6-icmp -l ${a} -d ${VRF} -b
+	log_test_addr ${a} $? 1 "Raw socket bind to invalid local address after vrf bind"
+
+	#
+	# tcp sockets
+	#
+	# address on enslaved device is valid for the VRF or device in a VRF
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s -l ${a} -d ${VRF} -t1 -b
+		log_test_addr ${a} $? 0 "TCP socket bind to local address with VRF bind"
+	done
+
+	a=${NSA_IP6}
+	log_start
+	run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 0 "TCP socket bind to local address with device bind"
+
+	a=${VRF_IP6}
+	log_start
+	run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 1 "TCP socket bind to VRF address with device bind"
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Address on loopback out of scope for VRF"
+	run_cmd nettest -6 -s -l ${a} -d ${VRF} -t1 -b
+	log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for VRF"
+
+	log_start
+	show_hint "Address on loopback out of scope for device in VRF"
+	run_cmd nettest -6 -s -l ${a} -d ${NSA_DEV} -t1 -b
+	log_test_addr ${a} $? 1 "TCP socket bind to invalid local address for device bind"
+
+}
+
+ipv6_addr_bind()
+{
+	log_section "IPv6 address binds"
+
+	log_subsection "No VRF"
+	setup
+	ipv6_addr_bind_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv6_addr_bind_vrf
+}
+
+################################################################################
 # usage
 
 usage()
@@ -2666,7 +2773,7 @@ EOF
 # main
 
 TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind"
-TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp"
+TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind"
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -2712,6 +2819,7 @@ do
 	ipv6_ping|ping6) ipv6_ping;;
 	ipv6_tcp|tcp6)   ipv6_tcp;;
 	ipv6_udp|udp6)   ipv6_udp;;
+	ipv6_bind|bind6) ipv6_addr_bind;;
 
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 14/15] selftests: Add ipv6 netfilter tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add IPv6 netfilter tests to send tcp reset or icmp unreachable for a
port. Initial tests are VRF only.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 65 ++++++++++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 6f56c91e2d66..17eec10e06bf 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -3185,6 +3185,68 @@ ipv4_netfilter()
 	iptables -F
 }
 
+netfilter_tcp6_reset()
+{
+	local a
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s &
+		sleep 1
+		run_cmd_nsb nettest -6 -r ${a}
+		log_test_addr ${a} $? 1 "Global server, reject with TCP-reset on Rx"
+	done
+}
+
+netfilter_icmp6()
+{
+	local stype="$1"
+	local arg
+	local a
+
+	[ "${stype}" = "UDP" ] && arg="$arg -D"
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd nettest -6 -s ${arg} &
+		sleep 1
+		run_cmd_nsb nettest -6 ${arg} -r ${a}
+		log_test_addr ${a} $? 1 "Global ${stype} server, Rx reject icmp-port-unreach"
+	done
+}
+
+ipv6_netfilter()
+{
+	which nettest >/dev/null
+	if [ $? -ne 0 ]; then
+		log_error "nettest not found; skipping tests"
+		return
+	fi
+
+	log_section "IPv6 Netfilter"
+	log_subsection "TCP reset"
+
+	setup "yes"
+	run_cmd ip6tables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset
+
+	netfilter_tcp6_reset
+
+	log_subsection "ICMP unreachable"
+
+	log_start
+	run_cmd ip6tables -F
+	run_cmd ip6tables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp6-port-unreachable
+	run_cmd ip6tables -A INPUT -p udp --dport 12345 -j REJECT --reject-with icmp6-port-unreachable
+
+	netfilter_icmp6 "TCP"
+	netfilter_icmp6 "UDP"
+
+	log_start
+	ip6tables -F
+}
+
 ################################################################################
 # usage
 
@@ -3206,7 +3268,7 @@ EOF
 # main
 
 TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime ipv4_netfilter"
-TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime"
+TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime ipv6_netfilter"
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -3256,6 +3318,7 @@ do
 	ipv6_udp|udp6)   ipv6_udp;;
 	ipv6_bind|bind6) ipv6_addr_bind;;
 	ipv6_runtime)    ipv6_runtime;;
+	ipv6_netfilter)  ipv6_netfilter;;
 
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 15/15] selftests: Add use case section to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add use case section to fcnal-test.

Initial test is VRF based with a bridge and vlans. The commands
stem from bug reports fixed by:

a173f066c7cf ("netfilter: bridge: Don't sabotage nf_hook calls from an l3mdev")
cd6428988bf4 ("netfilter: bridge: Don't sabotage nf_hook calls for an l3mdev slave")

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 124 ++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 17eec10e06bf..bd6b564382ec 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -3248,6 +3248,126 @@ ipv6_netfilter()
 }
 
 ################################################################################
+# specific use cases
+
+# VRF only.
+# ns-A device enslaved to bridge. Verify traffic with and without
+# br_netfilter module loaded. Repeat with SVI on bridge.
+use_case_br()
+{
+	setup "yes"
+
+	setup_cmd ip link set ${NSA_DEV} down
+	setup_cmd ip addr del dev ${NSA_DEV} ${NSA_IP}/24
+	setup_cmd ip -6 addr del dev ${NSA_DEV} ${NSA_IP6}/64
+
+	setup_cmd ip link add br0 type bridge
+	setup_cmd ip addr add dev br0 ${NSA_IP}/24
+	setup_cmd ip -6 addr add dev br0 ${NSA_IP6}/64 nodad
+
+	setup_cmd ip li set ${NSA_DEV} master br0
+	setup_cmd ip li set ${NSA_DEV} up
+	setup_cmd ip li set br0 up
+	setup_cmd ip li set br0 vrf ${VRF}
+
+	rmmod br_netfilter 2>/dev/null
+	sleep 5 # DAD
+
+	run_cmd ip neigh flush all
+	run_cmd ping -c1 -w1 -I br0 ${NSB_IP}
+	log_test $? 0 "Bridge into VRF - IPv4 ping out"
+
+	run_cmd ip neigh flush all
+	run_cmd ${ping6} -c1 -w1 -I br0 ${NSB_IP6}
+	log_test $? 0 "Bridge into VRF - IPv6 ping out"
+
+	run_cmd ip neigh flush all
+	run_cmd_nsb ping -c1 -w1 ${NSA_IP}
+	log_test $? 0 "Bridge into VRF - IPv4 ping in"
+
+	run_cmd ip neigh flush all
+	run_cmd_nsb ${ping6} -c1 -w1 ${NSA_IP6}
+	log_test $? 0 "Bridge into VRF - IPv6 ping in"
+
+	modprobe br_netfilter
+	if [ $? -eq 0 ]; then
+		run_cmd ip neigh flush all
+		run_cmd ping -c1 -w1 -I br0 ${NSB_IP}
+		log_test $? 0 "Bridge into VRF with br_netfilter - IPv4 ping out"
+
+		run_cmd ip neigh flush all
+		run_cmd ${ping6} -c1 -w1 -I br0 ${NSB_IP6}
+		log_test $? 0 "Bridge into VRF with br_netfilter - IPv6 ping out"
+
+		run_cmd ip neigh flush all
+		run_cmd_nsb ping -c1 -w1 ${NSA_IP}
+		log_test $? 0 "Bridge into VRF with br_netfilter - IPv4 ping in"
+
+		run_cmd ip neigh flush all
+		run_cmd_nsb ${ping6} -c1 -w1 ${NSA_IP6}
+		log_test $? 0 "Bridge into VRF with br_netfilter - IPv6 ping in"
+	fi
+
+	setup_cmd ip li set br0 nomaster
+	setup_cmd ip li add br0.100 link br0 type vlan id 100
+	setup_cmd ip li set br0.100 vrf ${VRF} up
+	setup_cmd ip    addr add dev br0.100 172.16.101.1/24
+	setup_cmd ip -6 addr add dev br0.100 2001:db8:101::1/64 nodad
+
+	setup_cmd_nsb ip li add vlan100 link ${NSB_DEV} type vlan id 100
+	setup_cmd_nsb ip addr add dev vlan100 172.16.101.2/24
+	setup_cmd_nsb ip -6 addr add dev vlan100 2001:db8:101::2/64 nodad
+	setup_cmd_nsb ip li set vlan100 up
+	sleep 1
+
+	rmmod br_netfilter 2>/dev/null
+
+	run_cmd ip neigh flush all
+	run_cmd ping -c1 -w1 -I br0.100 172.16.101.2
+	log_test $? 0 "Bridge vlan into VRF - IPv4 ping out"
+
+	run_cmd ip neigh flush all
+	run_cmd ${ping6} -c1 -w1 -I br0.100 2001:db8:101::2
+	log_test $? 0 "Bridge vlan into VRF - IPv6 ping out"
+
+	run_cmd ip neigh flush all
+	run_cmd_nsb ping -c1 -w1 172.16.101.1
+	log_test $? 0 "Bridge vlan into VRF - IPv4 ping in"
+
+	run_cmd ip neigh flush all
+	run_cmd_nsb ${ping6} -c1 -w1 2001:db8:101::1
+	log_test $? 0 "Bridge vlan into VRF - IPv6 ping in"
+
+	modprobe br_netfilter
+	if [ $? -eq 0 ]; then
+		run_cmd ip neigh flush all
+		run_cmd ping -c1 -w1 -I br0.100 172.16.101.2
+		log_test $? 0 "Bridge vlan into VRF with br_netfilter - IPv4 ping out"
+
+		run_cmd ip neigh flush all
+		run_cmd ${ping6} -c1 -w1 -I br0.100 2001:db8:101::2
+		log_test $? 0 "Bridge vlan into VRF with br_netfilter - IPv6 ping out"
+
+		run_cmd ip neigh flush all
+		run_cmd_nsb ping -c1 -w1 172.16.101.1
+		log_test $? 0 "Bridge vlan into VRF - IPv4 ping in"
+
+		run_cmd ip neigh flush all
+		run_cmd_nsb ${ping6} -c1 -w1 2001:db8:101::1
+		log_test $? 0 "Bridge vlan into VRF - IPv6 ping in"
+	fi
+
+	setup_cmd ip li del br0 2>/dev/null
+	setup_cmd_nsb ip li del vlan100 2>/dev/null
+}
+
+use_cases()
+{
+	log_section "Use cases"
+	use_case_br
+}
+
+################################################################################
 # usage
 
 usage()
@@ -3269,6 +3389,8 @@ EOF
 
 TESTS_IPV4="ipv4_ping ipv4_tcp ipv4_udp ipv4_addr_bind ipv4_runtime ipv4_netfilter"
 TESTS_IPV6="ipv6_ping ipv6_tcp ipv6_udp ipv6_addr_bind ipv6_runtime ipv6_netfilter"
+TESTS_OTHER="use_cases"
+
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -3320,6 +3442,8 @@ do
 	ipv6_runtime)    ipv6_runtime;;
 	ipv6_netfilter)  ipv6_netfilter;;
 
+	use_cases)       use_cases;;
+
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
 	vrf_setup)	 setup "yes"; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 01/15] selftests: Add nettest
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add nettest - a simple program with an implementation for various networking
APIs. nettest is used for tcp, udp and raw functional tests for both IPv4
and IPv6.

Point of this command versus existing utilities:
- controlled implementation of the APIs and the order in which they
  are called,
- ability to verify ingress device, local and remote addresses,
- timeout for controlled test length,
- ability to discriminate a timeout from a system call failure, and
- simplicity with test scripts.

The command returns:
  0  on success,
  1  for any system call failure, and
  2  on timeout.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/Makefile  |    2 +-
 tools/testing/selftests/net/nettest.c | 1756 +++++++++++++++++++++++++++++++++
 2 files changed, 1757 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/net/nettest.c

diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 1b24e36b4047..ba9ee36c9e94 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -12,7 +12,7 @@ TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_a
 TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
 TEST_PROGS += tcp_fastopen_backup_key.sh
 TEST_PROGS_EXTENDED := in_netns.sh
-TEST_GEN_FILES =  socket
+TEST_GEN_FILES =  socket nettest
 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
 TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite
 TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx ip_defrag
diff --git a/tools/testing/selftests/net/nettest.c b/tools/testing/selftests/net/nettest.c
new file mode 100644
index 000000000000..9278f8460d75
--- /dev/null
+++ b/tools/testing/selftests/net/nettest.c
@@ -0,0 +1,1756 @@
+// SPDX-License-Identifier: GPL-2.0
+/* nettest - used for functional tests of networking APIs
+ *
+ * Copyright (c) 2013-2019 David Ahern <dsahern@gmail.com>. All rights reserved.
+ */
+
+#define _GNU_SOURCE
+#include <features.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/tcp.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+
+#ifndef IPV6_UNICAST_IF
+#define IPV6_UNICAST_IF         76
+#endif
+#ifndef IPV6_MULTICAST_IF
+#define IPV6_MULTICAST_IF       17
+#endif
+
+#define DEFAULT_PORT 12345
+
+#ifndef MAX
+#define MAX(a, b)  ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b)  ((a) < (b) ? (a) : (b))
+#endif
+
+struct sock_args {
+	/* local address */
+	union {
+		struct in_addr  in;
+		struct in6_addr in6;
+	} local_addr;
+
+	/* remote address */
+	union {
+		struct in_addr  in;
+		struct in6_addr in6;
+	} remote_addr;
+	int scope_id;  /* remote scope; v6 send only */
+
+	struct in_addr grp;     /* multicast group */
+
+	unsigned int has_local_ip:1,
+		     has_remote_ip:1,
+		     has_grp:1,
+		     has_expected_laddr:1,
+		     has_expected_raddr:1,
+		     bind_test_only:1;
+
+	unsigned short port;
+
+	int type;      /* DGRAM, STREAM, RAW */
+	int protocol;
+	int version;   /* AF_INET/AF_INET6 */
+
+	int use_setsockopt;
+	int use_cmsg;
+	const char *dev;
+	int ifindex;
+	const char *password;
+
+	/* expected addresses and device index for connection */
+	int expected_ifindex;
+
+	/* local address */
+	union {
+		struct in_addr  in;
+		struct in6_addr in6;
+	} expected_laddr;
+
+	/* remote address */
+	union {
+		struct in_addr  in;
+		struct in6_addr in6;
+	} expected_raddr;
+};
+
+static int server_mode;
+static unsigned int prog_timeout = 5;
+static unsigned int interactive;
+static int iter = 1;
+static char *msg = "Hello world!";
+static int msglen;
+static int quiet;
+static int try_broadcast = 1;
+
+static char *timestamp(char *timebuf, int buflen)
+{
+	time_t now;
+
+	now = time(NULL);
+	if (strftime(timebuf, buflen, "%T", localtime(&now)) == 0) {
+		memset(timebuf, 0, buflen);
+		strncpy(timebuf, "00:00:00", buflen-1);
+	}
+
+	return timebuf;
+}
+
+static void log_msg(const char *format, ...)
+{
+	char timebuf[64];
+	va_list args;
+
+	if (quiet)
+		return;
+
+	fprintf(stdout, "%s %s:",
+		timestamp(timebuf, sizeof(timebuf)),
+		server_mode ? "server" : "client");
+	va_start(args, format);
+	vfprintf(stdout, format, args);
+	va_end(args);
+
+	fflush(stdout);
+}
+
+static void log_error(const char *format, ...)
+{
+	char timebuf[64];
+	va_list args;
+
+	if (quiet)
+		return;
+
+	fprintf(stderr, "%s %s:",
+		timestamp(timebuf, sizeof(timebuf)),
+		server_mode ? "server" : "client");
+	va_start(args, format);
+	vfprintf(stderr, format, args);
+	va_end(args);
+
+	fflush(stderr);
+}
+
+static void log_err_errno(const char *fmt, ...)
+{
+	char timebuf[64];
+	va_list args;
+
+	if (quiet)
+		return;
+
+	fprintf(stderr, "%s %s: ",
+		timestamp(timebuf, sizeof(timebuf)),
+		server_mode ? "server" : "client");
+	va_start(args, fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+
+	fprintf(stderr, ": %d: %s\n", errno, strerror(errno));
+	fflush(stderr);
+}
+
+static void log_address(const char *desc, struct sockaddr *sa)
+{
+	char addrstr[64];
+
+	if (quiet)
+		return;
+
+	if (sa->sa_family == AF_INET) {
+		struct sockaddr_in *s = (struct sockaddr_in *) sa;
+
+		log_msg("%s %s:%d",
+			desc,
+			inet_ntop(AF_INET, &s->sin_addr, addrstr,
+				  sizeof(addrstr)),
+			ntohs(s->sin_port));
+
+	} else if (sa->sa_family == AF_INET6) {
+		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
+
+		log_msg("%s [%s]:%d",
+			desc,
+			inet_ntop(AF_INET6, &s6->sin6_addr, addrstr,
+				  sizeof(addrstr)),
+			ntohs(s6->sin6_port));
+	}
+
+	printf("\n");
+
+	fflush(stdout);
+}
+
+static int tcp_md5sig(int sd, void *addr, socklen_t alen, const char *password)
+{
+	struct tcp_md5sig md5sig;
+	int keylen = password ? strlen(password) : 0;
+	int rc;
+
+	memset(&md5sig, 0, sizeof(md5sig));
+	memcpy(&md5sig.tcpm_addr, addr, alen);
+	md5sig.tcpm_keylen = keylen;
+
+	if (keylen)
+		memcpy(md5sig.tcpm_key, password, keylen);
+
+	rc = setsockopt(sd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig));
+	if (rc < 0) {
+		/* ENOENT is harmless. Returned when a password is cleared */
+		if (errno == ENOENT)
+			rc = 0;
+		else
+			log_err_errno("setsockopt(TCP_MD5SIG)");
+	}
+
+	return rc;
+}
+
+static int tcp_md5_remote(int sd, struct sock_args *args)
+{
+	struct sockaddr_in sin = {
+		.sin_family = AF_INET,
+	};
+	struct sockaddr_in6 sin6 = {
+		.sin6_family = AF_INET6,
+	};
+	void *addr;
+	int alen;
+
+	switch (args->version) {
+	case AF_INET:
+		sin.sin_port = htons(args->port);
+		sin.sin_addr = args->remote_addr.in;
+		addr = &sin;
+		alen = sizeof(sin);
+		break;
+	case AF_INET6:
+		sin6.sin6_port = htons(args->port);
+		sin6.sin6_addr = args->remote_addr.in6;
+		addr = &sin6;
+		alen = sizeof(sin6);
+		break;
+	default:
+		log_error("unknown address family\n");
+		exit(1);
+	}
+
+	if (tcp_md5sig(sd, addr, alen, args->password))
+		return -1;
+
+	return 0;
+}
+
+static int get_ifidx(const char *ifname)
+{
+	struct ifreq ifdata;
+	int sd, rc;
+
+	if (!ifname || *ifname == '\0')
+		return 0;
+
+	memset(&ifdata, 0, sizeof(ifdata));
+
+	strcpy(ifdata.ifr_name, ifname);
+
+	sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sd < 0) {
+		log_err_errno("socket failed");
+		return 0;
+	}
+
+	rc = ioctl(sd, SIOCGIFINDEX, (char *)&ifdata);
+	close(sd);
+	if (rc != 0) {
+		log_err_errno("ioctl(SIOCGIFINDEX) failed");
+		return 0;
+	}
+
+	return ifdata.ifr_ifindex;
+}
+
+static int bind_to_device(int sd, const char *name)
+{
+	int rc;
+
+	rc = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1);
+	if (rc < 0)
+		log_err_errno("setsockopt(SO_BINDTODEVICE)");
+
+	return rc;
+}
+
+static int get_bind_to_device(int sd, char *name, size_t len)
+{
+	int rc;
+	socklen_t optlen = len;
+
+	name[0] = '\0';
+	rc = getsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, name, &optlen);
+	if (rc < 0)
+		log_err_errno("setsockopt(SO_BINDTODEVICE)");
+
+	return rc;
+}
+
+static int check_device(int sd, struct sock_args *args)
+{
+	int ifindex = 0;
+	char name[32];
+
+	if (get_bind_to_device(sd, name, sizeof(name)))
+		*name = '\0';
+	else
+		ifindex = get_ifidx(name);
+
+	log_msg("    bound to device %s/%d\n",
+		*name ? name : "<none>", ifindex);
+
+	if (!args->expected_ifindex)
+		return 0;
+
+	if (args->expected_ifindex != ifindex) {
+		log_error("Device index mismatch: expected %d have %d\n",
+			  args->expected_ifindex, ifindex);
+		return 1;
+	}
+
+	log_msg("Device index matches: expected %d have %d\n",
+		args->expected_ifindex, ifindex);
+
+	return 0;
+}
+
+static int set_pktinfo_v4(int sd)
+{
+	int one = 1;
+	int rc;
+
+	rc = setsockopt(sd, SOL_IP, IP_PKTINFO, &one, sizeof(one));
+	if (rc < 0 && rc != -ENOTSUP)
+		log_err_errno("setsockopt(IP_PKTINFO)");
+
+	return rc;
+}
+
+static int set_recvpktinfo_v6(int sd)
+{
+	int one = 1;
+	int rc;
+
+	rc = setsockopt(sd, SOL_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+	if (rc < 0 && rc != -ENOTSUP)
+		log_err_errno("setsockopt(IPV6_RECVPKTINFO)");
+
+	return rc;
+}
+
+static int set_recverr_v4(int sd)
+{
+	int one = 1;
+	int rc;
+
+	rc = setsockopt(sd, SOL_IP, IP_RECVERR, &one, sizeof(one));
+	if (rc < 0 && rc != -ENOTSUP)
+		log_err_errno("setsockopt(IP_RECVERR)");
+
+	return rc;
+}
+
+static int set_recverr_v6(int sd)
+{
+	int one = 1;
+	int rc;
+
+	rc = setsockopt(sd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+	if (rc < 0 && rc != -ENOTSUP)
+		log_err_errno("setsockopt(IPV6_RECVERR)");
+
+	return rc;
+}
+
+static int set_unicast_if(int sd, int ifindex, int version)
+{
+	int opt = IP_UNICAST_IF;
+	int level = SOL_IP;
+	int rc;
+
+	ifindex = htonl(ifindex);
+
+	if (version == AF_INET6) {
+		opt = IPV6_UNICAST_IF;
+		level = SOL_IPV6;
+	}
+	rc = setsockopt(sd, level, opt, &ifindex, sizeof(ifindex));
+	if (rc < 0)
+		log_err_errno("setsockopt(IP_UNICAST_IF)");
+
+	return rc;
+}
+
+static int set_multicast_if(int sd, int ifindex)
+{
+	struct ip_mreqn mreq = { .imr_ifindex = ifindex };
+	int rc;
+
+	rc = setsockopt(sd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq));
+	if (rc < 0)
+		log_err_errno("setsockopt(IP_MULTICAST_IF)");
+
+	return rc;
+}
+
+static int set_membership(int sd, uint32_t grp, uint32_t addr, const char *dev)
+{
+	uint32_t if_addr = addr;
+	struct ip_mreqn mreq;
+	int rc;
+
+	if (addr == htonl(INADDR_ANY) && !dev) {
+		log_error("Either local address or device needs to be given for multicast membership\n");
+		return -1;
+	}
+
+	mreq.imr_multiaddr.s_addr = grp;
+	mreq.imr_address.s_addr = if_addr;
+	mreq.imr_ifindex = dev ? get_ifidx(dev) : 0;
+
+	rc = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+	if (rc < 0) {
+		log_err_errno("setsockopt(IP_ADD_MEMBERSHIP)");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int set_broadcast(int sd)
+{
+	unsigned int one = 1;
+	int rc = 0;
+
+	if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) != 0) {
+		log_err_errno("setsockopt(SO_BROADCAST)");
+		rc = -1;
+	}
+
+	return rc;
+}
+
+static int set_reuseport(int sd)
+{
+	unsigned int one = 1;
+	int rc = 0;
+
+	if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != 0) {
+		log_err_errno("setsockopt(SO_REUSEPORT)");
+		rc = -1;
+	}
+
+	return rc;
+}
+
+static int set_reuseaddr(int sd)
+{
+	unsigned int one = 1;
+	int rc = 0;
+
+	if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) {
+		log_err_errno("setsockopt(SO_REUSEADDR)");
+		rc = -1;
+	}
+
+	return rc;
+}
+
+static int str_to_uint(const char *str, int min, int max, unsigned int *value)
+{
+	int number;
+	char *end;
+
+	errno = 0;
+	number = (unsigned int) strtoul(str, &end, 0);
+
+	/* entire string should be consumed by conversion
+	 * and value should be between min and max
+	 */
+	if (((*end == '\0') || (*end == '\n')) && (end != str) &&
+	    (errno != ERANGE) && (min <= number) && (number <= max)) {
+		*value = number;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int expected_addr_match(struct sockaddr *sa, void *expected,
+			       const char *desc)
+{
+	char addrstr[64];
+	int rc = 0;
+
+	if (sa->sa_family == AF_INET) {
+		struct sockaddr_in *s = (struct sockaddr_in *) sa;
+		struct in_addr *exp_in = (struct in_addr *) expected;
+
+		if (s->sin_addr.s_addr != exp_in->s_addr) {
+			log_error("%s address does not match expected %s",
+				  desc,
+				  inet_ntop(AF_INET, exp_in,
+					    addrstr, sizeof(addrstr)));
+			rc = 1;
+		}
+	} else if (sa->sa_family == AF_INET6) {
+		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
+		struct in6_addr *exp_in = (struct in6_addr *) expected;
+
+		if (memcmp(&s6->sin6_addr, exp_in, sizeof(*exp_in))) {
+			log_error("%s address does not match expected %s",
+				  desc,
+				  inet_ntop(AF_INET6, exp_in,
+					    addrstr, sizeof(addrstr)));
+			rc = 1;
+		}
+	} else {
+		log_error("%s address does not match expected - unknown family",
+			  desc);
+		rc = 1;
+	}
+
+	if (!rc)
+		log_msg("%s address matches expected\n", desc);
+
+	return rc;
+}
+
+static int show_sockstat(int sd, struct sock_args *args)
+{
+	struct sockaddr_in6 local_addr, remote_addr;
+	socklen_t alen = sizeof(local_addr);
+	struct sockaddr *sa;
+	const char *desc;
+	int rc = 0;
+
+	desc = server_mode ? "server local:" : "client local:";
+	sa = (struct sockaddr *) &local_addr;
+	if (getsockname(sd, sa, &alen) == 0) {
+		log_address(desc, sa);
+
+		if (args->has_expected_laddr) {
+			rc = expected_addr_match(sa, &args->expected_laddr,
+						 "local");
+		}
+	} else {
+		log_err_errno("getsockname failed");
+	}
+
+	sa = (struct sockaddr *) &remote_addr;
+	desc = server_mode ? "server peer:" : "client peer:";
+	if (getpeername(sd, sa, &alen) == 0) {
+		log_address(desc, sa);
+
+		if (args->has_expected_raddr) {
+			rc |= expected_addr_match(sa, &args->expected_raddr,
+						 "remote");
+		}
+	} else {
+		log_err_errno("getpeername failed");
+	}
+
+	return rc;
+}
+
+static int get_index_from_cmsg(struct msghdr *m)
+{
+	struct cmsghdr *cm;
+	int ifindex = 0;
+	char buf[64];
+
+	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(m);
+	     m->msg_controllen != 0 && cm;
+	     cm = (struct cmsghdr *)CMSG_NXTHDR(m, cm)) {
+
+		if (cm->cmsg_level == SOL_IP &&
+		    cm->cmsg_type == IP_PKTINFO) {
+			struct in_pktinfo *pi;
+
+			pi = (struct in_pktinfo *)(CMSG_DATA(cm));
+			inet_ntop(AF_INET, &pi->ipi_addr, buf, sizeof(buf));
+			ifindex = pi->ipi_ifindex;
+		} else if (cm->cmsg_level == SOL_IPV6 &&
+			   cm->cmsg_type == IPV6_PKTINFO) {
+			struct in6_pktinfo *pi6;
+
+			pi6 = (struct in6_pktinfo *)(CMSG_DATA(cm));
+			inet_ntop(AF_INET6, &pi6->ipi6_addr, buf, sizeof(buf));
+			ifindex = pi6->ipi6_ifindex;
+		}
+	}
+
+	if (ifindex) {
+		log_msg("    pktinfo: ifindex %d dest addr %s\n",
+			ifindex, buf);
+	}
+	return ifindex;
+}
+
+static int send_msg_no_cmsg(int sd, void *addr, socklen_t alen)
+{
+	int err;
+
+again:
+	err = sendto(sd, msg, msglen, 0, addr, alen);
+	if (err < 0) {
+		if (errno == EACCES && try_broadcast) {
+			try_broadcast = 0;
+			if (!set_broadcast(sd))
+				goto again;
+			errno = EACCES;
+		}
+
+		log_err_errno("sendto failed");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int send_msg_cmsg(int sd, void *addr, socklen_t alen,
+			 int ifindex, int version)
+{
+	unsigned char cmsgbuf[64];
+	struct iovec iov[2];
+	struct cmsghdr *cm;
+	struct msghdr m;
+	int err;
+
+	iov[0].iov_base = msg;
+	iov[0].iov_len = msglen;
+	m.msg_iov = iov;
+	m.msg_iovlen = 1;
+	m.msg_name = (caddr_t)addr;
+	m.msg_namelen = alen;
+
+	memset(cmsgbuf, 0, sizeof(cmsgbuf));
+	cm = (struct cmsghdr *)cmsgbuf;
+	m.msg_control = (caddr_t)cm;
+
+	if (version == AF_INET) {
+		struct in_pktinfo *pi;
+
+		cm->cmsg_level = SOL_IP;
+		cm->cmsg_type = IP_PKTINFO;
+		cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+		pi = (struct in_pktinfo *)(CMSG_DATA(cm));
+		pi->ipi_ifindex = ifindex;
+
+		m.msg_controllen = cm->cmsg_len;
+
+	} else if (version == AF_INET6) {
+		struct in6_pktinfo *pi6;
+
+		cm->cmsg_level = SOL_IPV6;
+		cm->cmsg_type = IPV6_PKTINFO;
+		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+		pi6 = (struct in6_pktinfo *)(CMSG_DATA(cm));
+		pi6->ipi6_ifindex = ifindex;
+
+		m.msg_controllen = cm->cmsg_len;
+	}
+
+again:
+	err = sendmsg(sd, &m, 0);
+	if (err < 0) {
+		if (errno == EACCES && try_broadcast) {
+			try_broadcast = 0;
+			if (!set_broadcast(sd))
+				goto again;
+			errno = EACCES;
+		}
+
+		log_err_errno("sendmsg failed");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int send_msg(int sd, void *addr, socklen_t alen, struct sock_args *args)
+{
+	if (args->type == SOCK_STREAM) {
+		if (write(sd, msg, msglen) < 0) {
+			log_err_errno("write failed sending msg to peer");
+			return 1;
+		}
+	} else if (args->ifindex && args->use_cmsg) {
+		if (send_msg_cmsg(sd, addr, alen, args->ifindex, args->version))
+			return 1;
+	} else {
+		if (send_msg_no_cmsg(sd, addr, alen))
+			return 1;
+	}
+
+	log_msg("Sent message:\n");
+	log_msg("    %.24s%s\n", msg, msglen > 24 ? " ..." : "");
+
+	return 0;
+}
+
+static int socket_read_dgram(int sd, struct sock_args *args)
+{
+	unsigned char addr[sizeof(struct sockaddr_in6)];
+	struct sockaddr *sa = (struct sockaddr *) addr;
+	socklen_t alen = sizeof(addr);
+	struct iovec iov[2];
+	struct msghdr m = {
+		.msg_name = (caddr_t)addr,
+		.msg_namelen = alen,
+		.msg_iov = iov,
+		.msg_iovlen = 1,
+	};
+	unsigned char cmsgbuf[256];
+	struct cmsghdr *cm = (struct cmsghdr *)cmsgbuf;
+	char buf[16*1024];
+	int ifindex;
+	int len;
+
+	iov[0].iov_base = (caddr_t)buf;
+	iov[0].iov_len = sizeof(buf);
+
+	memset(cmsgbuf, 0, sizeof(cmsgbuf));
+	m.msg_control = (caddr_t)cm;
+	m.msg_controllen = sizeof(cmsgbuf);
+
+	len = recvmsg(sd, &m, 0);
+	if (len == 0) {
+		log_msg("peer closed connection.\n");
+		return 0;
+	} else if (len < 0) {
+		log_msg("failed to read message: %d: %s\n",
+			errno, strerror(errno));
+		return -1;
+	}
+
+	buf[len] = '\0';
+
+	log_address("Message from:", sa);
+	log_msg("    %.24s%s\n", buf, len > 24 ? " ..." : "");
+
+	ifindex = get_index_from_cmsg(&m);
+	if (args->expected_ifindex) {
+		if (args->expected_ifindex != ifindex) {
+			log_error("Device index mismatch: expected %d have %d\n",
+				  args->expected_ifindex, ifindex);
+			return -1;
+		}
+		log_msg("Device index matches: expected %d have %d\n",
+			args->expected_ifindex, ifindex);
+	}
+
+	if (!interactive && server_mode) {
+		if (sa->sa_family == AF_INET6) {
+			struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
+			struct in6_addr *in6 = &s6->sin6_addr;
+
+			if (IN6_IS_ADDR_V4MAPPED(in6)) {
+				const uint32_t *pa = (uint32_t *) &in6->s6_addr;
+				struct in_addr in4;
+				struct sockaddr_in *sin;
+
+				sin = (struct sockaddr_in *) addr;
+				pa += 3;
+				in4.s_addr = *pa;
+				sin->sin_addr = in4;
+				sin->sin_family = AF_INET;
+				if (send_msg_cmsg(sd, addr, alen,
+						  ifindex, AF_INET) < 0)
+					goto out_err;
+			}
+		}
+again:
+		iov[0].iov_len = len;
+
+		if (args->version == AF_INET6) {
+			struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
+
+			if (args->dev) {
+				/* avoid PKTINFO conflicts with bindtodev */
+				if (sendto(sd, buf, len, 0,
+					   (void *) addr, alen) < 0)
+					goto out_err;
+			} else {
+				/* kernel is allowing scope_id to be set to VRF
+				 * index for LLA. for sends to global address
+				 * reset scope id
+				 */
+				s6->sin6_scope_id = ifindex;
+				if (sendmsg(sd, &m, 0) < 0)
+					goto out_err;
+			}
+		} else {
+			int err;
+
+			err = sendmsg(sd, &m, 0);
+			if (err < 0) {
+				if (errno == EACCES && try_broadcast) {
+					try_broadcast = 0;
+					if (!set_broadcast(sd))
+						goto again;
+					errno = EACCES;
+				}
+				goto out_err;
+			}
+		}
+		log_msg("Sent message:\n");
+		log_msg("    %.24s%s\n", buf, len > 24 ? " ..." : "");
+	}
+
+	return 1;
+out_err:
+	log_err_errno("failed to send msg to peer");
+	return -1;
+}
+
+static int socket_read_stream(int sd)
+{
+	char buf[1024];
+	int len;
+
+	len = read(sd, buf, sizeof(buf)-1);
+	if (len == 0) {
+		log_msg("client closed connection.\n");
+		return 0;
+	} else if (len < 0) {
+		log_msg("failed to read message\n");
+		return -1;
+	}
+
+	buf[len] = '\0';
+	log_msg("Incoming message:\n");
+	log_msg("    %.24s%s\n", buf, len > 24 ? " ..." : "");
+
+	if (!interactive && server_mode) {
+		if (write(sd, buf, len) < 0) {
+			log_err_errno("failed to send buf");
+			return -1;
+		}
+		log_msg("Sent message:\n");
+		log_msg("     %.24s%s\n", buf, len > 24 ? " ..." : "");
+	}
+
+	return 1;
+}
+
+static int socket_read(int sd, struct sock_args *args)
+{
+	if (args->type == SOCK_STREAM)
+		return socket_read_stream(sd);
+
+	return socket_read_dgram(sd, args);
+}
+
+static int stdin_to_socket(int sd, int type, void *addr, socklen_t alen)
+{
+	char buf[1024];
+	int len;
+
+	if (fgets(buf, sizeof(buf), stdin) == NULL)
+		return 0;
+
+	len = strlen(buf);
+	if (type == SOCK_STREAM) {
+		if (write(sd, buf, len) < 0) {
+			log_err_errno("failed to send buf");
+			return -1;
+		}
+	} else {
+		int err;
+
+again:
+		err = sendto(sd, buf, len, 0, addr, alen);
+		if (err < 0) {
+			if (errno == EACCES && try_broadcast) {
+				try_broadcast = 0;
+				if (!set_broadcast(sd))
+					goto again;
+				errno = EACCES;
+			}
+			log_err_errno("failed to send msg to peer");
+			return -1;
+		}
+	}
+	log_msg("Sent message:\n");
+	log_msg("    %.24s%s\n", buf, len > 24 ? " ..." : "");
+
+	return 1;
+}
+
+static void set_recv_attr(int sd, int version)
+{
+	if (version == AF_INET6) {
+		set_recvpktinfo_v6(sd);
+		set_recverr_v6(sd);
+	} else {
+		set_pktinfo_v4(sd);
+		set_recverr_v4(sd);
+	}
+}
+
+static int msg_loop(int client, int sd, void *addr, socklen_t alen,
+		    struct sock_args *args)
+{
+	struct timeval timeout = { .tv_sec = prog_timeout }, *ptval = NULL;
+	fd_set rfds;
+	int nfds;
+	int rc;
+
+	if (args->type != SOCK_STREAM)
+		set_recv_attr(sd, args->version);
+
+	if (msg) {
+		msglen = strlen(msg);
+
+		/* client sends first message */
+		if (client) {
+			if (send_msg(sd, addr, alen, args))
+				return 1;
+		}
+		if (!interactive) {
+			ptval = &timeout;
+			if (!prog_timeout)
+				timeout.tv_sec = 5;
+		}
+	}
+
+	nfds = interactive ? MAX(fileno(stdin), sd)  + 1 : sd + 1;
+	while (1) {
+		FD_ZERO(&rfds);
+		FD_SET(sd, &rfds);
+		if (interactive)
+			FD_SET(fileno(stdin), &rfds);
+
+		rc = select(nfds, &rfds, NULL, NULL, ptval);
+		if (rc < 0) {
+			if (errno == EINTR)
+				continue;
+
+			rc = 1;
+			log_err_errno("select failed");
+			break;
+		} else if (rc == 0) {
+			log_error("Timed out waiting for response\n");
+			rc = 2;
+			break;
+		}
+
+		if (FD_ISSET(sd, &rfds)) {
+			rc = socket_read(sd, args);
+			if (rc < 0) {
+				rc = 1;
+				break;
+			}
+			if (rc == 0)
+				break;
+		}
+
+		rc = 0;
+
+		if (FD_ISSET(fileno(stdin), &rfds)) {
+			if (stdin_to_socket(sd, args->type, addr, alen) <= 0)
+				break;
+		}
+
+		if (interactive)
+			continue;
+
+		if (iter != -1) {
+			--iter;
+			if (iter == 0)
+				break;
+		}
+
+		log_msg("Going into quiet mode\n");
+		quiet = 1;
+
+		if (client) {
+			if (send_msg(sd, addr, alen, args)) {
+				rc = 1;
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int msock_init(struct sock_args *args, int server)
+{
+	uint32_t if_addr = htonl(INADDR_ANY);
+	struct sockaddr_in laddr = {
+		.sin_family = AF_INET,
+		.sin_port = htons(args->port),
+	};
+	int one = 1;
+	int sd;
+
+	if (!server && args->has_local_ip)
+		if_addr = args->local_addr.in.s_addr;
+
+	sd = socket(PF_INET, SOCK_DGRAM, 0);
+	if (sd < 0) {
+		log_err_errno("socket");
+		return -1;
+	}
+
+	if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
+		       (char *)&one, sizeof(one)) < 0) {
+		log_err_errno("Setting SO_REUSEADDR error");
+		goto out_err;
+	}
+
+	if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST,
+		       (char *)&one, sizeof(one)) < 0)
+		log_err_errno("Setting SO_BROADCAST error");
+
+	if (args->dev && bind_to_device(sd, args->dev) != 0)
+		goto out_err;
+	else if (args->use_setsockopt &&
+		 set_multicast_if(sd, args->ifindex))
+		goto out_err;
+
+	laddr.sin_addr.s_addr = if_addr;
+
+	if (bind(sd, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) {
+		log_err_errno("bind failed");
+		goto out_err;
+	}
+
+	if (server &&
+	    set_membership(sd, args->grp.s_addr,
+			   args->local_addr.in.s_addr, args->dev))
+		goto out_err;
+
+	return sd;
+out_err:
+	close(sd);
+	return -1;
+}
+
+static int msock_server(struct sock_args *args)
+{
+	return msock_init(args, 1);
+}
+
+static int msock_client(struct sock_args *args)
+{
+	return msock_init(args, 0);
+}
+
+static int bind_socket(int sd, struct sock_args *args)
+{
+	struct sockaddr_in serv_addr = {
+		.sin_family = AF_INET,
+	};
+	struct sockaddr_in6 serv6_addr = {
+		.sin6_family = AF_INET6,
+	};
+	void *addr;
+	socklen_t alen;
+
+	if (!args->has_local_ip && args->type == SOCK_RAW)
+		return 0;
+
+	switch (args->version) {
+	case AF_INET:
+		serv_addr.sin_port = htons(args->port);
+		serv_addr.sin_addr = args->local_addr.in;
+		addr = &serv_addr;
+		alen = sizeof(serv_addr);
+		break;
+
+	case AF_INET6:
+		serv6_addr.sin6_port = htons(args->port);
+		serv6_addr.sin6_addr = args->local_addr.in6;
+		addr = &serv6_addr;
+		alen = sizeof(serv6_addr);
+		break;
+
+	default:
+		log_error("Invalid address family\n");
+		return -1;
+	}
+
+	if (bind(sd, addr, alen) < 0) {
+		log_err_errno("error binding socket");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int lsock_init(struct sock_args *args)
+{
+	long flags;
+	int sd;
+
+	sd = socket(args->version, args->type, args->protocol);
+	if (sd < 0) {
+		log_err_errno("Error opening socket");
+		return  -1;
+	}
+
+	if (set_reuseaddr(sd) != 0)
+		goto err;
+
+	if (set_reuseport(sd) != 0)
+		goto err;
+
+	if (args->dev && bind_to_device(sd, args->dev) != 0)
+		goto err;
+	else if (args->use_setsockopt &&
+		 set_unicast_if(sd, args->ifindex, args->version))
+		goto err;
+
+	if (bind_socket(sd, args))
+		goto err;
+
+	if (args->bind_test_only)
+		goto out;
+
+	if (args->type == SOCK_STREAM && listen(sd, 1) < 0) {
+		log_err_errno("listen failed");
+		goto err;
+	}
+
+	flags = fcntl(sd, F_GETFL);
+	if ((flags < 0) || (fcntl(sd, F_SETFL, flags|O_NONBLOCK) < 0)) {
+		log_err_errno("Failed to set non-blocking option");
+		goto err;
+	}
+
+	if (fcntl(sd, F_SETFD, FD_CLOEXEC) < 0)
+		log_err_errno("Failed to set close-on-exec flag");
+
+out:
+	return sd;
+
+err:
+	close(sd);
+	return -1;
+}
+
+static int do_server(struct sock_args *args)
+{
+	struct timeval timeout = { .tv_sec = prog_timeout }, *ptval = NULL;
+	unsigned char addr[sizeof(struct sockaddr_in6)] = {};
+	socklen_t alen = sizeof(addr);
+	int lsd, csd = -1;
+
+	fd_set rfds;
+	int rc;
+
+	if (prog_timeout)
+		ptval = &timeout;
+
+	if (args->has_grp)
+		lsd = msock_server(args);
+	else
+		lsd = lsock_init(args);
+
+	if (lsd < 0)
+		return 1;
+
+	if (args->bind_test_only) {
+		close(lsd);
+		return 0;
+	}
+
+	if (args->type != SOCK_STREAM) {
+		rc = msg_loop(0, lsd, (void *) addr, alen, args);
+		close(lsd);
+		return rc;
+	}
+
+	if (args->password && tcp_md5_remote(lsd, args)) {
+		close(lsd);
+		return -1;
+	}
+
+	while (1) {
+		log_msg("\n");
+		log_msg("waiting for client connection.\n");
+		FD_ZERO(&rfds);
+		FD_SET(lsd, &rfds);
+
+		rc = select(lsd+1, &rfds, NULL, NULL, ptval);
+		if (rc == 0) {
+			rc = 2;
+			break;
+		}
+
+		if (rc < 0) {
+			if (errno == EINTR)
+				continue;
+
+			log_err_errno("select failed");
+			break;
+		}
+
+		if (FD_ISSET(lsd, &rfds)) {
+
+			csd = accept(lsd, (void *) addr, &alen);
+			if (csd < 0) {
+				log_err_errno("accept failed");
+				break;
+			}
+
+			rc = show_sockstat(csd, args);
+			if (rc)
+				break;
+
+			rc = check_device(csd, args);
+			if (rc)
+				break;
+		}
+
+		rc = msg_loop(0, csd, (void *) addr, alen, args);
+		close(csd);
+
+		if (!interactive)
+			break;
+	}
+
+	close(lsd);
+
+	return rc;
+}
+
+static int wait_for_connect(int sd)
+{
+	struct timeval _tv = { .tv_sec = prog_timeout }, *tv = NULL;
+	fd_set wfd;
+	int val = 0, sz = sizeof(val);
+	int rc;
+
+	FD_ZERO(&wfd);
+	FD_SET(sd, &wfd);
+
+	if (prog_timeout)
+		tv = &_tv;
+
+	rc = select(FD_SETSIZE, NULL, &wfd, NULL, tv);
+	if (rc == 0) {
+		log_error("connect timed out\n");
+		return -2;
+	} else if (rc < 0) {
+		log_err_errno("select failed");
+		return -3;
+	}
+
+	if (getsockopt(sd, SOL_SOCKET, SO_ERROR, &val, (socklen_t *)&sz) < 0) {
+		log_err_errno("getsockopt(SO_ERROR) failed");
+		return -4;
+	}
+
+	if (val != 0) {
+		log_error("connect failed: %d: %s\n", val, strerror(val));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int connectsock(void *addr, socklen_t alen, struct sock_args *args)
+{
+	int sd, rc = -1;
+	long flags;
+
+	sd = socket(args->version, args->type, args->protocol);
+	if (sd < 0) {
+		log_err_errno("Failed to create socket");
+		return -1;
+	}
+
+	flags = fcntl(sd, F_GETFL);
+	if ((flags < 0) || (fcntl(sd, F_SETFL, flags|O_NONBLOCK) < 0)) {
+		log_err_errno("Failed to set non-blocking option");
+		goto err;
+	}
+
+	if (set_reuseport(sd) != 0)
+		goto err;
+
+	if (args->dev && bind_to_device(sd, args->dev) != 0)
+		goto err;
+	else if (args->use_setsockopt &&
+		 set_unicast_if(sd, args->ifindex, args->version))
+		goto err;
+
+	if (args->has_local_ip && bind_socket(sd, args))
+		goto err;
+
+	if (args->type != SOCK_STREAM)
+		goto out;
+
+	if (args->password && tcp_md5sig(sd, addr, alen, args->password))
+		goto err;
+
+	if (args->bind_test_only)
+		goto out;
+
+	if (connect(sd, addr, alen) < 0) {
+		if (errno != EINPROGRESS) {
+			log_err_errno("Failed to connect to remote host");
+			rc = -1;
+			goto err;
+		}
+		rc = wait_for_connect(sd);
+		if (rc < 0)
+			goto err;
+	}
+out:
+	return sd;
+
+err:
+	close(sd);
+	return rc;
+}
+
+static int do_client(struct sock_args *args)
+{
+	struct sockaddr_in sin = {
+		.sin_family = AF_INET,
+	};
+	struct sockaddr_in6 sin6 = {
+		.sin6_family = AF_INET6,
+	};
+	void *addr;
+	int alen;
+	int rc = 0;
+	int sd;
+
+	if (!args->has_remote_ip && !args->has_grp) {
+		fprintf(stderr, "remote IP or multicast group not given\n");
+		return 1;
+	}
+
+	switch (args->version) {
+	case AF_INET:
+		sin.sin_port = htons(args->port);
+		if (args->has_grp)
+			sin.sin_addr = args->grp;
+		else
+			sin.sin_addr = args->remote_addr.in;
+		addr = &sin;
+		alen = sizeof(sin);
+		break;
+	case AF_INET6:
+		sin6.sin6_port = htons(args->port);
+		sin6.sin6_addr = args->remote_addr.in6;
+		sin6.sin6_scope_id = args->scope_id;
+		addr = &sin6;
+		alen = sizeof(sin6);
+		break;
+	}
+
+	if (args->has_grp)
+		sd = msock_client(args);
+	else
+		sd = connectsock(addr, alen, args);
+
+	if (sd < 0)
+		return -sd;
+
+	if (args->bind_test_only)
+		goto out;
+
+	if (args->type == SOCK_STREAM) {
+		rc = show_sockstat(sd, args);
+		if (rc != 0)
+			goto out;
+	}
+
+	rc = msg_loop(1, sd, addr, alen, args);
+
+out:
+	close(sd);
+
+	return rc;
+}
+
+enum addr_type {
+	ADDR_TYPE_LOCAL,
+	ADDR_TYPE_REMOTE,
+	ADDR_TYPE_MCAST,
+	ADDR_TYPE_EXPECTED_LOCAL,
+	ADDR_TYPE_EXPECTED_REMOTE,
+};
+
+static int convert_addr(struct sock_args *args, const char *_str,
+			enum addr_type atype)
+{
+	int family = args->version;
+	struct in6_addr *in6;
+	struct in_addr  *in;
+	const char *desc;
+	char *str, *dev;
+	void *addr;
+	int rc = 0;
+
+	str = strdup(_str);
+	if (!str)
+		return -ENOMEM;
+
+	switch (atype) {
+	case ADDR_TYPE_LOCAL:
+		desc = "local";
+		addr = &args->local_addr;
+		break;
+	case ADDR_TYPE_REMOTE:
+		desc = "remote";
+		addr = &args->remote_addr;
+		break;
+	case ADDR_TYPE_MCAST:
+		desc = "mcast grp";
+		addr = &args->grp;
+		break;
+	case ADDR_TYPE_EXPECTED_LOCAL:
+		desc = "expected local";
+		addr = &args->expected_laddr;
+		break;
+	case ADDR_TYPE_EXPECTED_REMOTE:
+		desc = "expected remote";
+		addr = &args->expected_raddr;
+		break;
+	default:
+		log_error("unknown address type");
+		exit(1);
+	}
+
+	switch (family) {
+	case AF_INET:
+		in  = (struct in_addr *) addr;
+		if (str) {
+			if (inet_pton(AF_INET, str, in) == 0) {
+				log_error("Invalid %s IP address\n", desc);
+				rc = -1;
+				goto out;
+			}
+		} else {
+			in->s_addr = htonl(INADDR_ANY);
+		}
+		break;
+
+	case AF_INET6:
+		dev = strchr(str, '%');
+		if (dev) {
+			*dev = '\0';
+			dev++;
+		}
+
+		in6 = (struct in6_addr *) addr;
+		if (str) {
+			if (inet_pton(AF_INET6, str, in6) == 0) {
+				log_error("Invalid %s IPv6 address\n", desc);
+				rc = -1;
+				goto out;
+			}
+		} else {
+			*in6 = in6addr_any;
+		}
+		if (dev) {
+			args->scope_id = get_ifidx(dev);
+			if (args->scope_id < 0) {
+				log_error("Invalid scope on %s IPv6 address\n",
+					  desc);
+				rc = -1;
+				goto out;
+			}
+		}
+		break;
+
+	default:
+		log_error("Invalid address family\n");
+	}
+
+out:
+	free(str);
+	return rc;
+}
+
+static char *random_msg(int len)
+{
+	int i, n = 0, olen = len + 1;
+	char *m;
+
+	if (len <= 0)
+		return NULL;
+
+	m = malloc(olen);
+	if (!m)
+		return NULL;
+
+	while (len > 26) {
+		i = snprintf(m + n, olen - n, "%.26s",
+			     "abcdefghijklmnopqrstuvwxyz");
+		n += i;
+		len -= i;
+	}
+	i = snprintf(m + n, olen - n, "%.*s", len,
+		     "abcdefghijklmnopqrstuvwxyz");
+	return m;
+}
+
+#define GETOPT_STR  "sr:l:p:t:g:P:DRn:M:d:SCi6L:0:1:2:Fbq"
+
+static void print_usage(char *prog)
+{
+	printf(
+	"usage: %s OPTS\n"
+	"Required:\n"
+	"    -r addr       remote address to connect to (client mode only)\n"
+	"    -p port       port to connect to (client mode)/listen on (server mode)\n"
+	"                  (default: %d)\n"
+	"    -s            server mode (default: client mode)\n"
+	"    -t            timeout seconds (default: none)\n"
+	"\n"
+	"Optional:\n"
+	"    -F            Restart server loop\n"
+	"    -6            IPv6 (default is IPv4)\n"
+	"    -P proto      protocol for socket: icmp, ospf (default: none)\n"
+	"    -D|R          datagram (D) / raw (R) socket (default stream)\n"
+	"    -l addr       local address to bind to\n"
+	"\n"
+	"    -d dev        bind socket to given device name\n"
+	"    -S            use setsockopt (IP_UNICAST_IF or IP_MULTICAST_IF)\n"
+	"                  to set device binding\n"
+	"    -C            use cmsg and IP_PKTINFO to specify device binding\n"
+	"\n"
+	"    -L len        send random message of given length\n"
+	"    -n num        number of times to send message\n"
+	"\n"
+	"    -M password   use MD5 sum protection\n"
+	"    -g grp        multicast group (e.g., 239.1.1.1)\n"
+	"    -i            interactive mode (default is echo and terminate)\n"
+	"\n"
+	"    -0 addr       Expected local address\n"
+	"    -1 addr       Expected remote address\n"
+	"    -2 dev        Expected device name (or index) to receive packet\n"
+	"\n"
+	"    -b            Bind test only.\n"
+	"    -q            Be quiet. Run test without printing anything.\n"
+	, prog, DEFAULT_PORT);
+}
+
+int main(int argc, char *argv[])
+{
+	struct sock_args args = {
+		.version = AF_INET,
+		.type    = SOCK_STREAM,
+		.port    = DEFAULT_PORT,
+	};
+	struct protoent *pe;
+	unsigned int tmp;
+	int forever = 0;
+
+	/* process inputs */
+	extern char *optarg;
+	int rc = 0;
+
+	/*
+	 * process input args
+	 */
+
+	while ((rc = getopt(argc, argv, GETOPT_STR)) != -1) {
+		switch (rc) {
+		case 's':
+			server_mode = 1;
+			break;
+		case 'F':
+			forever = 1;
+			break;
+		case 'l':
+			args.has_local_ip = 1;
+			if (convert_addr(&args, optarg, ADDR_TYPE_LOCAL) < 0)
+				return 1;
+			break;
+		case 'r':
+			args.has_remote_ip = 1;
+			if (convert_addr(&args, optarg, ADDR_TYPE_REMOTE) < 0)
+				return 1;
+			break;
+		case 'p':
+			if (str_to_uint(optarg, 1, 65535, &tmp) != 0) {
+				fprintf(stderr, "Invalid port\n");
+				return 1;
+			}
+			args.port = (unsigned short) tmp;
+			break;
+		case 't':
+			if (str_to_uint(optarg, 0, INT_MAX,
+					&prog_timeout) != 0) {
+				fprintf(stderr, "Invalid timeout\n");
+				return 1;
+			}
+			break;
+		case 'D':
+			args.type = SOCK_DGRAM;
+			break;
+		case 'R':
+			args.type = SOCK_RAW;
+			args.port = 0;
+			break;
+		case 'P':
+			pe = getprotobyname(optarg);
+			if (pe) {
+				args.protocol = pe->p_proto;
+			} else {
+				if (str_to_uint(optarg, 0, 0xffff, &tmp) != 0) {
+					fprintf(stderr, "Invalid potocol\n");
+					return 1;
+				}
+				args.protocol = tmp;
+			}
+			break;
+		case 'n':
+			iter = atoi(optarg);
+			break;
+		case 'L':
+			msg = random_msg(atoi(optarg));
+			break;
+		case 'M':
+			args.password = optarg;
+			break;
+		case 'S':
+			args.use_setsockopt = 1;
+			break;
+		case 'C':
+			args.use_cmsg = 1;
+			break;
+		case 'd':
+			args.dev = optarg;
+			args.ifindex = get_ifidx(optarg);
+			if (args.ifindex < 0) {
+				fprintf(stderr, "Invalid device name\n");
+				return 1;
+			}
+			break;
+		case 'i':
+			interactive = 1;
+			break;
+		case 'g':
+			args.has_grp = 1;
+			if (convert_addr(&args, optarg, ADDR_TYPE_MCAST) < 0)
+				return 1;
+			args.type = SOCK_DGRAM;
+			break;
+		case '6':
+			args.version = AF_INET6;
+			break;
+		case 'b':
+			args.bind_test_only = 1;
+			break;
+		case '0':
+			args.has_expected_laddr = 1;
+			if (convert_addr(&args, optarg,
+					 ADDR_TYPE_EXPECTED_LOCAL))
+				return 1;
+			break;
+		case '1':
+			args.has_expected_raddr = 1;
+			if (convert_addr(&args, optarg,
+					 ADDR_TYPE_EXPECTED_REMOTE))
+				return 1;
+
+			break;
+		case '2':
+			if (str_to_uint(optarg, 0, 0x7ffffff, &tmp) != 0) {
+				tmp = get_ifidx(optarg);
+				if (tmp < 0) {
+					fprintf(stderr,
+						"Invalid device index\n");
+					return 1;
+				}
+			}
+			args.expected_ifindex = (int)tmp;
+			break;
+		case 'q':
+			quiet = 1;
+			break;
+		default:
+			print_usage(argv[0]);
+			return 1;
+		}
+	}
+
+	if (args.password &&
+	    (!args.has_remote_ip || args.type != SOCK_STREAM)) {
+		log_error("MD5 passwords apply to TCP only and require a remote ip for the password\n");
+		return 1;
+	}
+
+	if ((args.use_setsockopt || args.use_cmsg) && !args.ifindex) {
+		fprintf(stderr, "Device binding not specified\n");
+		return 1;
+	}
+	if (args.use_setsockopt || args.use_cmsg)
+		args.dev = NULL;
+
+	if (iter == 0) {
+		fprintf(stderr, "Invalid number of messages to send\n");
+		return 1;
+	}
+
+	if (args.type == SOCK_STREAM && !args.protocol)
+		args.protocol = IPPROTO_TCP;
+	if (args.type == SOCK_DGRAM && !args.protocol)
+		args.protocol = IPPROTO_UDP;
+
+	if ((args.type == SOCK_STREAM || args.type == SOCK_DGRAM) &&
+	     args.port == 0) {
+		fprintf(stderr, "Invalid port number\n");
+		return 1;
+	}
+
+	if (!server_mode && !args.has_grp &&
+	    !args.has_remote_ip && !args.has_local_ip) {
+		fprintf(stderr,
+			"Local (server mode) or remote IP (client IP) required\n");
+		return 1;
+	}
+
+	if (interactive) {
+		prog_timeout = 0;
+		msg = NULL;
+	}
+
+	if (server_mode) {
+		do {
+			rc = do_server(&args);
+		} while (forever);
+
+		return rc;
+	}
+	return do_client(&args);
+}
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 04/15] selftests: Add ipv6 ping tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add IPv6 ping tests to fcnal-test.sh. Covers the permutations of directly
connected addresses, routed destinations, VRF and non-VRF, and expected
failures.

Setup includes unreachable routes and fib rules blocking traffic.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 284 +++++++++++++++++++++++++++++-
 1 file changed, 283 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 3f6e786b34ae..4da510f6d625 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -712,6 +712,287 @@ ipv4_ping()
 }
 
 ################################################################################
+# IPv6
+
+ipv6_ping_novrf()
+{
+	local a
+
+	# should not have an impact, but make a known state
+	set_sysctl net.ipv4.raw_l3mdev_accept=0 2>/dev/null
+
+	#
+	# out
+	#
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping out"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 0 "ping out, device bind"
+
+		log_start
+		run_cmd ${ping6} -c1 -w1 -I ${NSA_LO_IP6} ${a}
+		log_test_addr ${a} $? 0 "ping out, loopback address bind"
+	done
+
+	#
+	# in
+	#
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ${NSA_LINKIP6}%${NSB_DEV} ${MCAST}%${NSB_DEV}
+	do
+		log_start
+		run_cmd_nsb ${ping6} -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping in"
+	done
+
+	#
+	# local traffic, local address
+	#
+	for a in ${NSA_IP6} ${NSA_LO_IP6} ::1 ${NSA_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping local, no bind"
+	done
+
+	for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 0 "ping local, device bind"
+	done
+
+	for a in ${NSA_LO_IP6} ::1
+	do
+		log_start
+		show_hint "Fails since address on loopback is out of device scope"
+		run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 2 "ping local, device bind"
+	done
+
+	#
+	# ip rule blocks address
+	#
+	log_start
+	setup_cmd ip -6 rule add pref 32765 from all lookup local
+	setup_cmd ip -6 rule del pref 0 from all lookup local
+	setup_cmd ip -6 rule add pref 50 to ${NSB_LO_IP6} prohibit
+	setup_cmd ip -6 rule add pref 51 from ${NSB_IP6} prohibit
+
+	a=${NSB_LO_IP6}
+	run_cmd ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, blocked by rule"
+
+	log_start
+	run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule"
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Response lost due to ip rule"
+	run_cmd_nsb ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, blocked by rule"
+
+	setup_cmd ip -6 rule add pref 0 from all lookup local
+	setup_cmd ip -6 rule del pref 32765 from all lookup local
+	setup_cmd ip -6 rule del pref 50 to ${NSB_LO_IP6} prohibit
+	setup_cmd ip -6 rule del pref 51 from ${NSB_IP6} prohibit
+
+	#
+	# route blocks reachability to remote address
+	#
+	log_start
+	setup_cmd ip -6 route del ${NSB_LO_IP6}
+	setup_cmd ip -6 route add unreachable ${NSB_LO_IP6} metric 10
+	setup_cmd ip -6 route add unreachable ${NSB_IP6} metric 10
+
+	a=${NSB_LO_IP6}
+	run_cmd ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, blocked by route"
+
+	log_start
+	run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, blocked by route"
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Response lost due to ip route"
+	run_cmd_nsb ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, blocked by route"
+
+
+	#
+	# remove 'remote' routes; fallback to default
+	#
+	log_start
+	setup_cmd ip -6 ro del unreachable ${NSB_LO_IP6}
+	setup_cmd ip -6 ro del unreachable ${NSB_IP6}
+
+	a=${NSB_LO_IP6}
+	run_cmd ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, unreachable route"
+
+	log_start
+	run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, unreachable route"
+}
+
+ipv6_ping_vrf()
+{
+	local a
+
+	# should default on; does not exist on older kernels
+	set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null
+
+	#
+	# out
+	#
+	for a in ${NSB_IP6} ${NSB_LO_IP6}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 -I ${VRF} ${a}
+		log_test_addr ${a} $? 0 "ping out, VRF bind"
+	done
+
+	for a in ${NSB_LINKIP6}%${VRF} ${MCAST}%${VRF}
+	do
+		log_start
+		show_hint "Fails since VRF device does not support linklocal or multicast"
+		run_cmd ${ping6} -c1 -w1 ${a}
+		log_test_addr ${a} $? 2 "ping out, VRF bind"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 0 "ping out, device bind"
+	done
+
+	for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV}
+	do
+		log_start
+		run_cmd ip vrf exec ${VRF} ${ping6} -c1 -w1 -I ${VRF_IP6} ${a}
+		log_test_addr ${a} $? 0 "ping out, vrf device+address bind"
+	done
+
+	#
+	# in
+	#
+	for a in ${NSA_IP6} ${VRF_IP6} ${NSA_LINKIP6}%${NSB_DEV} ${MCAST}%${NSB_DEV}
+	do
+		log_start
+		run_cmd_nsb ${ping6} -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping in"
+	done
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Fails since loopback address is out of VRF scope"
+	run_cmd_nsb ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in"
+
+	#
+	# local traffic, local address
+	#
+	for a in ${NSA_IP6} ${VRF_IP6} ::1
+	do
+		log_start
+		show_hint "Source address should be ${a}"
+		run_cmd ${ping6} -c1 -w1 -I ${VRF} ${a}
+		log_test_addr ${a} $? 0 "ping local, VRF bind"
+	done
+
+	for a in ${NSA_IP6} ${NSA_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
+	do
+		log_start
+		run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 0 "ping local, device bind"
+	done
+
+	# LLA to GUA - remove ipv6 global addresses from ns-B
+	setup_cmd_nsb ip -6 addr del ${NSB_IP6}/64 dev ${NSB_DEV}
+	setup_cmd_nsb ip -6 addr del ${NSB_LO_IP6}/128 dev lo
+	setup_cmd_nsb ip -6 ro add ${NSA_IP6}/128 via ${NSA_LINKIP6} dev ${NSB_DEV}
+
+	for a in ${NSA_IP6} ${VRF_IP6}
+	do
+		log_start
+		run_cmd_nsb ${ping6} -c1 -w1 ${NSA_IP6}
+		log_test_addr ${a} $? 0 "ping in, LLA to GUA"
+	done
+
+	setup_cmd_nsb ip -6 ro del ${NSA_IP6}/128 via ${NSA_LINKIP6} dev ${NSB_DEV}
+	setup_cmd_nsb ip -6 addr add ${NSB_IP6}/64 dev ${NSB_DEV}
+	setup_cmd_nsb ip -6 addr add ${NSB_LO_IP6}/128 dev lo
+
+	#
+	# ip rule blocks address
+	#
+	log_start
+	setup_cmd ip -6 rule add pref 50 to ${NSB_LO_IP6} prohibit
+	setup_cmd ip -6 rule add pref 51 from ${NSB_IP6} prohibit
+
+	a=${NSB_LO_IP6}
+	run_cmd ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, blocked by rule"
+
+	log_start
+	run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule"
+
+	a=${NSA_LO_IP6}
+	log_start
+	show_hint "Response lost due to ip rule"
+	run_cmd_nsb ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, blocked by rule"
+
+	log_start
+	setup_cmd ip -6 rule del pref 50 to ${NSB_LO_IP6} prohibit
+	setup_cmd ip -6 rule del pref 51 from ${NSB_IP6} prohibit
+
+	#
+	# remove 'remote' routes; fallback to default
+	#
+	log_start
+	setup_cmd ip -6 ro del ${NSB_LO_IP6} vrf ${VRF}
+
+	a=${NSB_LO_IP6}
+	run_cmd ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, unreachable route"
+
+	log_start
+	run_cmd ${ping6} -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, unreachable route"
+
+	ip -netns ${NSB} -6 ro del ${NSA_LO_IP6}
+	a=${NSA_LO_IP6}
+	log_start
+	run_cmd_nsb ${ping6} -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping in, unreachable route"
+}
+
+ipv6_ping()
+{
+	log_section "IPv6 ping"
+
+	log_subsection "No VRF"
+	setup
+	ipv6_ping_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv6_ping_vrf
+}
+
+################################################################################
 # usage
 
 usage()
@@ -732,7 +1013,7 @@ EOF
 # main
 
 TESTS_IPV4="ipv4_ping"
-TESTS_IPV6=""
+TESTS_IPV6="ipv6_ping"
 PAUSE_ON_FAIL=no
 PAUSE=no
 
@@ -771,6 +1052,7 @@ for t in $TESTS
 do
 	case $t in
 	ipv4_ping|ping)  ipv4_ping;;
+	ipv6_ping|ping6) ipv6_ping;;
 
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 03/15] selftests: Add ipv4 ping tests to fcnal-test
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern
In-Reply-To: <20190801185648.27653-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Add ping tests to fcnal-test.sh. Covers the permutations of directly
connected addresses, routed destinations, VRF and non-VRF, and expected
failures.

Setup includes unreachable routes and fib rules blocking traffic.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 tools/testing/selftests/net/fcnal-test.sh | 268 +++++++++++++++++++++++++++++-
 1 file changed, 267 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh
index 22cfbd2fd09c..3f6e786b34ae 100755
--- a/tools/testing/selftests/net/fcnal-test.sh
+++ b/tools/testing/selftests/net/fcnal-test.sh
@@ -448,6 +448,270 @@ setup()
 }
 
 ################################################################################
+# IPv4
+
+ipv4_ping_novrf()
+{
+	local a
+
+	#
+	# out
+	#
+	for a in ${NSB_IP} ${NSB_LO_IP}
+	do
+		log_start
+		run_cmd ping -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping out"
+
+		log_start
+		run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 0 "ping out, device bind"
+
+		log_start
+		run_cmd ping -c1 -w1 -I ${NSA_LO_IP} ${a}
+		log_test_addr ${a} $? 0 "ping out, address bind"
+	done
+
+	#
+	# in
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP}
+	do
+		log_start
+		run_cmd_nsb ping -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping in"
+	done
+
+	#
+	# local traffic
+	#
+	for a in ${NSA_IP} ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		run_cmd ping -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping local"
+	done
+
+	#
+	# local traffic, socket bound to device
+	#
+	# address on device
+	a=${NSA_IP}
+	log_start
+	run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 0 "ping local, device bind"
+
+	# loopback addresses not reachable from device bind
+	# fails in a really weird way though because ipv4 special cases
+	# route lookups with oif set.
+	for a in ${NSA_LO_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Fails since address on loopback device is out of device scope"
+		run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 1 "ping local, device bind"
+	done
+
+	#
+	# ip rule blocks reachability to remote address
+	#
+	log_start
+	setup_cmd ip rule add pref 32765 from all lookup local
+	setup_cmd ip rule del pref 0 from all lookup local
+	setup_cmd ip rule add pref 50 to ${NSB_LO_IP} prohibit
+	setup_cmd ip rule add pref 51 from ${NSB_IP} prohibit
+
+	a=${NSB_LO_IP}
+	run_cmd ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, blocked by rule"
+
+	# NOTE: ipv4 actually allows the lookup to fail and yet still create
+	# a viable rtable if the oif (e.g., bind to device) is set, so this
+	# case succeeds despite the rule
+	# run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+
+	a=${NSA_LO_IP}
+	log_start
+	show_hint "Response generates ICMP (or arp request is ignored) due to ip rule"
+	run_cmd_nsb ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, blocked by rule"
+
+	[ "$VERBOSE" = "1" ] && echo
+	setup_cmd ip rule del pref 32765 from all lookup local
+	setup_cmd ip rule add pref 0 from all lookup local
+	setup_cmd ip rule del pref 50 to ${NSB_LO_IP} prohibit
+	setup_cmd ip rule del pref 51 from ${NSB_IP} prohibit
+
+	#
+	# route blocks reachability to remote address
+	#
+	log_start
+	setup_cmd ip route replace unreachable ${NSB_LO_IP}
+	setup_cmd ip route replace unreachable ${NSB_IP}
+
+	a=${NSB_LO_IP}
+	run_cmd ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, blocked by route"
+
+	# NOTE: ipv4 actually allows the lookup to fail and yet still create
+	# a viable rtable if the oif (e.g., bind to device) is set, so this
+	# case succeeds despite not having a route for the address
+	# run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+
+	a=${NSA_LO_IP}
+	log_start
+	show_hint "Response is dropped (or arp request is ignored) due to ip route"
+	run_cmd_nsb ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, blocked by route"
+
+	#
+	# remove 'remote' routes; fallback to default
+	#
+	log_start
+	setup_cmd ip ro del ${NSB_LO_IP}
+
+	a=${NSB_LO_IP}
+	run_cmd ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 2 "ping out, unreachable default route"
+
+	# NOTE: ipv4 actually allows the lookup to fail and yet still create
+	# a viable rtable if the oif (e.g., bind to device) is set, so this
+	# case succeeds despite not having a route for the address
+	# run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+}
+
+ipv4_ping_vrf()
+{
+	local a
+
+	# should default on; does not exist on older kernels
+	set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null
+
+	#
+	# out
+	#
+	for a in ${NSB_IP} ${NSB_LO_IP}
+	do
+		log_start
+		run_cmd ping -c1 -w1 -I ${VRF} ${a}
+		log_test_addr ${a} $? 0 "ping out, VRF bind"
+
+		log_start
+		run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 0 "ping out, device bind"
+
+		log_start
+		run_cmd ip vrf exec ${VRF} ping -c1 -w1 -I ${NSA_IP} ${a}
+		log_test_addr ${a} $? 0 "ping out, vrf device + dev address bind"
+
+		log_start
+		run_cmd ip vrf exec ${VRF} ping -c1 -w1 -I ${VRF_IP} ${a}
+		log_test_addr ${a} $? 0 "ping out, vrf device + vrf address bind"
+	done
+
+	#
+	# in
+	#
+	for a in ${NSA_IP} ${VRF_IP}
+	do
+		log_start
+		run_cmd_nsb ping -c1 -w1 ${a}
+		log_test_addr ${a} $? 0 "ping in"
+	done
+
+	#
+	# local traffic, local address
+	#
+	for a in ${NSA_IP} ${VRF_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Source address should be ${a}"
+		run_cmd ping -c1 -w1 -I ${VRF} ${a}
+		log_test_addr ${a} $? 0 "ping local, VRF bind"
+	done
+
+	#
+	# local traffic, socket bound to device
+	#
+	# address on device
+	a=${NSA_IP}
+	log_start
+	run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 0 "ping local, device bind"
+
+	# vrf device is out of scope
+	for a in ${VRF_IP} 127.0.0.1
+	do
+		log_start
+		show_hint "Fails since address on vrf device is out of device scope"
+		run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+		log_test_addr ${a} $? 1 "ping local, device bind"
+	done
+
+	#
+	# ip rule blocks address
+	#
+	log_start
+	setup_cmd ip rule add pref 50 to ${NSB_LO_IP} prohibit
+	setup_cmd ip rule add pref 51 from ${NSB_IP} prohibit
+
+	a=${NSB_LO_IP}
+	run_cmd ping -c1 -w1 -I ${VRF} ${a}
+	log_test_addr ${a} $? 2 "ping out, vrf bind, blocked by rule"
+
+	log_start
+	run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, blocked by rule"
+
+	a=${NSA_LO_IP}
+	log_start
+	show_hint "Response lost due to ip rule"
+	run_cmd_nsb ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, blocked by rule"
+
+	[ "$VERBOSE" = "1" ] && echo
+	setup_cmd ip rule del pref 50 to ${NSB_LO_IP} prohibit
+	setup_cmd ip rule del pref 51 from ${NSB_IP} prohibit
+
+	#
+	# remove 'remote' routes; fallback to default
+	#
+	log_start
+	setup_cmd ip ro del vrf ${VRF} ${NSB_LO_IP}
+
+	a=${NSB_LO_IP}
+	run_cmd ping -c1 -w1 -I ${VRF} ${a}
+	log_test_addr ${a} $? 2 "ping out, vrf bind, unreachable route"
+
+	log_start
+	run_cmd ping -c1 -w1 -I ${NSA_DEV} ${a}
+	log_test_addr ${a} $? 2 "ping out, device bind, unreachable route"
+
+	a=${NSA_LO_IP}
+	log_start
+	show_hint "Response lost by unreachable route"
+	run_cmd_nsb ping -c1 -w1 ${a}
+	log_test_addr ${a} $? 1 "ping in, unreachable route"
+}
+
+ipv4_ping()
+{
+	log_section "IPv4 ping"
+
+	log_subsection "No VRF"
+	setup
+	set_sysctl net.ipv4.raw_l3mdev_accept=0 2>/dev/null
+	ipv4_ping_novrf
+	setup
+	set_sysctl net.ipv4.raw_l3mdev_accept=1 2>/dev/null
+	ipv4_ping_novrf
+
+	log_subsection "With VRF"
+	setup "yes"
+	ipv4_ping_vrf
+}
+
+################################################################################
 # usage
 
 usage()
@@ -467,7 +731,7 @@ EOF
 ################################################################################
 # main
 
-TESTS_IPV4=""
+TESTS_IPV4="ipv4_ping"
 TESTS_IPV6=""
 PAUSE_ON_FAIL=no
 PAUSE=no
@@ -506,6 +770,8 @@ declare -i nsuccess=0
 for t in $TESTS
 do
 	case $t in
+	ipv4_ping|ping)  ipv4_ping;;
+
 	# setup namespaces and config, but do not run any tests
 	setup)		 setup; exit 0;;
 	vrf_setup)	 setup "yes"; exit 0;;
-- 
2.11.0


^ permalink raw reply related

* [PATCH net-next 00/15] net: Add functional tests for L3 and L4
From: David Ahern @ 2019-08-01 18:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, David Ahern

From: David Ahern <dsahern@gmail.com>

This is a port the functional test cases created during the development
of the VRF feature. It covers various permutations of icmp, tcp and udp
for IPv4 and IPv6 including negative tests.

David Ahern (15):
  selftests: Add nettest
  selftests: Setup for functional tests for fib and socket lookups
  selftests: Add ipv4 ping tests to fcnal-test
  selftests: Add ipv6 ping tests to fcnal-test
  selftests: Add ipv4 tcp tests to fcnal-test
  selftests: Add ipv6 tcp tests to fcnal-test
  selftests: Add ipv4 udp tests to fcnal-test
  selftests: Add ipv6 udp tests to fcnal-test
  selftests: Add ipv4 address bind tests to fcnal-test
  selftests: Add ipv6 address bind tests to fcnal-test
  selftests: Add ipv4 runtime tests to fcnal-test
  selftests: Add ipv6 runtime tests to fcnal-test
  selftests: Add ipv4 netfilter tests to fcnal-test
  selftests: Add ipv6 netfilter tests to fcnal-test
  selftests: Add use case section to fcnal-test

 tools/testing/selftests/net/Makefile      |    4 +-
 tools/testing/selftests/net/fcnal-test.sh | 3458 +++++++++++++++++++++++++++++
 tools/testing/selftests/net/nettest.c     | 1756 +++++++++++++++
 3 files changed, 5216 insertions(+), 2 deletions(-)
 create mode 100755 tools/testing/selftests/net/fcnal-test.sh
 create mode 100644 tools/testing/selftests/net/nettest.c

-- 
2.11.0


^ permalink raw reply

* [PATCH net-next 1/5] net: dsa: mv88e6xxx: lock mutex in vlan_prepare
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
  Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
	andrew, netdev, davem
In-Reply-To: <20190801183637.24841-1-vivien.didelot@gmail.com>

Lock the mutex in the mv88e6xxx_port_vlan_prepare function
called by the DSA stack, instead of doing it in the internal
mv88e6xxx_port_check_hw_vlan helper.

Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 2e500428670c..1b2cb46d3b53 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1453,12 +1453,10 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
 	if (!vid_begin)
 		return -EOPNOTSUPP;
 
-	mv88e6xxx_reg_lock(chip);
-
 	do {
 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
 		if (err)
-			goto unlock;
+			return err;
 
 		if (!vlan.valid)
 			break;
@@ -1487,15 +1485,11 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
 			dev_err(ds->dev, "p%d: hw VLAN %d already used by port %d in %s\n",
 				port, vlan.vid, i,
 				netdev_name(dsa_to_port(ds, i)->bridge_dev));
-			err = -EOPNOTSUPP;
-			goto unlock;
+			return -EOPNOTSUPP;
 		}
 	} while (vlan.vid < vid_end);
 
-unlock:
-	mv88e6xxx_reg_unlock(chip);
-
-	return err;
+	return 0;
 }
 
 static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
@@ -1529,15 +1523,15 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
 	/* If the requested port doesn't belong to the same bridge as the VLAN
 	 * members, do not support it (yet) and fallback to software VLAN.
 	 */
+	mv88e6xxx_reg_lock(chip);
 	err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
 					   vlan->vid_end);
-	if (err)
-		return err;
+	mv88e6xxx_reg_unlock(chip);
 
 	/* We don't need any dynamic resource from the kernel (yet),
 	 * so skip the prepare phase.
 	 */
-	return 0;
+	return err;
 }
 
 static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
-- 
2.22.0


^ permalink raw reply related

* [PATCH net-next 2/5] net: dsa: mv88e6xxx: explicit entry passed to vtu_getnext
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
  Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
	andrew, netdev, davem
In-Reply-To: <20190801183637.24841-1-vivien.didelot@gmail.com>

mv88e6xxx_vtu_getnext interprets two members from the input
mv88e6xxx_vtu_entry structure: the (excluded) vid member to start
the iteration from, and the valid argument specifying whether the VID
must be written or not (only required once at the start of a loop).

Explicit the assignation of these two fields right before calling
mv88e6xxx_vtu_getnext, as it is done in the mv88e6xxx_vtu_get wrapper.

Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 1b2cb46d3b53..c825fa3477fa 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1361,9 +1361,7 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip,
 static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
 {
 	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
-	struct mv88e6xxx_vtu_entry vlan = {
-		.vid = chip->info->max_vid,
-	};
+	struct mv88e6xxx_vtu_entry vlan;
 	int i, err;
 
 	bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
@@ -1378,6 +1376,9 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid)
 	}
 
 	/* Set every FID bit used by the VLAN entries */
+	vlan.vid = chip->info->max_vid;
+	vlan.valid = false;
+
 	do {
 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
 		if (err)
@@ -1441,9 +1442,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
 					u16 vid_begin, u16 vid_end)
 {
 	struct mv88e6xxx_chip *chip = ds->priv;
-	struct mv88e6xxx_vtu_entry vlan = {
-		.vid = vid_begin - 1,
-	};
+	struct mv88e6xxx_vtu_entry vlan;
 	int i, err;
 
 	/* DSA and CPU ports have to be members of multiple vlans */
@@ -1453,6 +1452,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
 	if (!vid_begin)
 		return -EOPNOTSUPP;
 
+	vlan.vid = vid_begin - 1;
+	vlan.valid = false;
+
 	do {
 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
 		if (err)
@@ -1789,9 +1791,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
 static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
 				  dsa_fdb_dump_cb_t *cb, void *data)
 {
-	struct mv88e6xxx_vtu_entry vlan = {
-		.vid = chip->info->max_vid,
-	};
+	struct mv88e6xxx_vtu_entry vlan;
 	u16 fid;
 	int err;
 
@@ -1805,6 +1805,9 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
 		return err;
 
 	/* Dump VLANs' Filtering Information Databases */
+	vlan.vid = chip->info->max_vid;
+	vlan.valid = false;
+
 	do {
 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
 		if (err)
-- 
2.22.0


^ permalink raw reply related

* [PATCH net-next 3/5] net: dsa: mv88e6xxx: call vtu_getnext directly in db load/purge
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
  Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
	andrew, netdev, davem
In-Reply-To: <20190801183637.24841-1-vivien.didelot@gmail.com>

mv88e6xxx_vtu_getnext is simple enough to call it directly in the
mv88e6xxx_port_db_load_purge function and explicit the return code
expected by switchdev for software VLANs when an hardware VLAN does
not exist.

Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c825fa3477fa..42ab57dbc790 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1540,23 +1540,36 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
 					const unsigned char *addr, u16 vid,
 					u8 state)
 {
-	struct mv88e6xxx_vtu_entry vlan;
 	struct mv88e6xxx_atu_entry entry;
+	struct mv88e6xxx_vtu_entry vlan;
+	u16 fid;
 	int err;
 
 	/* Null VLAN ID corresponds to the port private database */
-	if (vid == 0)
-		err = mv88e6xxx_port_get_fid(chip, port, &vlan.fid);
-	else
-		err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
-	if (err)
-		return err;
+	if (vid == 0) {
+		err = mv88e6xxx_port_get_fid(chip, port, &fid);
+		if (err)
+			return err;
+	} else {
+		vlan.vid = vid - 1;
+		vlan.valid = false;
+
+		err = mv88e6xxx_vtu_getnext(chip, &vlan);
+		if (err)
+			return err;
+
+		/* switchdev expects -EOPNOTSUPP to honor software VLANs */
+		if (vlan.vid != vid || !vlan.valid)
+			return -EOPNOTSUPP;
+
+		fid = vlan.fid;
+	}
 
 	entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
 	ether_addr_copy(entry.mac, addr);
 	eth_addr_dec(entry.mac);
 
-	err = mv88e6xxx_g1_atu_getnext(chip, vlan.fid, &entry);
+	err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
 	if (err)
 		return err;
 
@@ -1577,7 +1590,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
 		entry.state = state;
 	}
 
-	return mv88e6xxx_g1_atu_loadpurge(chip, vlan.fid, &entry);
+	return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
 }
 
 static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
-- 
2.22.0


^ permalink raw reply related

* [PATCH net-next 4/5] net: dsa: mv88e6xxx: call vtu_getnext directly in vlan_del
From: Vivien Didelot @ 2019-08-01 18:36 UTC (permalink / raw)
  Cc: linux-kernel, Vivien Didelot, Rasmus Villemoes, f.fainelli,
	andrew, netdev, davem
In-Reply-To: <20190801183637.24841-1-vivien.didelot@gmail.com>

Wrapping mv88e6xxx_vtu_getnext makes the code less easy to read.
Explicit the call to mv88e6xxx_vtu_getnext in _mv88e6xxx_port_vlan_del
and the return value expected by switchdev in case of software VLANs.

At the same time, rename the helper using an old underscore convention.

Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 42ab57dbc790..50a6dbcc669c 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1671,18 +1671,27 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
 	mv88e6xxx_reg_unlock(chip);
 }
 
-static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
-				    int port, u16 vid)
+static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
+				     int port, u16 vid)
 {
 	struct mv88e6xxx_vtu_entry vlan;
 	int i, err;
 
-	err = mv88e6xxx_vtu_get(chip, vid, &vlan, false);
+	if (!vid)
+		return -EOPNOTSUPP;
+
+	vlan.vid = vid - 1;
+	vlan.valid = false;
+
+	err = mv88e6xxx_vtu_getnext(chip, &vlan);
 	if (err)
 		return err;
 
-	/* Tell switchdev if this VLAN is handled in software */
-	if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+	/* If the VLAN doesn't exist in hardware or the port isn't a member,
+	 * tell switchdev that this VLAN is likely handled in software.
+	 */
+	if (vlan.vid != vid || !vlan.valid ||
+	    vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER)
 		return -EOPNOTSUPP;
 
 	vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER;
@@ -1721,7 +1730,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
 		goto unlock;
 
 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
-		err = _mv88e6xxx_port_vlan_del(chip, port, vid);
+		err = mv88e6xxx_port_vlan_leave(chip, port, vid);
 		if (err)
 			goto unlock;
 
-- 
2.22.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox