Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 6/6] net: ethernet: ti: cpsw: add macvlan and ucast/vlan filtering support
From: Ivan Khoronzhuk @ 2019-02-26 18:45 UTC (permalink / raw)
  To: davem, grygorii.strashko, f.fainelli
  Cc: linux-omap, netdev, linux-kernel, jiri, ilias.apalodimas,
	Ivan Khoronzhuk
In-Reply-To: <20190226184556.16082-1-ivan.khoronzhuk@linaro.org>

The cpsw supports unicast filtering as for real as for vlan devices
now, but has no flag set for that. As result, once macvlan or vlan
adds new ucast address the cpsw is silently toggled to promiscuous
mode. That's smth not expected, so patch fixes it.

A unicast address for vlan has to be presented by vlan/unicast entry
in ALE table. At this moment, while vlan address change, entry is not
created in any form, even just like real device unicast used for
macvlan, leaving only address inherited from real device created
while vlan addition.

Therefore, program unicast entries for vlans by using IVDF, it allows
to add only vlan/unicast entries for vlans, omitting real device
ucast entries unless they are added for macvans or so, as they are
redundant for vlans and just consume forwarding table and in case of
matching packet income - CPU time.

So, after this patch, cpsw has ability to handle macvlan and vlan
ucasts, synchronizing ucast tables for these devices with cpsw ALE
table exclusively.

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 drivers/net/ethernet/ti/cpsw.c | 62 ++++++++++++++++++++++++++++++----
 1 file changed, 56 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index fd76d1f12911..c6d5ddc05299 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -693,6 +693,31 @@ static int cpsw_set_mc(struct net_device *ndev, const u8 *addr,
 	return ret;
 }
 
+static int cpsw_set_uc(struct net_device *ndev, const u8 *addr,
+		       int vid, int add)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+	struct cpsw_common *cpsw = priv->cpsw;
+	int flags, port, ret;
+
+	if (vid < 0) {
+		if (cpsw->data.dual_emac)
+			vid = cpsw->slaves[priv->emac_port].port_vlan;
+		else
+			vid = 0;
+	}
+
+	port = HOST_PORT_NUM;
+	flags = vid ? ALE_VLAN : 0;
+
+	if (add)
+		ret = cpsw_ale_add_ucast(cpsw->ale, addr, port, flags, vid);
+	else
+		ret = cpsw_ale_del_ucast(cpsw->ale, addr, port, flags, vid);
+
+	return ret;
+}
+
 static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr)
 {
 	u16 vid;
@@ -711,6 +736,24 @@ static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr)
 	return 0;
 }
 
+static int cpsw_add_uc_addr(struct net_device *ndev, const u8 *addr)
+{
+	u16 vid;
+
+	vid = vlan_dev_get_addr_vid(ndev, addr);
+	cpsw_set_uc(ndev, addr, vid ? vid : -1, 1);
+	return 0;
+}
+
+static int cpsw_del_uc_addr(struct net_device *ndev, const u8 *addr)
+{
+	u16 vid;
+
+	vid = vlan_dev_get_addr_vid(ndev, addr);
+	cpsw_set_uc(ndev, addr, vid ? vid : -1, 0);
+	return 0;
+}
+
 static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 {
 	struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
@@ -730,6 +773,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 
 	/* add/remove mcast address either for real netdev or for vlan */
 	__dev_mc_sync(ndev, cpsw_add_mc_addr, cpsw_del_mc_addr);
+	__dev_uc_sync(ndev, cpsw_add_uc_addr, cpsw_del_uc_addr);
 }
 
 static void cpsw_intr_enable(struct cpsw_common *cpsw)
@@ -2009,6 +2053,7 @@ static int cpsw_ndo_stop(struct net_device *ndev)
 
 	cpsw_info(priv, ifdown, "shutting down cpsw device\n");
 	__dev_mc_unsync(ndev, cpsw_del_mc_addr);
+	__dev_uc_unsync(ndev, cpsw_del_uc_addr);
 	netif_tx_stop_all_queues(priv->ndev);
 	netif_carrier_off(priv->ndev);
 
@@ -2369,10 +2414,12 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
 	if (ret != 0)
 		return ret;
 
-	ret = cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr,
-				 HOST_PORT_NUM, ALE_VLAN, vid);
-	if (ret != 0)
-		goto clean_vid;
+	if (!priv->ndev->vid_len) {
+		ret = cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr,
+					 HOST_PORT_NUM, ALE_VLAN, vid);
+		if (ret != 0)
+			goto clean_vid;
+	}
 
 	ret = cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast,
 				 mcast_mask, ALE_VLAN, vid, 0);
@@ -2381,8 +2428,9 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
 	return 0;
 
 clean_vlan_ucast:
-	cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr,
-			   HOST_PORT_NUM, ALE_VLAN, vid);
+	if (!priv->ndev->vid_len)
+		cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr,
+				   HOST_PORT_NUM, ALE_VLAN, vid);
 clean_vid:
 	cpsw_ale_del_vlan(cpsw->ale, vid, 0);
 	return ret;
@@ -3344,6 +3392,7 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv)
 	priv_sl2->emac_port = 1;
 	cpsw->slaves[1].ndev = ndev;
 	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX;
+	ndev->priv_flags |= IFF_UNICAST_FLT;
 	vlan_dev_ivdf_set(ndev, 1);
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
@@ -3606,6 +3655,7 @@ static int cpsw_probe(struct platform_device *pdev)
 	}
 
 	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX;
+	ndev->priv_flags |= IFF_UNICAST_FLT;
 	vlan_dev_ivdf_set(ndev, 1);
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
-- 
2.17.1


^ permalink raw reply related

* [PATCH net-next 5/6] net: ethernet: ti: cpsw: update mc filtering to use IVDF
From: Ivan Khoronzhuk @ 2019-02-26 18:45 UTC (permalink / raw)
  To: davem, grygorii.strashko, f.fainelli
  Cc: linux-omap, netdev, linux-kernel, jiri, ilias.apalodimas,
	Ivan Khoronzhuk
In-Reply-To: <20190226184556.16082-1-ivan.khoronzhuk@linaro.org>

The cpsw can filter multicast addresses only per vlan. Thus if mcast
address is set for one of them or only for real device it must be
added for every created vlan consuming ALE table w/o reason. In order to
simplify dispatching vlan filters, the IVDF recently added is resused.

In case IVDF is disabled - mc is updated only for real device as before.
The previous method is harder to reuse and vlan filtering is limited
only for vlans directly connected to real netdev, so drop it in flavor
of IVDF decision.

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 drivers/net/ethernet/ti/Kconfig |   1 +
 drivers/net/ethernet/ti/cpsw.c  | 113 ++++----------------------------
 2 files changed, 13 insertions(+), 101 deletions(-)

diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index bb126be1eb72..c99c08ece9a1 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -65,6 +65,7 @@ config TI_CPSW
 	select TI_DAVINCI_CPDMA
 	select TI_DAVINCI_MDIO
 	select TI_CPSW_PHY_SEL
+	select VLAN_8021Q_IVDF
 	select TI_CPSW_ALE
 	select MFD_SYSCON
 	select REGMAP
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a591583d120e..fd76d1f12911 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -693,108 +693,21 @@ static int cpsw_set_mc(struct net_device *ndev, const u8 *addr,
 	return ret;
 }
 
-static int cpsw_update_vlan_mc(struct net_device *vdev, int vid, void *ctx)
+static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr)
 {
-	struct addr_sync_ctx *sync_ctx = ctx;
-	struct netdev_hw_addr *ha;
-	int found = 0, ret = 0;
-
-	if (!vdev || !(vdev->flags & IFF_UP))
-		return 0;
-
-	/* vlan address is relevant if its sync_cnt != 0 */
-	netdev_for_each_mc_addr(ha, vdev) {
-		if (ether_addr_equal(ha->addr, sync_ctx->addr)) {
-			found = ha->sync_cnt;
-			break;
-		}
-	}
-
-	if (found)
-		sync_ctx->consumed++;
-
-	if (sync_ctx->flush) {
-		if (!found)
-			cpsw_set_mc(sync_ctx->ndev, sync_ctx->addr, vid, 0);
-		return 0;
-	}
-
-	if (found)
-		ret = cpsw_set_mc(sync_ctx->ndev, sync_ctx->addr, vid, 1);
-
-	return ret;
-}
-
-static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr, int num)
-{
-	struct addr_sync_ctx sync_ctx;
-	int ret;
-
-	sync_ctx.consumed = 0;
-	sync_ctx.addr = addr;
-	sync_ctx.ndev = ndev;
-	sync_ctx.flush = 0;
-
-	ret = vlan_for_each(ndev, cpsw_update_vlan_mc, &sync_ctx);
-	if (sync_ctx.consumed < num && !ret)
-		ret = cpsw_set_mc(ndev, addr, -1, 1);
-
-	return ret;
-}
-
-static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr, int num)
-{
-	struct addr_sync_ctx sync_ctx;
-
-	sync_ctx.consumed = 0;
-	sync_ctx.addr = addr;
-	sync_ctx.ndev = ndev;
-	sync_ctx.flush = 1;
-
-	vlan_for_each(ndev, cpsw_update_vlan_mc, &sync_ctx);
-	if (sync_ctx.consumed == num)
-		cpsw_set_mc(ndev, addr, -1, 0);
+	u16 vid;
 
+	vid = vlan_dev_get_addr_vid(ndev, addr);
+	cpsw_set_mc(ndev, addr, vid ? vid : -1, 1);
 	return 0;
 }
 
-static int cpsw_purge_vlan_mc(struct net_device *vdev, int vid, void *ctx)
+static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr)
 {
-	struct addr_sync_ctx *sync_ctx = ctx;
-	struct netdev_hw_addr *ha;
-	int found = 0;
-
-	if (!vdev || !(vdev->flags & IFF_UP))
-		return 0;
-
-	/* vlan address is relevant if its sync_cnt != 0 */
-	netdev_for_each_mc_addr(ha, vdev) {
-		if (ether_addr_equal(ha->addr, sync_ctx->addr)) {
-			found = ha->sync_cnt;
-			break;
-		}
-	}
-
-	if (!found)
-		return 0;
-
-	sync_ctx->consumed++;
-	cpsw_set_mc(sync_ctx->ndev, sync_ctx->addr, vid, 0);
-	return 0;
-}
-
-static int cpsw_purge_all_mc(struct net_device *ndev, const u8 *addr, int num)
-{
-	struct addr_sync_ctx sync_ctx;
-
-	sync_ctx.addr = addr;
-	sync_ctx.ndev = ndev;
-	sync_ctx.consumed = 0;
-
-	vlan_for_each(ndev, cpsw_purge_vlan_mc, &sync_ctx);
-	if (sync_ctx.consumed < num)
-		cpsw_set_mc(ndev, addr, -1, 0);
+	u16 vid;
 
+	vid = vlan_dev_get_addr_vid(ndev, addr);
+	cpsw_set_mc(ndev, addr, vid ? vid : -1, 0);
 	return 0;
 }
 
@@ -816,8 +729,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 	cpsw_ale_set_allmulti(cpsw->ale, ndev->flags & IFF_ALLMULTI);
 
 	/* add/remove mcast address either for real netdev or for vlan */
-	__hw_addr_ref_sync_dev(&ndev->mc, ndev, cpsw_add_mc_addr,
-			       cpsw_del_mc_addr);
+	__dev_mc_sync(ndev, cpsw_add_mc_addr, cpsw_del_mc_addr);
 }
 
 static void cpsw_intr_enable(struct cpsw_common *cpsw)
@@ -1970,9 +1882,6 @@ static int cpsw_restore_vlans(struct net_device *vdev, int vid, void *arg)
 {
 	struct cpsw_priv *priv = arg;
 
-	if (!vdev)
-		return 0;
-
 	cpsw_ndo_vlan_rx_add_vid(priv->ndev, 0, vid);
 	return 0;
 }
@@ -2099,7 +2008,7 @@ static int cpsw_ndo_stop(struct net_device *ndev)
 	struct cpsw_common *cpsw = priv->cpsw;
 
 	cpsw_info(priv, ifdown, "shutting down cpsw device\n");
-	__hw_addr_ref_unsync_dev(&ndev->mc, ndev, cpsw_purge_all_mc);
+	__dev_mc_unsync(ndev, cpsw_del_mc_addr);
 	netif_tx_stop_all_queues(priv->ndev);
 	netif_carrier_off(priv->ndev);
 
@@ -3435,6 +3344,7 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv)
 	priv_sl2->emac_port = 1;
 	cpsw->slaves[1].ndev = ndev;
 	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX;
+	vlan_dev_ivdf_set(ndev, 1);
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
 	ndev->ethtool_ops = &cpsw_ethtool_ops;
@@ -3696,6 +3606,7 @@ static int cpsw_probe(struct platform_device *pdev)
 	}
 
 	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX;
+	vlan_dev_ivdf_set(ndev, 1);
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
 	ndev->ethtool_ops = &cpsw_ethtool_ops;
-- 
2.17.1


^ permalink raw reply related

* [PATCH net-next 4/6] ethernet: eth: add default vid len for all ehternet kind devices
From: Ivan Khoronzhuk @ 2019-02-26 18:45 UTC (permalink / raw)
  To: davem, grygorii.strashko, f.fainelli
  Cc: linux-omap, netdev, linux-kernel, jiri, ilias.apalodimas,
	Ivan Khoronzhuk
In-Reply-To: <20190226184556.16082-1-ivan.khoronzhuk@linaro.org>

IVDF - individual virtual device filtering. Allows to set per vlan
l2 address filters on end real network device (for unicast and for
multicast) and drop redundant not expected packet income.

If CONFIG_VLAN_8021Q_IVDF is enabled the following changes are
applied, and only for ethernet network devices.

By default every ethernet netdev needs vid len = 2 bytes to be able to
hold up to 4096 vids. So set it for every eth device to be correct,
except vlan devs.

In order to shrink all addresses of devices above vlan, the vid_len
for vlan dev = 0, as result all suckers sync their addresses to common
base not taking in to account vid part (vid_len of "to" devices is
important only). And only vlan device is the source of addresses with
actual its vid set, propagating it to parent devices while rx_mode().

Also, don't bother those ethernet devices that at this moment are not
moved to vlan addressing scheme, so while end ethernet device is
created - set vid_len to 0, thus, while syncing, its address space is
concatenated to one dimensional like usual, and who needs IVDF - set
it to NET_8021Q_VID_TSIZE.

There is another decision - is to inherit vid_len or some feature flag
from end root device in order to all upper devices have vlan extended
address space only if exact end real device have such capability. But
I didn't, because it requires more changes and probably I'm not
familiar with all places where it should be inherited, I would
appreciate if someone can guid where it's applicable, then it could
become a little bit more limited.

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 include/linux/if_vlan.h |  1 +
 net/8021q/Kconfig       | 12 ++++++++++++
 net/8021q/vlan_core.c   | 12 ++++++++++++
 net/8021q/vlan_dev.c    |  1 +
 net/ethernet/eth.c      | 10 ++++++++--
 5 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 94657f3c483a..9c914b31d208 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -137,6 +137,7 @@ extern int vlan_for_each(struct net_device *dev,
 			 int (*action)(struct net_device *dev, int vid,
 				       void *arg), void *arg);
 extern u16 vlan_dev_get_addr_vid(struct net_device *dev, const u8 *addr);
+extern void vlan_dev_ivdf_set(struct net_device *dev, int enable);
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
 extern u16 vlan_dev_vlan_id(const struct net_device *dev);
 extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
index 42320180967f..3e843045739c 100644
--- a/net/8021q/Kconfig
+++ b/net/8021q/Kconfig
@@ -38,3 +38,15 @@ config VLAN_8021Q_MVRP
 	  supersedes GVRP and is not backwards-compatible.
 
 	  If unsure, say N.
+
+config VLAN_8021Q_IVDF
+	bool "IVDF (Individual Virtual Device Filtering) support"
+	depends on VLAN_8021Q
+	help
+	  Select this to enable IVDF addressing scheme support. IVDF is used
+	  for automatic propagation of registered VLANs addresses to real end
+	  devices. If no device supporting IVDF then disable this as it can
+	  consume some memory in configuration with complex network device
+	  structures to hold vlan addresses.
+
+	  If unsure, say N.
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index fe2ac64c13f8..310b6cd39f22 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -454,6 +454,18 @@ bool vlan_uses_dev(const struct net_device *dev)
 }
 EXPORT_SYMBOL(vlan_uses_dev);
 
+void vlan_dev_ivdf_set(struct net_device *dev, int enable)
+{
+#ifdef CONFIG_VLAN_8021Q_IVDF
+	if (enable) {
+		dev->vid_len = NET_8021Q_VID_TSIZE;
+		return;
+	}
+#endif
+	dev->vid_len = 0;
+}
+EXPORT_SYMBOL(vlan_dev_ivdf_set);
+
 u16 vlan_dev_get_addr_vid(struct net_device *dev, const u8 *addr)
 {
 	u16 vid = 0;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 634436e780f1..e4120aca4b9b 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -896,5 +896,6 @@ void vlan_setup(struct net_device *dev)
 	dev->min_mtu		= 0;
 	dev->max_mtu		= ETH_MAX_MTU;
 
+	vlan_dev_ivdf_set(dev, 0);
 	eth_zero_addr(dev->broadcast);
 }
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index f7a3d7a171c7..95497cac24eb 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -381,6 +381,7 @@ void ether_setup(struct net_device *dev)
 	dev->flags		= IFF_BROADCAST|IFF_MULTICAST;
 	dev->priv_flags		|= IFF_TX_SKB_SHARING;
 
+	vlan_dev_ivdf_set(dev, 1);
 	eth_broadcast_addr(dev->broadcast);
 
 }
@@ -404,8 +405,13 @@ EXPORT_SYMBOL(ether_setup);
 struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
 				      unsigned int rxqs)
 {
-	return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN,
-				ether_setup, txqs, rxqs);
+	struct net_device *dev;
+
+	dev = alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN,
+			       ether_setup, txqs, rxqs);
+
+	vlan_dev_ivdf_set(dev, 0);
+	return dev;
 }
 EXPORT_SYMBOL(alloc_etherdev_mqs);
 
-- 
2.17.1


^ permalink raw reply related

* [PATCH net-next 3/6] net: 8021q: vlan_dev: add vid tag for vlan device own address
From: Ivan Khoronzhuk @ 2019-02-26 18:45 UTC (permalink / raw)
  To: davem, grygorii.strashko, f.fainelli
  Cc: linux-omap, netdev, linux-kernel, jiri, ilias.apalodimas,
	Ivan Khoronzhuk
In-Reply-To: <20190226184556.16082-1-ivan.khoronzhuk@linaro.org>

The vlan device address is held separately from uc/mc lists and
handled differently. The vlan dev address is bound with real device
address only if it's inherited from init, in all other cases it's
separate address entry in uc list. With vid set, the address becomes
not inherited from real device after it's set manually as before, but
is part of uc list any way, with appropriate vid tag set. If vid_len
for real device is 0, the behaviour is the same as before this change,
so shouldn't be any impact on systems w/o individual virtual device
filtering (IVDF) enabled. This allows to control and sync vlan device
address and disable concrete vlan packet income when vlan interface is
down.

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 net/8021q/vlan.c     |  3 ++
 net/8021q/vlan_dev.c | 76 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index dc4411165e43..9c72551a9a1e 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -295,6 +295,9 @@ static void vlan_sync_address(struct net_device *dev,
 	if (vlan_dev_inherit_address(vlandev, dev))
 		goto out;
 
+	if (dev->vid_len)
+		goto out;
+
 	/* vlan address was different from the old address and is equal to
 	 * the new address */
 	if (!ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) &&
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 93d20b1f4916..634436e780f1 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -257,12 +257,61 @@ static void vlan_dev_set_addr_vid(struct net_device *vlan_dev, u8 *addr)
 	addr[vlan_dev->addr_len + 1] = (vid >> 8) & 0xf;
 }
 
+static int vlan_dev_add_addr(struct net_device *dev, u8 *addr)
+{
+	struct net_device *real_dev = vlan_dev_real_dev(dev);
+	unsigned char naddr[ETH_ALEN + NET_8021Q_VID_TSIZE];
+
+	if (real_dev->vid_len) {
+		memcpy(naddr, addr, dev->addr_len);
+		vlan_dev_set_addr_vid(dev, naddr);
+		return dev_vid_uc_add(real_dev, naddr);
+	}
+
+	if (ether_addr_equal(addr, real_dev->dev_addr))
+		return 0;
+
+	return dev_uc_add(real_dev, addr);
+}
+
+static void vlan_dev_del_addr(struct net_device *dev, u8 *addr)
+{
+	struct net_device *real_dev = vlan_dev_real_dev(dev);
+	unsigned char naddr[ETH_ALEN + NET_8021Q_VID_TSIZE];
+
+	if (real_dev->vid_len) {
+		memcpy(naddr, addr, dev->addr_len);
+		vlan_dev_set_addr_vid(dev, naddr);
+		dev_vid_uc_del(real_dev, naddr);
+		return;
+	}
+
+	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
+		dev_uc_del(real_dev, addr);
+}
+
+static int vlan_dev_subs_addr(struct net_device *dev, u8 *addr)
+{
+	int err;
+
+	err = vlan_dev_add_addr(dev, addr);
+	if (err < 0)
+		return err;
+
+	vlan_dev_del_addr(dev, dev->dev_addr);
+	return err;
+}
+
 bool vlan_dev_inherit_address(struct net_device *dev,
 			      struct net_device *real_dev)
 {
 	if (dev->addr_assign_type != NET_ADDR_STOLEN)
 		return false;
 
+	if (real_dev->vid_len)
+		if (vlan_dev_subs_addr(dev, real_dev->dev_addr))
+			return false;
+
 	ether_addr_copy(dev->dev_addr, real_dev->dev_addr);
 	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
 	return true;
@@ -278,9 +327,10 @@ static int vlan_dev_open(struct net_device *dev)
 	    !(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
 		return -ENETDOWN;
 
-	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) &&
-	    !vlan_dev_inherit_address(dev, real_dev)) {
-		err = dev_uc_add(real_dev, dev->dev_addr);
+	if (ether_addr_equal(dev->dev_addr, real_dev->dev_addr) ||
+	    (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) &&
+	     !vlan_dev_inherit_address(dev, real_dev))) {
+		err = vlan_dev_add_addr(dev, dev->dev_addr);
 		if (err < 0)
 			goto out;
 	}
@@ -312,8 +362,7 @@ static int vlan_dev_open(struct net_device *dev)
 	if (dev->flags & IFF_ALLMULTI)
 		dev_set_allmulti(real_dev, -1);
 del_unicast:
-	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
-		dev_uc_del(real_dev, dev->dev_addr);
+	vlan_dev_del_addr(dev, dev->dev_addr);
 out:
 	netif_carrier_off(dev);
 	return err;
@@ -331,18 +380,14 @@ static int vlan_dev_stop(struct net_device *dev)
 	if (dev->flags & IFF_PROMISC)
 		dev_set_promiscuity(real_dev, -1);
 
-	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
-		dev_uc_del(real_dev, dev->dev_addr);
-
+	vlan_dev_del_addr(dev, dev->dev_addr);
 	netif_carrier_off(dev);
 	return 0;
 }
 
 static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
 {
-	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
 	struct sockaddr *addr = p;
-	int err;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
@@ -350,15 +395,8 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
 	if (!(dev->flags & IFF_UP))
 		goto out;
 
-	if (!ether_addr_equal(addr->sa_data, real_dev->dev_addr)) {
-		err = dev_uc_add(real_dev, addr->sa_data);
-		if (err < 0)
-			return err;
-	}
-
-	if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr))
-		dev_uc_del(real_dev, dev->dev_addr);
-
+	if (vlan_dev_subs_addr(dev, addr->sa_data))
+		return true;
 out:
 	ether_addr_copy(dev->dev_addr, addr->sa_data);
 	return 0;
-- 
2.17.1


^ permalink raw reply related

* [PATCH net-next 2/6] net: 8021q: vlan_dev: add vid tag to addresses of uc and mc lists
From: Ivan Khoronzhuk @ 2019-02-26 18:45 UTC (permalink / raw)
  To: davem, grygorii.strashko, f.fainelli
  Cc: linux-omap, netdev, linux-kernel, jiri, ilias.apalodimas,
	Ivan Khoronzhuk
In-Reply-To: <20190226184556.16082-1-ivan.khoronzhuk@linaro.org>

Update vlan mc and uc addresses with VID tag while propagating
addresses to lower devices, do this only if address is not synced.
It allows at end driver level to distinguish addresses belonging
to vlan devices.

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 include/linux/if_vlan.h |  1 +
 net/8021q/vlan.h        |  2 ++
 net/8021q/vlan_core.c   | 13 +++++++++++++
 net/8021q/vlan_dev.c    | 26 ++++++++++++++++++++++++++
 4 files changed, 42 insertions(+)

diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 4cca4da7a6de..94657f3c483a 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -136,6 +136,7 @@ extern struct net_device *__vlan_find_dev_deep_rcu(struct net_device *real_dev,
 extern int vlan_for_each(struct net_device *dev,
 			 int (*action)(struct net_device *dev, int vid,
 				       void *arg), void *arg);
+extern u16 vlan_dev_get_addr_vid(struct net_device *dev, const u8 *addr);
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
 extern u16 vlan_dev_vlan_id(const struct net_device *dev);
 extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index c46daf09a501..f083c43c508f 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -6,6 +6,8 @@
 #include <linux/u64_stats_sync.h>
 #include <linux/list.h>
 
+#define NET_8021Q_VID_TSIZE	2
+
 /* if this changes, algorithm will have to be reworked because this
  * depends on completely exhausting the VLAN identifier space.  Thus
  * it gives constant time look-up, but in many cases it wastes memory.
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index a313165e7a67..fe2ac64c13f8 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -454,6 +454,19 @@ bool vlan_uses_dev(const struct net_device *dev)
 }
 EXPORT_SYMBOL(vlan_uses_dev);
 
+u16 vlan_dev_get_addr_vid(struct net_device *dev, const u8 *addr)
+{
+	u16 vid = 0;
+
+	if (dev->vid_len != NET_8021Q_VID_TSIZE)
+		return vid;
+
+	vid = addr[dev->addr_len];
+	vid |= (addr[dev->addr_len + 1] & 0xf) << 8;
+	return vid;
+}
+EXPORT_SYMBOL(vlan_dev_get_addr_vid);
+
 static struct sk_buff *vlan_gro_receive(struct list_head *head,
 					struct sk_buff *skb)
 {
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 15293c2a5dd8..93d20b1f4916 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -249,6 +249,14 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result)
 	strncpy(result, vlan_dev_priv(dev)->real_dev->name, 23);
 }
 
+static void vlan_dev_set_addr_vid(struct net_device *vlan_dev, u8 *addr)
+{
+	u16 vid = vlan_dev_vlan_id(vlan_dev);
+
+	addr[vlan_dev->addr_len] = vid & 0xff;
+	addr[vlan_dev->addr_len + 1] = (vid >> 8) & 0xf;
+}
+
 bool vlan_dev_inherit_address(struct net_device *dev,
 			      struct net_device *real_dev)
 {
@@ -480,8 +488,26 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
 	}
 }
 
+static void vlan_dev_align_addr_vid(struct net_device *vlan_dev)
+{
+	struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
+	struct netdev_hw_addr *ha;
+
+	if (!real_dev->vid_len)
+		return;
+
+	netdev_for_each_mc_addr(ha, vlan_dev)
+		if (!ha->sync_cnt)
+			vlan_dev_set_addr_vid(vlan_dev, ha->addr);
+
+	netdev_for_each_uc_addr(ha, vlan_dev)
+		if (!ha->sync_cnt)
+			vlan_dev_set_addr_vid(vlan_dev, ha->addr);
+}
+
 static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
 {
+	vlan_dev_align_addr_vid(vlan_dev);
 	dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
 	dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
 }
-- 
2.17.1


^ permalink raw reply related

* [PATCH net-next 1/6] net: core: dev_addr_lists: add VID to device address
From: Ivan Khoronzhuk @ 2019-02-26 18:45 UTC (permalink / raw)
  To: davem, grygorii.strashko, f.fainelli
  Cc: linux-omap, netdev, linux-kernel, jiri, ilias.apalodimas,
	Ivan Khoronzhuk
In-Reply-To: <20190226184556.16082-1-ivan.khoronzhuk@linaro.org>

Despite this is supposed to be used for Ethernet VLANs, not Ethernet
addresses with space for VID also can reuse this, so VID is considered
as virtual ID extension, not belonging strictly to Ethernet VLAN VIDs,
and overall change can be named individual virtual device filtering
(IVDF).

This patch adds VID tag at the end of each address. The actual
reserved address size is 32 bytes. For Ethernet addresses with 6 bytes
long that's possible to add tag w/o increasing address size. Thus,
each address for the case has 32 - 6 = 26 bytes to hold additional
info, say VID for virtual device addresses.

Therefore, when addresses are synced to the address list of parent
device the address list of latter can contain separate addresses for
virtual devices. It allows to track separate address tables for
virtual devices if they present and the device can be placed on
any place of device tree as the address is propagated to to the end
real device thru *_sync()/ndo_set_rx_mode() APIs. Also it simplifies
handling VID addresses at real device when it supports IVDF.

If parent device doesn't want to have virtual addresses in its address
space the vid_len has to be 0, thus its address space is "shrunk" to
the state as before this patch. For now it's 0 for every device. It
allows two devices with and w/o IVDF to be part of same bond device
for instance.

The end real device supporting IVDF can retrieve VID tag from an
address and set it for a given virtual device only. By default, vid 0
is used for real devices to distinguish it from virtual addresses.

See next patches to see how it's used.

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 include/linux/netdevice.h |   4 ++
 net/core/dev_addr_lists.c | 124 +++++++++++++++++++++++++++++++-------
 2 files changed, 105 insertions(+), 23 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 58e83bd7a861..74fef35b6bec 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1660,6 +1660,7 @@ enum netdev_priv_flags {
  * 	@perm_addr:		Permanent hw address
  * 	@addr_assign_type:	Hw address assignment type
  * 	@addr_len:		Hardware address length
+ *	@vid_len:		Virtual ID length, set in case of IVDF
  *	@neigh_priv_len:	Used in neigh_alloc()
  * 	@dev_id:		Used to differentiate devices that share
  * 				the same link layer address
@@ -1889,6 +1890,7 @@ struct net_device {
 	unsigned char		perm_addr[MAX_ADDR_LEN];
 	unsigned char		addr_assign_type;
 	unsigned char		addr_len;
+	unsigned char		vid_len;
 	unsigned short		neigh_priv_len;
 	unsigned short          dev_id;
 	unsigned short          dev_port;
@@ -4141,8 +4143,10 @@ int dev_addr_init(struct net_device *dev);
 
 /* Functions used for unicast addresses handling */
 int dev_uc_add(struct net_device *dev, const unsigned char *addr);
+int dev_vid_uc_add(struct net_device *dev, const unsigned char *addr);
 int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr);
 int dev_uc_del(struct net_device *dev, const unsigned char *addr);
+int dev_vid_uc_del(struct net_device *dev, const unsigned char *addr);
 int dev_uc_sync(struct net_device *to, struct net_device *from);
 int dev_uc_sync_multiple(struct net_device *to, struct net_device *from);
 void dev_uc_unsync(struct net_device *to, struct net_device *from);
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index a6723b306717..e3c80e044b8c 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -545,6 +545,26 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr,
 }
 EXPORT_SYMBOL(dev_addr_del);
 
+static int get_addr_len(struct net_device *dev)
+{
+	return dev->addr_len + dev->vid_len;
+}
+
+static int set_vid_addr(struct net_device *dev, const unsigned char *addr,
+			unsigned char *naddr)
+{
+	int i;
+
+	if (!dev->vid_len)
+		return dev->addr_len;
+
+	memcpy(naddr, addr, dev->addr_len);
+	for (i = 0; i < dev->vid_len; i++)
+		naddr[dev->addr_len + i] = 0;
+
+	return get_addr_len(dev);
+}
+
 /*
  * Unicast list handling functions
  */
@@ -556,18 +576,22 @@ EXPORT_SYMBOL(dev_addr_del);
  */
 int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)
 {
+	unsigned char naddr[MAX_ADDR_LEN];
 	struct netdev_hw_addr *ha;
-	int err;
+	int addr_len, err;
+
+	addr_len = set_vid_addr(dev, addr, naddr);
+	addr = dev->vid_len ? naddr : addr;
 
 	netif_addr_lock_bh(dev);
 	list_for_each_entry(ha, &dev->uc.list, list) {
-		if (!memcmp(ha->addr, addr, dev->addr_len) &&
+		if (!memcmp(ha->addr, addr, addr_len) &&
 		    ha->type == NETDEV_HW_ADDR_T_UNICAST) {
 			err = -EEXIST;
 			goto out;
 		}
 	}
-	err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len,
+	err = __hw_addr_create_ex(&dev->uc, addr, addr_len,
 				  NETDEV_HW_ADDR_T_UNICAST, true, false);
 	if (!err)
 		__dev_set_rx_mode(dev);
@@ -578,47 +602,89 @@ int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)
 EXPORT_SYMBOL(dev_uc_add_excl);
 
 /**
- *	dev_uc_add - Add a secondary unicast address
+ *	dev_vid_uc_add - Add a secondary unicast address with tag
  *	@dev: device
- *	@addr: address to add
+ *	@addr: address to add, includes vid tag already
  *
  *	Add a secondary unicast address to the device or increase
  *	the reference count if it already exists.
  */
-int dev_uc_add(struct net_device *dev, const unsigned char *addr)
+int dev_vid_uc_add(struct net_device *dev, const unsigned char *addr)
 {
 	int err;
 
 	netif_addr_lock_bh(dev);
-	err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
+	err = __hw_addr_add(&dev->uc, addr, get_addr_len(dev),
 			    NETDEV_HW_ADDR_T_UNICAST);
 	if (!err)
 		__dev_set_rx_mode(dev);
 	netif_addr_unlock_bh(dev);
 	return err;
 }
+EXPORT_SYMBOL(dev_vid_uc_add);
+
+/**
+ *	dev_uc_add - Add a secondary unicast address
+ *	@dev: device
+ *	@addr: address to add
+ *
+ *	Add a secondary unicast address to the device or increase
+ *	the reference count if it already exists.
+ */
+int dev_uc_add(struct net_device *dev, const unsigned char *addr)
+{
+	unsigned char naddr[MAX_ADDR_LEN];
+	int err;
+
+	set_vid_addr(dev, addr, naddr);
+	addr = dev->vid_len ? naddr : addr;
+
+	err = dev_vid_uc_add(dev, addr);
+	return err;
+}
 EXPORT_SYMBOL(dev_uc_add);
 
 /**
  *	dev_uc_del - Release secondary unicast address.
  *	@dev: device
- *	@addr: address to delete
+ *	@addr: address to delete, includes vid tag already
  *
  *	Release reference to a secondary unicast address and remove it
  *	from the device if the reference count drops to zero.
  */
-int dev_uc_del(struct net_device *dev, const unsigned char *addr)
+int dev_vid_uc_del(struct net_device *dev, const unsigned char *addr)
 {
 	int err;
 
 	netif_addr_lock_bh(dev);
-	err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
+	err = __hw_addr_del(&dev->uc, addr, get_addr_len(dev),
 			    NETDEV_HW_ADDR_T_UNICAST);
 	if (!err)
 		__dev_set_rx_mode(dev);
 	netif_addr_unlock_bh(dev);
 	return err;
 }
+EXPORT_SYMBOL(dev_vid_uc_del);
+
+/**
+ *	dev_uc_del - Release secondary unicast address.
+ *	@dev: device
+ *	@addr: address to delete
+ *
+ *	Release reference to a secondary unicast address and remove it
+ *	from the device if the reference count drops to zero.
+ */
+int dev_uc_del(struct net_device *dev, const unsigned char *addr)
+{
+	unsigned char naddr[MAX_ADDR_LEN];
+	int err;
+
+	set_vid_addr(dev, addr, naddr);
+	addr = dev->vid_len ? naddr : addr;
+
+	err = dev_vid_uc_del(dev, addr);
+	return err;
+}
 EXPORT_SYMBOL(dev_uc_del);
 
 /**
@@ -642,7 +708,7 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)
 		return -EINVAL;
 
 	netif_addr_lock_nested(to);
-	err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
+	err = __hw_addr_sync(&to->uc, &from->uc, get_addr_len(to));
 	if (!err)
 		__dev_set_rx_mode(to);
 	netif_addr_unlock(to);
@@ -672,7 +738,7 @@ int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
 		return -EINVAL;
 
 	netif_addr_lock_nested(to);
-	err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
+	err = __hw_addr_sync_multiple(&to->uc, &from->uc, get_addr_len(to));
 	if (!err)
 		__dev_set_rx_mode(to);
 	netif_addr_unlock(to);
@@ -696,7 +762,7 @@ void dev_uc_unsync(struct net_device *to, struct net_device *from)
 
 	netif_addr_lock_bh(from);
 	netif_addr_lock_nested(to);
-	__hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
+	__hw_addr_unsync(&to->uc, &from->uc, get_addr_len(to));
 	__dev_set_rx_mode(to);
 	netif_addr_unlock(to);
 	netif_addr_unlock_bh(from);
@@ -740,18 +806,22 @@ EXPORT_SYMBOL(dev_uc_init);
  */
 int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr)
 {
+	unsigned char naddr[MAX_ADDR_LEN];
 	struct netdev_hw_addr *ha;
-	int err;
+	int addr_len, err;
+
+	addr_len = set_vid_addr(dev, addr, naddr);
+	addr = dev->vid_len ? naddr : addr;
 
 	netif_addr_lock_bh(dev);
 	list_for_each_entry(ha, &dev->mc.list, list) {
-		if (!memcmp(ha->addr, addr, dev->addr_len) &&
+		if (!memcmp(ha->addr, addr, addr_len) &&
 		    ha->type == NETDEV_HW_ADDR_T_MULTICAST) {
 			err = -EEXIST;
 			goto out;
 		}
 	}
-	err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len,
+	err = __hw_addr_create_ex(&dev->mc, addr, addr_len,
 				  NETDEV_HW_ADDR_T_MULTICAST, true, false);
 	if (!err)
 		__dev_set_rx_mode(dev);
@@ -764,10 +834,14 @@ EXPORT_SYMBOL(dev_mc_add_excl);
 static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
 			bool global)
 {
-	int err;
+	unsigned char naddr[MAX_ADDR_LEN];
+	int addr_len, err;
+
+	addr_len = set_vid_addr(dev, addr, naddr);
+	addr = dev->vid_len ? naddr : addr;
 
 	netif_addr_lock_bh(dev);
-	err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
+	err = __hw_addr_add_ex(&dev->mc, addr, addr_len,
 			       NETDEV_HW_ADDR_T_MULTICAST, global, false, 0);
 	if (!err)
 		__dev_set_rx_mode(dev);
@@ -804,10 +878,14 @@ EXPORT_SYMBOL(dev_mc_add_global);
 static int __dev_mc_del(struct net_device *dev, const unsigned char *addr,
 			bool global)
 {
-	int err;
+	unsigned char naddr[MAX_ADDR_LEN];
+	int addr_len, err;
+
+	addr_len = set_vid_addr(dev, addr, naddr);
+	addr = dev->vid_len ? naddr : addr;
 
 	netif_addr_lock_bh(dev);
-	err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len,
+	err = __hw_addr_del_ex(&dev->mc, addr, addr_len,
 			       NETDEV_HW_ADDR_T_MULTICAST, global, false);
 	if (!err)
 		__dev_set_rx_mode(dev);
@@ -863,7 +941,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
 		return -EINVAL;
 
 	netif_addr_lock_nested(to);
-	err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
+	err = __hw_addr_sync(&to->mc, &from->mc, get_addr_len(to));
 	if (!err)
 		__dev_set_rx_mode(to);
 	netif_addr_unlock(to);
@@ -893,7 +971,7 @@ int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)
 		return -EINVAL;
 
 	netif_addr_lock_nested(to);
-	err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len);
+	err = __hw_addr_sync_multiple(&to->mc, &from->mc, get_addr_len(to));
 	if (!err)
 		__dev_set_rx_mode(to);
 	netif_addr_unlock(to);
@@ -917,7 +995,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
 
 	netif_addr_lock_bh(from);
 	netif_addr_lock_nested(to);
-	__hw_addr_unsync(&to->mc, &from->mc, to->addr_len);
+	__hw_addr_unsync(&to->mc, &from->mc, get_addr_len(to));
 	__dev_set_rx_mode(to);
 	netif_addr_unlock(to);
 	netif_addr_unlock_bh(from);
-- 
2.17.1


^ permalink raw reply related

* Re: [RFC] nasty corner case in unix_dgram_sendmsg()
From: Al Viro @ 2019-02-26 19:03 UTC (permalink / raw)
  To: Rainer Weikusat; +Cc: Jason Baron, netdev
In-Reply-To: <878sy2k1m3.fsf@doppelsaurus.mobileactivedefense.com>

On Tue, Feb 26, 2019 at 03:31:32PM +0000, Rainer Weikusat wrote:
> Al Viro <viro@zeniv.linux.org.uk> writes:
> > On Tue, Feb 26, 2019 at 06:28:17AM +0000, Al Viro wrote:
> 
> [...]
> 
> 
> >> 	* if after relocking we see that unix_peer(sk) now
> >> is equal to other, we arrange for wakeup forwarding from other's
> >> peer_wait *and* if that has (likely) succeeded we fail with -EAGAIN.
> >> Huh?
> 
> This returns 1 if sending isn't possible at the moment, ie, if the
> process which tries to send has to wait.

Except that in _this_ case we won't be waiting at all - we'll just
return -EAGAIN (as one could expect, what with no timeout given/left).
So what's the point of forwarding wakeups?  IOW, what is it that we
expect to be waiting on sk_sleep(sk)?  Note that it won't be this
call of sendmsg(2) (it'll bugger off without any further waiting).
It won't be subsequent calls of sendmsg(2) either - they either
sleep on skb allocation (which has nothing to do with destination)
_or_ they sleep directly on other->peer_wait.  And poll(), while it
will be sleeping on sk_sleep(sk), will make sure to set the forwarding 
up.

I understand what the unix_dgram_peer_wake_me() is doing; I understand
what unix_dgram_poll() is using it for.  What I do not understand is
what's the point of doing that in unix_dgram_sendmsg()...

^ permalink raw reply

* Re: [PATCH 0/3] soc: fsl: dpio: enable and configure cache stashing
From: Li Yang @ 2019-02-26 19:03 UTC (permalink / raw)
  To: Ioana Ciornei
  Cc: David Miller, Roy Pledge, Ioana Ciocoi Radulescu, Laurentiu Tudor,
	Horia Geanta, brouer@redhat.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <VI1PR0402MB280056BBF62A86E1703C549BE07A0@VI1PR0402MB2800.eurprd04.prod.outlook.com>

On Mon, Feb 25, 2019 at 1:01 AM Ioana Ciornei <ioana.ciornei@nxp.com> wrote:
>
> > Subject: Re: [PATCH 0/3] soc: fsl: dpio: enable and configure cache stashing
> >
> > From: Ioana Ciornei <ioana.ciornei@nxp.com>
> > Date: Sat, 23 Feb 2019 08:48:42 +0000
> >
> > > The first two patches enable cache stashing and configure the core
> > > cluster destination per software portal while the third patch is the
> > > one configuring the amount of stashing on a queue.
> >
> > Should I merge this series in via my networking tree?
>
> Even though it would be really good to have this on the networking tree as soon as possible, I am afraid that patch 2/3 is not going to apply cleanly because it touches the same areas of code that some other patches on Leo's tree are.

Hi David,

What shall we do if we want to get this in the 5.1?  Since the change
on the ethernet driver is pretty small, can I get your ACK on that
patch and merge the series through my tree?  Otherwise I can also try
to get the dpio patches in next merge window, and you can apply the
Ethernet patch after that.

Regards,
Leo

^ permalink raw reply

* Re: [PATCH v2] iov_iter: optimize page_copy_sane()
From: Al Viro @ 2019-02-26 19:04 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David S . Miller, linux-kernel, netdev, Eric Dumazet
In-Reply-To: <20190226184239.49946-1-edumazet@google.com>

On Tue, Feb 26, 2019 at 10:42:39AM -0800, Eric Dumazet wrote:
> Avoid cache line miss dereferencing struct page if we can.
> 
> page_copy_sane() mostly deals with order-0 pages.
> 
> Extra cache line miss is visible on TCP recvmsg() calls dealing
> with GRO packets (typically 45 page frags are attached to one skb).
> 
> Bringing the 45 struct pages into cpu cache while copying the data
> is not free, since the freeing of the skb (and associated
> page frags put_page()) can happen after cache lines have been evicted.

Applied.

^ permalink raw reply

* [PATCH v1 net] lan743x: Fix TX Stall Issue
From: Bryan Whitehead @ 2019-02-26 19:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver

It has been observed that tx queue stalls while downloading
from certain web sites (example www.speedtest.net)

The cause has been tracked down to a corner case where
dma descriptors where not setup properly. And there for a tx
completion interrupt was not signaled.

This fix corrects the problem by properly marking the end of
a multi descriptor transmission.

fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver")
Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_main.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 310807e..4d1b4a2 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -1400,7 +1400,8 @@ static int lan743x_tx_frame_start(struct lan743x_tx *tx,
 }
 
 static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
-				     unsigned int frame_length)
+				     unsigned int frame_length,
+				     int nr_frags)
 {
 	/* called only from within lan743x_tx_xmit_frame.
 	 * assuming tx->ring_lock has already been acquired.
@@ -1410,6 +1411,10 @@ static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
 
 	/* wrap up previous descriptor */
 	tx->frame_data0 |= TX_DESC_DATA0_EXT_;
+	if (nr_frags <= 0) {
+		tx->frame_data0 |= TX_DESC_DATA0_LS_;
+		tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+	}
 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
 	tx_descriptor->data0 = tx->frame_data0;
 
@@ -1514,8 +1519,11 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx,
 	u32 tx_tail_flags = 0;
 
 	/* wrap up previous descriptor */
-	tx->frame_data0 |= TX_DESC_DATA0_LS_;
-	tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+	if ((tx->frame_data0 & TX_DESC_DATA0_DTYPE_MASK_) ==
+	    TX_DESC_DATA0_DTYPE_DATA_) {
+		tx->frame_data0 |= TX_DESC_DATA0_LS_;
+		tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+	}
 
 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
 	buffer_info = &tx->buffer_info[tx->frame_tail];
@@ -1600,7 +1608,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	}
 
 	if (gso)
-		lan743x_tx_frame_add_lso(tx, frame_length);
+		lan743x_tx_frame_add_lso(tx, frame_length, nr_frags);
 
 	if (nr_frags <= 0)
 		goto finish;
-- 
2.7.4


^ permalink raw reply related

* Re: [PATCH v1 iproute2-next 1/4] rdma: add helper rd_sendrecv_msg()
From: Leon Romanovsky @ 2019-02-26 19:16 UTC (permalink / raw)
  To: Steve Wise; +Cc: dsahern, stephen, netdev, linux-rdma
In-Reply-To: <7f48fc85-45ab-fe7d-9614-4c5eb50f8401@opengridcomputing.com>

[-- Attachment #1: Type: text/plain, Size: 3133 bytes --]

On Tue, Feb 26, 2019 at 11:19:12AM -0600, Steve Wise wrote:
>
> On 2/23/2019 3:31 AM, Leon Romanovsky wrote:
> > On Sat, Feb 23, 2019 at 11:26:15AM +0200, Leon Romanovsky wrote:
> >> On Thu, Feb 21, 2019 at 08:19:03AM -0800, Steve Wise wrote:
> >>> This function sends the constructed netlink message and then
> >>> receives the response, displaying any error text.
> >>>
> >>> Change 'rdma dev set' to use it.
> >>>
> >>> Signed-off-by: Steve Wise <swise@opengridcomputing.com>
> >>> ---
> >>>  rdma/dev.c   |  2 +-
> >>>  rdma/rdma.h  |  1 +
> >>>  rdma/utils.c | 21 +++++++++++++++++++++
> >>>  3 files changed, 23 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/rdma/dev.c b/rdma/dev.c
> >>> index 60ff4b31e320..d2949c378f08 100644
> >>> --- a/rdma/dev.c
> >>> +++ b/rdma/dev.c
> >>> @@ -273,7 +273,7 @@ static int dev_set_name(struct rd *rd)
> >>>  	mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
> >>>  	mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
> >>>
> >>> -	return rd_send_msg(rd);
> >>> +	return rd_sendrecv_msg(rd, seq);
> >>>  }
> >>>
> >>>  static int dev_one_set(struct rd *rd)
> >>> diff --git a/rdma/rdma.h b/rdma/rdma.h
> >>> index 547bb5749a39..20be2f12c4f8 100644
> >>> --- a/rdma/rdma.h
> >>> +++ b/rdma/rdma.h
> >>> @@ -115,6 +115,7 @@ bool rd_check_is_key_exist(struct rd *rd, const char *key);
> >>>   */
> >>>  int rd_send_msg(struct rd *rd);
> >>>  int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, uint32_t seq);
> >>> +int rd_sendrecv_msg(struct rd *rd, unsigned int seq);
> >>>  void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags);
> >>>  int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data);
> >>>  int rd_attr_cb(const struct nlattr *attr, void *data);
> >>> diff --git a/rdma/utils.c b/rdma/utils.c
> >>> index 069d44fece10..a6f2826c9605 100644
> >>> --- a/rdma/utils.c
> >>> +++ b/rdma/utils.c
> >>> @@ -664,6 +664,27 @@ int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, unsigned int seq)
> >>>  	return ret;
> >>>  }
> >>>
> >>> +static int null_cb(const struct nlmsghdr *nlh, void *data)
> >>> +{
> >>> +	return MNL_CB_OK;
> >>> +}
> >>> +
> >>> +int rd_sendrecv_msg(struct rd *rd, unsigned int seq)
> >>> +{
> >>> +	int ret;
> >>> +
> >>> +	ret = rd_send_msg(rd);
> >>> +	if (ret) {
> >>> +		perror(NULL);
> >> This is more or less already done in rd_send_msg() and that function
> >> prints something in case of execution error. So the missing piece
> >> is to update rd_recv_msg(), so all places will "magically" print errors
> >> and not only dev_set_name().
> >>
> >>> +		goto out;
> >>> +	}
> >>> +	ret = rd_recv_msg(rd, null_cb, rd, seq);
> > Will this "null_cb" work for all send/recv flows or only in flows where
> > response can be error only?
>
>
> Only those flows where no nl attributes are expected to be returned.
>
>
> > Will we need this recv_msg if we implement
> > extack support?
>
>
> I'm not sure how extack works.  Do you know?

I can't say that :)

>
> Thanks!
>
> Steve.
>
>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH v1 iproute2-next 1/4] rdma: add helper rd_sendrecv_msg()
From: Steve Wise @ 2019-02-26 19:55 UTC (permalink / raw)
  To: Leon Romanovsky; +Cc: dsahern, stephen, netdev, linux-rdma
In-Reply-To: <20190226191637.GW11231@mtr-leonro.mtl.com>


On 2/26/2019 1:16 PM, Leon Romanovsky wrote:
> On Tue, Feb 26, 2019 at 11:19:12AM -0600, Steve Wise wrote:
>> On 2/23/2019 3:31 AM, Leon Romanovsky wrote:
>>> On Sat, Feb 23, 2019 at 11:26:15AM +0200, Leon Romanovsky wrote:
>>>> On Thu, Feb 21, 2019 at 08:19:03AM -0800, Steve Wise wrote:
>>>>> This function sends the constructed netlink message and then
>>>>> receives the response, displaying any error text.
>>>>>
>>>>> Change 'rdma dev set' to use it.
>>>>>
>>>>> Signed-off-by: Steve Wise <swise@opengridcomputing.com>
>>>>> ---
>>>>>  rdma/dev.c   |  2 +-
>>>>>  rdma/rdma.h  |  1 +
>>>>>  rdma/utils.c | 21 +++++++++++++++++++++
>>>>>  3 files changed, 23 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/rdma/dev.c b/rdma/dev.c
>>>>> index 60ff4b31e320..d2949c378f08 100644
>>>>> --- a/rdma/dev.c
>>>>> +++ b/rdma/dev.c
>>>>> @@ -273,7 +273,7 @@ static int dev_set_name(struct rd *rd)
>>>>>  	mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
>>>>>  	mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
>>>>>
>>>>> -	return rd_send_msg(rd);
>>>>> +	return rd_sendrecv_msg(rd, seq);
>>>>>  }
>>>>>
>>>>>  static int dev_one_set(struct rd *rd)
>>>>> diff --git a/rdma/rdma.h b/rdma/rdma.h
>>>>> index 547bb5749a39..20be2f12c4f8 100644
>>>>> --- a/rdma/rdma.h
>>>>> +++ b/rdma/rdma.h
>>>>> @@ -115,6 +115,7 @@ bool rd_check_is_key_exist(struct rd *rd, const char *key);
>>>>>   */
>>>>>  int rd_send_msg(struct rd *rd);
>>>>>  int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, uint32_t seq);
>>>>> +int rd_sendrecv_msg(struct rd *rd, unsigned int seq);
>>>>>  void rd_prepare_msg(struct rd *rd, uint32_t cmd, uint32_t *seq, uint16_t flags);
>>>>>  int rd_dev_init_cb(const struct nlmsghdr *nlh, void *data);
>>>>>  int rd_attr_cb(const struct nlattr *attr, void *data);
>>>>> diff --git a/rdma/utils.c b/rdma/utils.c
>>>>> index 069d44fece10..a6f2826c9605 100644
>>>>> --- a/rdma/utils.c
>>>>> +++ b/rdma/utils.c
>>>>> @@ -664,6 +664,27 @@ int rd_recv_msg(struct rd *rd, mnl_cb_t callback, void *data, unsigned int seq)
>>>>>  	return ret;
>>>>>  }
>>>>>
>>>>> +static int null_cb(const struct nlmsghdr *nlh, void *data)
>>>>> +{
>>>>> +	return MNL_CB_OK;
>>>>> +}
>>>>> +
>>>>> +int rd_sendrecv_msg(struct rd *rd, unsigned int seq)
>>>>> +{
>>>>> +	int ret;
>>>>> +
>>>>> +	ret = rd_send_msg(rd);
>>>>> +	if (ret) {
>>>>> +		perror(NULL);
>>>> This is more or less already done in rd_send_msg() and that function
>>>> prints something in case of execution error. So the missing piece
>>>> is to update rd_recv_msg(), so all places will "magically" print errors
>>>> and not only dev_set_name().
>>>>
>>>>> +		goto out;
>>>>> +	}
>>>>> +	ret = rd_recv_msg(rd, null_cb, rd, seq);
>>> Will this "null_cb" work for all send/recv flows or only in flows where
>>> response can be error only?
>>
>> Only those flows where no nl attributes are expected to be returned.
>>
>>
>>> Will we need this recv_msg if we implement
>>> extack support?
>>
>> I'm not sure how extack works.  Do you know?
> I can't say that :)


We can change things if/when we support extack.

Stevo.



^ permalink raw reply

* Re: [PATCH v1 iproute2-next 1/4] rdma: add helper rd_sendrecv_msg()
From: David Ahern @ 2019-02-26 19:55 UTC (permalink / raw)
  To: Steve Wise, Leon Romanovsky; +Cc: stephen, netdev, linux-rdma
In-Reply-To: <7f48fc85-45ab-fe7d-9614-4c5eb50f8401@opengridcomputing.com>

On 2/26/19 10:19 AM, Steve Wise wrote:
> 
>> Will we need this recv_msg if we implement
>> extack support?
> 
> I'm not sure how extack works.  Do you know?

see devlink/mnlg.c

mnlg_socket_open()
{
	...
	mnl_socket_setsockopt(nlg->nl, NETLINK_EXT_ACK, &one, sizeof(one));
	...
}

and

mnlg_cb_error()

That code under devlink needs to be generic for both tools.

^ permalink raw reply

* [PATCH iproute2-next] devlink: add support for updating device flash
From: Jakub Kicinski @ 2019-02-26 20:20 UTC (permalink / raw)
  To: dsahern, jiri, stephen; +Cc: oss-drivers, netdev, Jakub Kicinski

Add new command for updating flash of devices via devlink API.
Example:

$ cp flash-boot.bin /lib/firmware/
$ devlink dev flash pci/0000:05:00.0 file flash-boot.bin

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 devlink/devlink.c      | 54 ++++++++++++++++++++++++++++++++++++++++++
 man/man8/devlink-dev.8 | 32 +++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/devlink/devlink.c b/devlink/devlink.c
index 960cdda99b5b..5c6cac1f76dd 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -199,6 +199,8 @@ static void ifname_map_free(struct ifname_map *ifname_map)
 #define DL_OPT_REGION_SNAPSHOT_ID	BIT(22)
 #define DL_OPT_REGION_ADDRESS		BIT(23)
 #define DL_OPT_REGION_LENGTH		BIT(24)
+#define DL_OPT_FLASH_FILE_NAME	BIT(25)
+#define DL_OPT_FLASH_COMPONENT	BIT(26)
 
 struct dl_opts {
 	uint32_t present; /* flags of present items */
@@ -230,6 +232,8 @@ struct dl_opts {
 	uint32_t region_snapshot_id;
 	uint64_t region_address;
 	uint64_t region_length;
+	const char *flash_file_name;
+	const char *flash_component;
 };
 
 struct dl {
@@ -1185,6 +1189,20 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
 			if (err)
 				return err;
 			o_found |= DL_OPT_REGION_LENGTH;
+		} else if (dl_argv_match(dl, "file") &&
+			   (o_all & DL_OPT_FLASH_FILE_NAME)) {
+			dl_arg_inc(dl);
+			err = dl_argv_str(dl, &opts->flash_file_name);
+			if (err)
+				return err;
+			o_found |= DL_OPT_FLASH_FILE_NAME;
+		} else if (dl_argv_match(dl, "component") &&
+			   (o_all & DL_OPT_FLASH_COMPONENT)) {
+			dl_arg_inc(dl);
+			err = dl_argv_str(dl, &opts->flash_component);
+			if (err)
+				return err;
+			o_found |= DL_OPT_FLASH_COMPONENT;
 		} else {
 			pr_err("Unknown option \"%s\"\n", dl_argv(dl));
 			return -EINVAL;
@@ -1389,6 +1407,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
 	if (opts->present & DL_OPT_REGION_LENGTH)
 		mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN,
 				 opts->region_length);
+	if (opts->present & DL_OPT_FLASH_FILE_NAME)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME,
+				  opts->flash_file_name);
+	if (opts->present & DL_OPT_FLASH_COMPONENT)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
+				  opts->flash_component);
 }
 
 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
@@ -1451,6 +1475,7 @@ static void cmd_dev_help(void)
 	pr_err("       devlink dev param show [DEV name PARAMETER]\n");
 	pr_err("       devlink dev reload DEV\n");
 	pr_err("       devlink dev info [ DEV ]\n");
+	pr_err("       devlink dev flash DEV file PATH [ component NAME ]\n");
 }
 
 static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
@@ -2583,6 +2608,32 @@ static int cmd_dev_info(struct dl *dl)
 	return err;
 }
 
+static void cmd_dev_flash_help(void)
+{
+	pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
+}
+
+static int cmd_dev_flash(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	int err;
+
+	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+		cmd_dev_flash_help();
+		return 0;
+	}
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
+			       NLM_F_REQUEST | NLM_F_ACK);
+
+	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
+				DL_OPT_FLASH_COMPONENT);
+	if (err)
+		return err;
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
 static int cmd_dev(struct dl *dl)
 {
 	if (dl_argv_match(dl, "help")) {
@@ -2604,6 +2655,9 @@ static int cmd_dev(struct dl *dl)
 	} else if (dl_argv_match(dl, "info")) {
 		dl_arg_inc(dl);
 		return cmd_dev_info(dl);
+	} else if (dl_argv_match(dl, "flash")) {
+		dl_arg_inc(dl);
+		return cmd_dev_flash(dl);
 	}
 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
 	return -ENOENT;
diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8
index 47838371fecd..1804463b2321 100644
--- a/man/man8/devlink-dev.8
+++ b/man/man8/devlink-dev.8
@@ -69,6 +69,16 @@ devlink-dev \- devlink device configuration
 .IR DEV
 .RI "]"
 
+.ti -8
+.BR "devlink dev flash"
+.IR DEV
+.BR file
+.IR PATH
+.RI "["
+.BR target
+.IR ID
+.RI "]"
+
 .SH "DESCRIPTION"
 .SS devlink dev show - display devlink device attributes
 
@@ -177,6 +187,28 @@ versions may differ after flash has been updated, but before reboot.
 - specifies the devlink device to show.
 If this argument is omitted all devices are listed.
 
+.SS devlink dev flash - write device's non-volatile memory.
+
+.PP
+.I "DEV"
+- specifies the devlink device to write to.
+
+.BR file
+.I PATH
+- Path to the file which will be written into device's flash. The path needs
+to be relative to one of the directories searched by the kernel firmware loaded,
+such as /lib/firmware.
+
+.BR component
+.I NAME
+- If device stores multiple firmware images in non-volatile memory, this
+parameter may be used to indicate which firmware image should be written.
+The value of
+.I NAME
+should match the component names from
+.B "devlink dev info"
+and may be driver-dependent.
+
 .SH "EXAMPLES"
 .PP
 devlink dev show
-- 
2.19.2


^ permalink raw reply related

* Re: [PATCH 0/3] soc: fsl: dpio: enable and configure cache stashing
From: David Miller @ 2019-02-26 20:31 UTC (permalink / raw)
  To: leoyang.li
  Cc: ioana.ciornei, roy.pledge, ruxandra.radulescu, laurentiu.tudor,
	horia.geanta, brouer, netdev, linux-kernel
In-Reply-To: <CADRPPNSRpbD_dUZYJC4-SwudNk2JTPCug3T6g4dTYMBDQeeu7w@mail.gmail.com>

From: Li Yang <leoyang.li@nxp.com>
Date: Tue, 26 Feb 2019 13:03:17 -0600

> On Mon, Feb 25, 2019 at 1:01 AM Ioana Ciornei <ioana.ciornei@nxp.com> wrote:
>>
>> > Subject: Re: [PATCH 0/3] soc: fsl: dpio: enable and configure cache stashing
>> >
>> > From: Ioana Ciornei <ioana.ciornei@nxp.com>
>> > Date: Sat, 23 Feb 2019 08:48:42 +0000
>> >
>> > > The first two patches enable cache stashing and configure the core
>> > > cluster destination per software portal while the third patch is the
>> > > one configuring the amount of stashing on a queue.
>> >
>> > Should I merge this series in via my networking tree?
>>
>> Even though it would be really good to have this on the networking tree as soon as possible, I am afraid that patch 2/3 is not going to apply cleanly because it touches the same areas of code that some other patches on Leo's tree are.
> 
> Hi David,
> 
> What shall we do if we want to get this in the 5.1?  Since the change
> on the ethernet driver is pretty small, can I get your ACK on that
> patch and merge the series through my tree?

Sure.

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* Re: [PATCH net 4/4] tls: Fix tls_device receive
From: Dave Watson @ 2019-02-26 20:34 UTC (permalink / raw)
  To: Boris Pismenny
  Cc: aviadye@mellanox.com, john.fastabend@gmail.com,
	daniel@iogearbox.net, vakul.garg@nxp.com, netdev@vger.kernel.org,
	eranbe@mellanox.com
In-Reply-To: <20190226121235.20784-5-borisp@mellanox.com>

On 02/26/19 02:12 PM, Boris Pismenny wrote:
> Currently, the receive function fails to handle records already
> decrypted by the device due to the commit mentioned below.
> 
> This commit advances the TLS record sequence number and prepares the context
> to handle the next record.
> 
> Fixes: fedf201e1296 ("net: tls: Refactor control message handling on recv")
> Signed-off-by: Boris Pismenny <borisp@mellanox.com>
> Reviewed-by: Eran Ben Elisha <eranbe@mellanox.com>
> ---
>  net/tls/tls_sw.c | 15 +++++++--------
>  1 file changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
> index f515cd7e984e..85da10182d8d 100644
> --- a/net/tls/tls_sw.c
> +++ b/net/tls/tls_sw.c
> @@ -1481,18 +1481,17 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb,
>  
>  			return err;
>  		}
> -
> -		rxm->full_len -= padding_length(ctx, tls_ctx, skb);
> -
> -		rxm->offset += prot->prepend_size;
> -		rxm->full_len -= prot->overhead_size;
> -		tls_advance_record_sn(sk, &tls_ctx->rx, version);
> -		ctx->decrypted = true;
> -		ctx->saved_data_ready(sk);
>  	} else {
>  		*zc = false;
>  	}
>  
> +	rxm->full_len -= padding_length(ctx, tls_ctx, skb);
> +	rxm->offset += prot->prepend_size;
> +	rxm->full_len -= prot->overhead_size;
> +	tls_advance_record_sn(sk, &tls_ctx->rx, version);
> +	ctx->decrypted = true;
> +	ctx->saved_data_ready(sk);
> +
>  	return err;
>  }

This breaks the tls.control_msg test:

  [ RUN      ] tls.control_msg
  tls.c:764:tls.control_msg:Expected memcmp(buf, test_str, send_len) (18446744073709551614) == 0 (0)
  tls.c:777:tls.control_msg:Expected memcmp(buf, test_str, send_len) (18446744073709551614) == 0 (0)
  tls.control_msg: Test failed at step #8

So either control message handling needs to only call
decrypt_skb_update once, or we need a new flag or something to handle
the device case

^ permalink raw reply

* RE: [RFC v1 10/19] RDMA/irdma: Add connection manager
From: Saleem, Shiraz @ 2019-02-26 21:07 UTC (permalink / raw)
  To: 'Jason Gunthorpe', Gal Pressman
  Cc: dledford@redhat.com, davem@davemloft.net,
	linux-rdma@vger.kernel.org, netdev@vger.kernel.org,
	Ismail, Mustafa, Kirsher, Jeffrey T
In-Reply-To: <20190225184629.GC21863@ziepe.ca>

>Subject: Re: [RFC v1 10/19] RDMA/irdma: Add connection manager
>
>On Sun, Feb 24, 2019 at 01:21:16PM +0200, Gal Pressman wrote:
>> On 15-Feb-19 19:10, Shiraz Saleem wrote:
>> > +/**
>> > + * irdma_cm_teardown_connections - teardown QPs
>> > + * @iwdev: device pointer
>> > + * @ipaddr: Pointer to IPv4 or IPv6 address
>> > + * @ipv4: flag indicating IPv4 when true
>>
>> There is no ipv4 parameter.
>
>Be sure to run code through make W=1 - it runs stuff that checks the kdocs.

OK. Will do. Thanks! We have a few hits here.

>
>> > +	INIT_LIST_HEAD(&teardown_list);
>> > +	for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
>> > +		spin_lock_irqsave(&vsi->qos[i].lock, flags);
>> > +		list_for_each_safe(list_node, list_core_temp, &vsi->qos[i].qplist) {
>> > +			u32 qp_ip[4];
>> > +
>> > +			sc_qp = container_of(list_node, struct irdma_sc_qp, list);
>> > +			if (sc_qp->qp_type != IRDMA_QP_TYPE_ROCE_RC)
>> > +				continue;
>> > +
>> > +			qp = sc_qp->back_qp;
>> > +			if (!disconnect_all) {
>> > +				if (nfo->ipv4)
>> > +					qp_ip[0] = qp->udp_info.local_ipaddr3;
>> > +				else
>> > +					memcpy(qp_ip,
>> > +					       &qp->udp_info.local_ipaddr0,
>> > +					       sizeof(qp_ip));
>> > +			}
>> > +
>> > +			if (disconnect_all ||
>> > +			    (nfo->vlan_id == qp->udp_info.vlan_tag &&
>> > +			    !memcmp(qp_ip, ipaddr, nfo->ipv4 ? 4 : 16))) {
>> > +				spin_lock_irqsave(&iwdev->rf->qptable_lock,
>flags);
>>
>> You should use different 'flags' here.
>
>If irqs are already proven disabled it is just spin_lock, right?
>
Correct.

^ permalink raw reply

* RE: [RFC v1 04/19] RDMA/irdma: Add driver framework definitions
From: Saleem, Shiraz @ 2019-02-26 21:08 UTC (permalink / raw)
  To: 'Gal Pressman', dledford@redhat.com, jgg@ziepe.ca,
	davem@davemloft.net
  Cc: linux-rdma@vger.kernel.org, netdev@vger.kernel.org,
	Ismail, Mustafa, Kirsher, Jeffrey T
In-Reply-To: <5215c158-2935-ef45-db49-44caa84e07d3@amazon.com>

>Subject: Re: [RFC v1 04/19] RDMA/irdma: Add driver framework definitions
>
>On 15-Feb-19 19:10, Shiraz Saleem wrote:
>> +/* client interface functions */
>> +static const struct i40e_client_ops i40e_ops = {
>> +	.open = i40iw_open,
>> +	.close = i40iw_close,
>> +	.l2_param_change = i40iw_l2param_change,
>> +	.virtchnl_receive = NULL,
>> +	.vf_reset = NULL,
>> +	.vf_enable = NULL,
>> +	.vf_capable = NULL
>
>NULL assignments are redundant.
>
>> +};
>> +
>> diff --git a/drivers/infiniband/hw/irdma/irdma_if.c
>> b/drivers/infiniband/hw/irdma/irdma_if.c
>> new file mode 100644
>> index 0000000..f7b89e9
>> --- /dev/null
>> +++ b/drivers/infiniband/hw/irdma/irdma_if.c
>> @@ -0,0 +1,430 @@
>> +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
>> +/* Copyright (c) 2019, Intel Corporation. */
>> +
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <ice_idc.h>
>> +#include "main.h"
>> +#include "ws.h"
>> +#include "icrdma_hw.h"
>> +
>> +void irdma_add_dev_ref(struct irdma_sc_dev *dev) {
>> +	try_module_get(THIS_MODULE);
>> +}
>> +
>> +void irdma_put_dev_ref(struct irdma_sc_dev *dev) {
>> +	module_put(THIS_MODULE);
>> +}
>
>What are these used for?
>
>> +
>> +/**
>> + * irdma_find_iwdev - find a vsi device given a name
>> + * @name: name of iwdev
>> + */
>
>Can't find uses of this function as well.
>
>> +struct irdma_device *irdma_find_iwdev(const char *name) {
>> +	struct irdma_handler *hdl;
>> +	struct list_head *pos;
>> +	struct list_head *tmp;
>> +	struct irdma_device *iwdev;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&irdma_handler_lock, flags);
>> +	list_for_each_entry(hdl, &irdma_handlers, list) {
>> +		list_for_each_safe(pos, tmp, &hdl->rf.vsi_dev_list) {
>> +			iwdev = container_of(pos, struct irdma_device, list);
>> +			if (!strcmp(name, iwdev->iwibdev->ibdev.name)) {
>> +				spin_unlock_irqrestore(&irdma_handler_lock,
>> +						       flags);
>> +				return iwdev;
>> +			}
>> +		}
>> +	}
>> +	spin_unlock_irqrestore(&irdma_handler_lock, flags);
>> +
>> +	return NULL;
>> +}
>> +

Will all fix 3 comments. Thanks!

^ permalink raw reply

* RE: [RFC v1 12/19] RDMA/irdma: Implement device supported verb APIs
From: Saleem, Shiraz @ 2019-02-26 21:09 UTC (permalink / raw)
  To: Gal Pressman, dledford@redhat.com, jgg@ziepe.ca,
	davem@davemloft.net
  Cc: linux-rdma@vger.kernel.org, netdev@vger.kernel.org,
	Ismail, Mustafa, Kirsher, Jeffrey T, Yossi Leybovich
In-Reply-To: <01b0d571-81d8-ed6c-77b7-e83ee0ab9caa@amazon.com>

>Subject: Re: [RFC v1 12/19] RDMA/irdma: Implement device supported verb APIs
>
>On 15-Feb-19 19:10, Shiraz Saleem wrote:
>> /**
>>  * irdma_dealloc_ucontext - deallocate the user context data structure
>>  * @context: user context created during alloc  */ static int
>> irdma_dealloc_ucontext(struct ib_ucontext *context) {
>> 	struct irdma_ucontext *ucontext = to_ucontext(context);
>> 	unsigned long flags;
>>
>> 	spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
>> 	if (!list_empty(&ucontext->cq_reg_mem_list)) {
>> 		spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
>> 		return -EBUSY;
>> 	}
>> 	spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
>>
>> 	spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
>> 	if (!list_empty(&ucontext->qp_reg_mem_list)) {
>> 		spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
>> 		return -EBUSY;
>
>Drivers are not permitted to fail dealloc_ucontext.

This is fixed in RFC v1 submission. Maybe this was pasted from the v0 ver?

[..]

>> +/**
>> + * irdma_alloc_pd - allocate protection domain
>> + * @pd: PD pointer
>> + * @context: user context created during alloc
>> + * @udata: user data
>> + */
>> +static int irdma_alloc_pd(struct ib_pd *pd,
>> +			  struct ib_ucontext *context,
>> +			  struct ib_udata *udata)
>> +{
>> +	struct irdma_pd *iwpd = to_iwpd(pd);
>> +	struct irdma_device *iwdev = to_iwdev(pd->device);
>> +	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
>> +	struct irdma_pci_f *rf = iwdev->rf;
>> +	struct irdma_alloc_pd_resp uresp = {};
>> +	struct irdma_sc_pd *sc_pd;
>> +	struct irdma_ucontext *ucontext;
>> +	u32 pd_id = 0;
>> +	int err;
>> +
>> +	if (iwdev->closing)
>> +		return -ENODEV;
>> +
>> +	err = irdma_alloc_rsrc(rf, rf->allocated_pds, rf->max_pd, &pd_id,
>> +			       &rf->next_pd);
>> +	if (err)
>> +		return err;
>> +
>> +	sc_pd = &iwpd->sc_pd;
>> +	if (context) {
>
>I think this should be 'if (udata)', this applies to many other places in this driver.

That’s right. Will fix it.

>
>> +		ucontext = to_ucontext(context);
>> +		dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id, ucontext->abi_ver);
>> +		uresp.pd_id = pd_id;
>> +		if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
>> +			err = -EFAULT;
>> +			goto error;
>> +		}
>> +	} else {
>> +		dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id, -1);
>> +	}
>> +
>> +	irdma_add_pdusecount(iwpd);
>> +
>> +	return 0;
>> +error:
>> +	irdma_free_rsrc(rf, rf->allocated_pds, pd_id);
>> +
>> +	return err;
>> +}
>> +/**
>> + * irdma_create_qp - create qp
>> + * @ibpd: ptr of pd
>> + * @init_attr: attributes for qp
>> + * @udata: user data for create qp
>> + */
>> +static struct ib_qp *irdma_create_qp(struct ib_pd *ibpd,
>> +				     struct ib_qp_init_attr *init_attr,
>> +				     struct ib_udata *udata)
>> +{
>> +	struct irdma_pd *iwpd = to_iwpd(ibpd);
>> +	struct irdma_device *iwdev = to_iwdev(ibpd->device);
>> +	struct irdma_pci_f *rf = iwdev->rf;
>> +	struct irdma_cqp *iwcqp = &rf->cqp;
>> +	struct irdma_qp *iwqp;
>> +	struct irdma_ucontext *ucontext;
>> +	struct irdma_create_qp_req req;
>> +	struct irdma_create_qp_resp uresp = {};
>> +	struct i40iw_create_qp_resp uresp_gen1 = {};
>> +	u32 qp_num = 0;
>> +	void *mem;
>> +	enum irdma_status_code ret;
>> +	int err_code = 0;
>> +	int sq_size;
>> +	int rq_size;
>> +	struct irdma_sc_qp *qp;
>> +	struct irdma_sc_dev *dev = &rf->sc_dev;
>> +	struct irdma_qp_init_info init_info = {};
>> +	struct irdma_create_qp_info *qp_info;
>> +	struct irdma_cqp_request *cqp_request;
>> +	struct cqp_cmds_info *cqp_info;
>> +	struct irdma_qp_host_ctx_info *ctx_info;
>> +	struct irdma_iwarp_offload_info *iwarp_info;
>> +	struct irdma_roce_offload_info *roce_info;
>> +	struct irdma_udp_offload_info *udp_info;
>> +	unsigned long flags;
>> +
>> +	if (iwdev->closing)
>> +		return ERR_PTR(-ENODEV);
>> +
>> +	if (init_attr->create_flags)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	if (init_attr->cap.max_inline_data > dev->hw_attrs.max_hw_inline)
>> +		init_attr->cap.max_inline_data = dev->hw_attrs.max_hw_inline;
>> +
>> +	if (init_attr->cap.max_send_sge > dev->hw_attrs.max_hw_wq_frags)
>> +		init_attr->cap.max_send_sge = dev-
>>hw_attrs.max_hw_wq_frags;
>> +
>> +	if (init_attr->cap.max_recv_sge > dev->hw_attrs.max_hw_wq_frags)
>> +		init_attr->cap.max_recv_sge = dev->hw_attrs.max_hw_wq_frags;
>
>AFAIK, you can change the requested values to be greater than or equal to the
>values requested. I don't think you can change them to something smaller.

Hmm...This is a sanity check to make sure we don’t exceed the device supported values.
But we should fail the call.

[..]

>> +	mem = kzalloc(sizeof(*iwqp), GFP_KERNEL);
>> +	if (!mem)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	iwqp = (struct irdma_qp *)mem;
>> +	iwqp->allocated_buf = mem;
>
>'allocated_buf' feels redundant. Why is iwqp not sufficient?

I agree.
[..]

>> +	if (udata) {
>> +		err_code = ib_copy_from_udata(&req, udata, sizeof(req));
>
>Perhaps ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen)?
>Applies to other call sites of ib_copy_from/to_udata as well.
>

It’s a good idea.

>> + * irdma_query - query qp attributes
>> + * @ibqp: qp pointer
>> + * @attr: attributes pointer
>> + * @attr_mask: Not used
>> + * @init_attr: qp attributes to return  */ static int
>> +irdma_query_qp(struct ib_qp *ibqp,
>> +			  struct ib_qp_attr *attr,
>> +			  int attr_mask,
>> +			  struct ib_qp_init_attr *init_attr) {
>> +	struct irdma_qp *iwqp = to_iwqp(ibqp);
>> +	struct irdma_sc_qp *qp = &iwqp->sc_qp;
>> +
>> +	attr->qp_state = iwqp->ibqp_state;
>> +	attr->cur_qp_state = iwqp->ibqp_state;
>> +	attr->qp_access_flags = 0;
>> +	attr->cap.max_send_wr = qp->qp_uk.sq_size - 1;
>> +	attr->cap.max_recv_wr = qp->qp_uk.rq_size - 1;
>
>Why -1?

It's reserved for HW. But the equation should be 
(sqdepth - I40IW_SQ_RSVD) >> sqshift.

[....]
>
>> +	attr->cap.max_inline_data = qp->qp_uk.max_inline_data;
>> +	attr->cap.max_send_sge = qp->qp_uk.max_sq_frag_cnt;
>> +	attr->cap.max_recv_sge = qp->qp_uk.max_rq_frag_cnt;
>> +	attr->qkey = iwqp->roce_info.qkey;
>> +
>> +	init_attr->event_handler = iwqp->ibqp.event_handler;
>> +	init_attr->qp_context = iwqp->ibqp.qp_context;
>> +	init_attr->send_cq = iwqp->ibqp.send_cq;
>> +	init_attr->recv_cq = iwqp->ibqp.recv_cq;
>> +	init_attr->srq = iwqp->ibqp.srq;
>> +	init_attr->cap = attr->cap;
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * irdma_destroy_cq - destroy cq
>> + * @ib_cq: cq pointer
>> + */
>> +static int irdma_destroy_cq(struct ib_cq *ib_cq) {
>> +	struct irdma_cq *iwcq;
>> +	struct irdma_device *iwdev;
>> +	struct irdma_sc_cq *cq;
>> +
>> +	if (!ib_cq) {
>> +		irdma_pr_err("ib_cq == NULL\n");
>> +		return 0;
>> +	}
>
>Is this really needed? Which caller can pass NULL pointer?

Not needed.

>> +
>> +/**
>> + * board_id_show
>> + */
>> +static ssize_t board_id_show(struct device *dev,
>> +			     struct device_attribute *attr,
>> +			     char *buf)
>> +{
>> +	return sprintf(buf, "%.*s\n", 32, "IRDMA Board ID");
>
>That doesn't add much information.

Will fix.

>
>> +}
>> +
>> +static DEVICE_ATTR_RO(hw_rev);
>> +static DEVICE_ATTR_RO(hca_type);
>> +static DEVICE_ATTR_RO(board_id);
>> +
>> +static struct attribute *irdma_dev_attributes[] = {
>> +	&dev_attr_hw_rev.attr,
>> +	&dev_attr_hca_type.attr,
>> +	&dev_attr_board_id.attr,
>> +	NULL
>> +};
>> +
>> +static const struct attribute_group irdma_attr_group = {
>> +	.attrs = irdma_dev_attributes,
>> +};
>> +
>> +/**
>> + * irdma_modify_port  Modify port properties
>> + * @ibdev: device pointer from stack
>> + * @port: port number
>> + * @port_modify_mask: mask for port modifications
>> + * @props: port properties
>> + */
>> +static int irdma_modify_port(struct ib_device *ibdev,
>> +			     u8 port,
>> +			     int port_modify_mask,
>> +			     struct ib_port_modify *props) {
>> +	return 0;
>> +}
>
>Same question as disacossiate_ucontext.

This was likely added during early dev. and can be removed.

>
>> +
>> +/**
>> + * irdma_query_gid_roce - Query port GID for Roce
>> + * @ibdev: device pointer from stack
>> + * @port: port number
>> + * @index: Entry index
>> + * @gid: Global ID
>> + */
>> +static int irdma_query_gid_roce(struct ib_device *ibdev,
>> +				u8 port,
>> +				int index,
>> +				union ib_gid *gid)
>> +{
>> +	int ret;
>> +
>> +	ret = rdma_query_gid(ibdev, port, index, gid);
>> +	if (ret == -EAGAIN) {
>
>I can't see a path where rdma_query_gid returns -EAGAIN.

This function can be removed now. It's only applicable to non-Roce providers.

>
>> +		memcpy(gid, &zgid, sizeof(*gid));
>> +		return 0;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>
>> +/**
>> + * irdma_create_ah - create address handle
>> + * @ibpd: ptr to protection domain
>> + * @ah_attr: address handle attributes
>
>'ah_attr' -> 'attr', missing flags and udata.

Will fix all these hits in the driver.

[..]
>> + */
>> +static int irdma_destroy_ah(struct ib_ah *ibah, u32 flags) {
>> +	struct irdma_device *iwdev = to_iwdev(ibah->device);
>> +	struct irdma_ah *ah = to_iwah(ibah);
>> +	int err;
>> +
>> +	if (!ah->sc_ah.ah_info.ah_valid)
>> +		return -EINVAL;
>> +
>> +	err = irdma_ah_cqp_op(iwdev->rf, &ah->sc_ah,
>IRDMA_OP_AH_DESTROY,
>> +			      flags & RDMA_DESTROY_AH_SLEEPABLE,
>> +			      irdma_destroy_ah_cb, ah);
>> +	if (!err)
>> +		return 0;
>
>Why are the rest of the cleanups only in case of error?

On success, the cleanup is done in the callback, irdma_destroy_ah_cb.

[...]


>> +static __be64 irdma_mac_to_guid(struct net_device *ndev) {
>> +	unsigned char *mac = ndev->dev_addr;
>> +	__be64 guid;
>> +	unsigned char *dst = (unsigned char *)&guid;
>> +
>> +	dst[0] = mac[0] ^ 2;
>> +	dst[1] = mac[1];
>> +	dst[2] = mac[2];
>> +	dst[3] = 0xff;
>> +	dst[4] = 0xfe;
>> +	dst[5] = mac[3];
>> +	dst[6] = mac[4];
>> +	dst[7] = mac[5];
>> +
>> +	return guid;
>> +}
>
>There's a variant of this function in irdma, bnxt_re, ocrdma and qedr.
>Maybe it's time to provide it in common code?

Agreed.

^ permalink raw reply

* RE: [RFC v1 12/19] RDMA/irdma: Implement device supported verb APIs
From: Saleem, Shiraz @ 2019-02-26 21:09 UTC (permalink / raw)
  To: 'Jason Gunthorpe', Gal Pressman
  Cc: dledford@redhat.com, davem@davemloft.net,
	linux-rdma@vger.kernel.org, netdev@vger.kernel.org,
	Ismail, Mustafa, Kirsher, Jeffrey T, Yossi Leybovich
In-Reply-To: <20190225185015.GD21863@ziepe.ca>

>Subject: Re: [RFC v1 12/19] RDMA/irdma: Implement device supported verb APIs
>

[..]

>> > +	ret = irdma_alloc_rsrc(iwdev->rf,
>> > +			       iwdev->rf->allocated_mrs, iwdev->rf->max_mr,
>> > +			       &stag_index, &next_stag_index);
>> > +	if (!ret) {
>> > +		stag = stag_index << IRDMA_CQPSQ_STAG_IDX_S;
>> > +		stag |= driver_key;
>> > +		stag += (u32)consumer_key;
>> > +		irdma_add_devusecount(iwdev);
>> > +	}
>>
>> This is confusing IMHO, better to test for 'if (ret)' and keep the
>> main flow unindented.
>
>Yes please follow the standard 'success oriented flow'
>
OK.

^ permalink raw reply

* Re: [RFC] nasty corner case in unix_dgram_sendmsg()
From: Jason Baron @ 2019-02-26 20:35 UTC (permalink / raw)
  To: Al Viro, Rainer Weikusat; +Cc: netdev
In-Reply-To: <20190226190316.GJ2217@ZenIV.linux.org.uk>



On 2/26/19 2:03 PM, Al Viro wrote:
> On Tue, Feb 26, 2019 at 03:31:32PM +0000, Rainer Weikusat wrote:
>> Al Viro <viro@zeniv.linux.org.uk> writes:
>>> On Tue, Feb 26, 2019 at 06:28:17AM +0000, Al Viro wrote:
>>
>> [...]
>>
>>
>>>> 	* if after relocking we see that unix_peer(sk) now
>>>> is equal to other, we arrange for wakeup forwarding from other's
>>>> peer_wait *and* if that has (likely) succeeded we fail with -EAGAIN.
>>>> Huh?
>>
>> This returns 1 if sending isn't possible at the moment, ie, if the
>> process which tries to send has to wait.
> 
> Except that in _this_ case we won't be waiting at all - we'll just
> return -EAGAIN (as one could expect, what with no timeout given/left).
> So what's the point of forwarding wakeups?  IOW, what is it that we
> expect to be waiting on sk_sleep(sk)?  Note that it won't be this
> call of sendmsg(2) (it'll bugger off without any further waiting).
> It won't be subsequent calls of sendmsg(2) either - they either
> sleep on skb allocation (which has nothing to do with destination)
> _or_ they sleep directly on other->peer_wait.  And poll(), while it
> will be sleeping on sk_sleep(sk), will make sure to set the forwarding 
> up.
> 
> I understand what the unix_dgram_peer_wake_me() is doing; I understand
> what unix_dgram_poll() is using it for.  What I do not understand is
> what's the point of doing that in unix_dgram_sendmsg()...
> 

Hi,

So the unix_dgram_peer_wake_me() in unix_dgram_sendmsg() is there for
epoll in edge-triggered mode. In that case, we want to ensure that if
-EAGAIN is returned a subsequent epoll_wait() is not stuck indefinitely.
Probably could use a comment...

Thanks,

-Jason

^ permalink raw reply

* Re: [PATCH net-next 0/5] tcp: cleanups for linux-5.1
From: David Miller @ 2019-02-26 21:16 UTC (permalink / raw)
  To: edumazet; +Cc: netdev, eric.dumazet
In-Reply-To: <20190226174913.18824-1-edumazet@google.com>

From: Eric Dumazet <edumazet@google.com>
Date: Tue, 26 Feb 2019 09:49:08 -0800

> This small patch series cleanups few things, and add a small
> timewait optimization for hosts not using md5.

Series applied, thanks Eric.

^ permalink raw reply

* Re: [PATCH RFC] net: Validate size of non-TSO packets in validate_xmit_skb().
From: David Miller @ 2019-02-26 21:16 UTC (permalink / raw)
  To: michael.chan; +Cc: maheshb, edumazet, netdev, dja
In-Reply-To: <CACKFLim51U_NGEU9nH5ZPWiup==aDLQM+x3p_O0-3EerZQ74hg@mail.gmail.com>

From: Michael Chan <michael.chan@broadcom.com>
Date: Tue, 26 Feb 2019 10:22:42 -0800

> On Tue, Feb 26, 2019 at 9:13 AM David Miller <davem@davemloft.net> wrote:
>>
>> From: Michael Chan <michael.chan@broadcom.com>
>> Date: Tue, 26 Feb 2019 05:56:41 -0500
>>
>> > There have been reports of oversize UDP packets being sent to the
>> > driver to be transmitted, causing error conditions.  The issue is
>> > likely caused by the dst of the SKB switching between 'lo' with
>> > 64K MTU and the hardware device with a smaller MTU.  Patches are
>> > being proposed by Mahesh Bandewar <maheshb@google.com> to fix the
>> > issue.
>> >
>> > Separately, we should add a length check in validate_xmit_skb()
>> > to drop these oversize packets before they reach the driver.
>> > This patch only validates non-TSO packets.  Complete validation
>> > of segmented TSO packet size will probably be too slow.
>> >
>> > Signed-off-by: Michael Chan <michael.chan@broadcom.com>
>>
>> Anything which changes the dst of an SKB really is responsible for
>> fixing up whatever became "incompatible" in the new path.
>>
>> So like Eric I want to see this out of the fast path.
> 
> Ok.  In the meantime, will you take a 2-line bnxt_en patch that will
> prevent this issue in kernel 5.0?

Sure, but we will have to remember to remove it when it is no longer
necessary...

^ permalink raw reply

* Re: [PATCH net 0/3] net: Fail route add with unsupported nexthop attribute
From: David Miller @ 2019-02-26 22:27 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, dsahern
In-Reply-To: <20190226170004.4535-1-dsahern@kernel.org>

From: David Ahern <dsahern@kernel.org>
Date: Tue, 26 Feb 2019 09:00:01 -0800

> From: David Ahern <dsahern@gmail.com>
> 
> RTA_VIA was added for MPLS as a way of specifying a gateway from a
> different address family. IPv4 and IPv6 do not currently support RTA_VIA
> so using it leads to routes that are not what the user intended. Catch
> and fail - returning a proper error message.
> 
> MPLS on the other hand does not support RTA_GATEWAY since it does not
> make sense to have a nexthop from the MPLS address family. Similarly,
> catch and fail - returning a proper error message.

Series applied and queued up for -stable.

^ permalink raw reply

* [PATCH bpf-next 1/3] bpf: add bpf_progenyof helper
From: Javier Honduvilla Coto @ 2019-02-26 22:36 UTC (permalink / raw)
  To: netdev; +Cc: yhs, kernel-team
In-Reply-To: <20190226223651.3166820-1-javierhonduco@fb.com>

This patch adds the bpf_progenyof helper which receives a PID and returns
1 if the process currently being executed is in the process hierarchy
including itself or 0 if not.

This is very useful in tracing programs when we want to filter by a
given PID and all the children it might spawn. The current workarounds
most people implement for this purpose have issues:

- Attaching to process spawning syscalls and dynamically add those PIDs
  to some bpf map that would be used to filter is cumbersome and
potentially racy.
- Unrolling some loop to perform what this helper is doing consumes lots
  of instructions. That and the impossibility to jump backwards makes it
really hard to be correct in really large process chains.

Signed-off-by: Javier Honduvilla Coto <javierhonduco@fb.com>
---
 include/linux/bpf.h      |  1 +
 include/uapi/linux/bpf.h |  3 ++-
 kernel/bpf/core.c        |  1 +
 kernel/bpf/helpers.c     | 29 +++++++++++++++++++++++++++++
 kernel/trace/bpf_trace.c |  2 ++
 5 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index de18227b3d95..447395ba202b 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -921,6 +921,7 @@ extern const struct bpf_func_proto bpf_sk_redirect_map_proto;
 extern const struct bpf_func_proto bpf_spin_lock_proto;
 extern const struct bpf_func_proto bpf_spin_unlock_proto;
 extern const struct bpf_func_proto bpf_get_local_storage_proto;
+extern const struct bpf_func_proto bpf_progenyof_proto;
 
 /* Shared helpers among cBPF and eBPF. */
 void bpf_user_rnd_init_once(void);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index bcdd2474eee7..804e4218eb28 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -2457,7 +2457,8 @@ union bpf_attr {
 	FN(spin_lock),			\
 	FN(spin_unlock),		\
 	FN(sk_fullsock),		\
-	FN(tcp_sock),
+	FN(tcp_sock),			\
+	FN(progenyof),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index ef88b167959d..69e209fbd128 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2015,6 +2015,7 @@ const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak;
 const struct bpf_func_proto bpf_get_current_comm_proto __weak;
 const struct bpf_func_proto bpf_get_current_cgroup_id_proto __weak;
 const struct bpf_func_proto bpf_get_local_storage_proto __weak;
+const struct bpf_func_proto bpf_progenyof_proto __weak;
 
 const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void)
 {
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index a411fc17d265..3899787e8dbf 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/uidgid.h>
 #include <linux/filter.h>
+#include <linux/init_task.h>
 
 /* If kernel subsystem is allowing eBPF programs to call this function,
  * inside its own verifier_ops->get_func_proto() callback it should return
@@ -364,3 +365,31 @@ const struct bpf_func_proto bpf_get_local_storage_proto = {
 };
 #endif
 #endif
+
+BPF_CALL_1(bpf_progenyof, int, pid)
+{
+	int result = 0;
+	struct task_struct *task = current;
+
+	if (unlikely(!task))
+		return -EINVAL;
+
+	rcu_read_lock();
+	while (task != &init_task) {
+		if (task->pid == pid) {
+			result = 1;
+			break;
+		}
+		task = rcu_dereference(task->real_parent);
+	}
+	rcu_read_unlock();
+
+	return result;
+}
+
+const struct bpf_func_proto bpf_progenyof_proto = {
+	.func		= bpf_progenyof,
+	.gpl_only	= false,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_ANYTHING,
+};
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index f1a86a0d881d..8602ae83c799 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -600,6 +600,8 @@ tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 		return &bpf_get_prandom_u32_proto;
 	case BPF_FUNC_probe_read_str:
 		return &bpf_probe_read_str_proto;
+	case BPF_FUNC_progenyof:
+		return &bpf_progenyof_proto;
 #ifdef CONFIG_CGROUPS
 	case BPF_FUNC_get_current_cgroup_id:
 		return &bpf_get_current_cgroup_id_proto;
-- 
2.17.1


^ 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