* Re: [PATCH net-next v3 4/8] net: dsa: Add setter for SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS
From: Jiri Pirko @ 2019-02-21 9:57 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, David S. Miller, Ido Schimmel, open list,
open list:STAGING SUBSYSTEM, moderated list:ETHERNET BRIDGE, jiri,
andrew, vivien.didelot
In-Reply-To: <20190221005826.26317-5-f.fainelli@gmail.com>
Thu, Feb 21, 2019 at 01:58:22AM CET, f.fainelli@gmail.com wrote:
>In preparation for removing SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT,
>add support for a function that processes the
>SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS and
>SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS attributes and returns not
>supported for any flag set, since DSA does not currently support
>toggling those bridge port attributes (yet).
>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* Re: [PATCH net-next v3 5/8] rocker: Check Handle PORT_PRE_BRIDGE_FLAGS
From: Jiri Pirko @ 2019-02-21 9:57 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, David S. Miller, Ido Schimmel, open list,
open list:STAGING SUBSYSTEM, moderated list:ETHERNET BRIDGE, jiri,
andrew, vivien.didelot
In-Reply-To: <20190221005826.26317-6-f.fainelli@gmail.com>
Thu, Feb 21, 2019 at 01:58:23AM CET, f.fainelli@gmail.com wrote:
>In preparation for getting rid of switchdev_port_attr_get(), have rocker
>check for the bridge flags being set through switchdev_port_attr_set()
>with the SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS attribute identifier.
>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* Re: [PATCH net-next v3 6/8] net: bridge: Stop calling switchdev_port_attr_get()
From: Jiri Pirko @ 2019-02-21 9:57 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, David S. Miller, Ido Schimmel, open list,
open list:STAGING SUBSYSTEM, moderated list:ETHERNET BRIDGE, jiri,
andrew, vivien.didelot
In-Reply-To: <20190221005826.26317-7-f.fainelli@gmail.com>
Thu, Feb 21, 2019 at 01:58:24AM CET, f.fainelli@gmail.com wrote:
>Now that all switchdev drivers have been converted to check the
>SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS flags and report flags that they
>do not support accordingly, we can migrate the bridge code to try to set
>that attribute first, check the results and then do the actual setting.
>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* Re: [PATCH net-next v3 7/8] net: Remove SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT
From: Jiri Pirko @ 2019-02-21 9:57 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, David S. Miller, Ido Schimmel, open list,
open list:STAGING SUBSYSTEM, moderated list:ETHERNET BRIDGE, jiri,
andrew, vivien.didelot
In-Reply-To: <20190221005826.26317-8-f.fainelli@gmail.com>
Thu, Feb 21, 2019 at 01:58:25AM CET, f.fainelli@gmail.com wrote:
>Now that we have converted the bridge code and the drivers to check for
>bridge port(s) flags at the time we try to set them, there is no need
>for a get() -> set() sequence anymore and
>SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT therefore becomes unused.
>
>Reviewed-by: Ido Schimmel <idosch@mellanox.com>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* Re: [PATCH net-next v3 8/8] net: Get rid of switchdev_port_attr_get()
From: Jiri Pirko @ 2019-02-21 9:57 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, David S. Miller, Ido Schimmel, open list,
open list:STAGING SUBSYSTEM, moderated list:ETHERNET BRIDGE, jiri,
andrew, vivien.didelot
In-Reply-To: <20190221005826.26317-9-f.fainelli@gmail.com>
Thu, Feb 21, 2019 at 01:58:26AM CET, f.fainelli@gmail.com wrote:
>With the bridge no longer calling switchdev_port_attr_get() to obtain
>the supported bridge port flags from a driver but instead trying to set
>the bridge port flags directly and relying on driver to reject
>unsupported configurations, we can effectively get rid of
>switchdev_port_attr_get() entirely since this was the only place where
>it was called.
>
>Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Thanks!
^ permalink raw reply
* Re: [RFC PATCH net-next v3 15/21] ethtool: provide link settings and link modes in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-21 10:14 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <f2f8ccdd-c8bb-7f0a-5df7-dd54359e859e@gmail.com>
On Wed, Feb 20, 2019 at 07:14:50PM -0800, Florian Fainelli wrote:
> On 2/18/2019 10:22 AM, Michal Kubecek wrote:
> > +#define ETH_SETTINGS_IM_LINKINFO 0x01
> > +#define ETH_SETTINGS_IM_LINKMODES 0x02
> > +
> > +#define ETH_SETTINGS_IM_ALL 0x03
>
> You could define ETH_SETTINGS_IM_ALL as:
>
> #define ETH_SETTING_IM_ALL \
> (ETH_SETTINGS_IM_LINKINFO |
> ETH_SETTINGS_IM_LINMODES)
>
> that would scale better IMHO, especially given that you have to keep
> bumping that mask with new bits in subsequent patches.
I'm considering going even further and using something similar to what
is used for NETIF_F_* constants so that the *_ALL value would be
calculated automatically. But I'm not sure if it's not too fancy for
a uapi header file.
> > + if (tb[ETHA_SETTINGS_INFOMASK])
> > + req_info->req_mask = nla_get_u32(tb[ETHA_SETTINGS_INFOMASK]);
> > + if (tb[ETHA_SETTINGS_COMPACT])
> > + req_info->compact = true;
> > + if (req_info->req_mask == 0)
> > + req_info->req_mask = ETH_SETTINGS_IM_ALL;
>
> What if userland is newer than the kernel and specifies a req_mask with
> bits set that you don't support? Should not you always do an &
> ETH_SETTINGS_IM_ALL here?
In that case only known bits would be handled and the check at the end
of prepare_info() would add a warning to extack that part of the
information couldn't be provided (same as if some of the recognized
parts didn't have necessary ethtool_ops handlers or if they failed).
Michal
^ permalink raw reply
* [PATCH net v2 0/2] ipv6: route: enforce RCU protection for fib6_info->from
From: Paolo Abeni @ 2019-02-21 10:19 UTC (permalink / raw)
To: netdev; +Cc: David Ahern, David S. Miller
This series addresses a couple of RCU left-over dating back to rt6_info->from
conversion to RCU
v1 -> v2:
- fix a possible race in patch 1
Paolo Abeni (2):
ipv6: route: enforce RCU protection in rt6_update_exception_stamp_rt()
ipv6: route: enforce RCU protection in ip6_route_check_nh_onlink()
net/ipv6/route.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
--
2.20.1
^ permalink raw reply
* [PATCH net v2 2/2] ipv6: route: enforce RCU protection in ip6_route_check_nh_onlink()
From: Paolo Abeni @ 2019-02-21 10:19 UTC (permalink / raw)
To: netdev; +Cc: David Ahern, David S. Miller
In-Reply-To: <cover.1550684182.git.pabeni@redhat.com>
We need a RCU critical section around rt6_info->from deference, and
proper annotation.
Fixes: 4ed591c8ab44 ("net/ipv6: Allow onlink routes to have a device mismatch if it is the default route")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
net/ipv6/route.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 1597a3746b40..047c47224dba 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2754,20 +2754,24 @@ static int ip6_route_check_nh_onlink(struct net *net,
u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
const struct in6_addr *gw_addr = &cfg->fc_gateway;
u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
+ struct fib6_info *from;
struct rt6_info *grt;
int err;
err = 0;
grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
if (grt) {
+ rcu_read_lock();
+ from = rcu_dereference(grt->from);
if (!grt->dst.error &&
/* ignore match if it is the default route */
- grt->from && !ipv6_addr_any(&grt->from->fib6_dst.addr) &&
+ from && !ipv6_addr_any(&from->fib6_dst.addr) &&
(grt->rt6i_flags & flags || dev != grt->dst.dev)) {
NL_SET_ERR_MSG(extack,
"Nexthop has invalid gateway or device mismatch");
err = -EINVAL;
}
+ rcu_read_unlock();
ip6_rt_put(grt);
}
--
2.20.1
^ permalink raw reply related
* [PATCH net v2 1/2] ipv6: route: enforce RCU protection in rt6_update_exception_stamp_rt()
From: Paolo Abeni @ 2019-02-21 10:19 UTC (permalink / raw)
To: netdev; +Cc: David Ahern, David S. Miller
In-Reply-To: <cover.1550684182.git.pabeni@redhat.com>
We must access rt6_info->from under RCU read lock: move the
dereference under such lock, with proper annotation.
v1 -> v2:
- avoid using multiple, racy, fetch operations for rt->from
Fixes: a68886a69180 ("net/ipv6: Make from in rt6_info rcu protected")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
net/ipv6/route.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index bd09abd1fb22..1597a3746b40 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1610,15 +1610,15 @@ static int rt6_remove_exception_rt(struct rt6_info *rt)
static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
{
struct rt6_exception_bucket *bucket;
- struct fib6_info *from = rt->from;
struct in6_addr *src_key = NULL;
struct rt6_exception *rt6_ex;
-
- if (!from ||
- !(rt->rt6i_flags & RTF_CACHE))
- return;
+ struct fib6_info *from;
rcu_read_lock();
+ from = rcu_dereference(rt->from);
+ if (!from || !(rt->rt6i_flags & RTF_CACHE))
+ goto unlock;
+
bucket = rcu_dereference(from->rt6i_exception_bucket);
#ifdef CONFIG_IPV6_SUBTREES
@@ -1637,6 +1637,7 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
if (rt6_ex)
rt6_ex->stamp = jiffies;
+unlock:
rcu_read_unlock();
}
--
2.20.1
^ permalink raw reply related
* Re: mlx5 stable backport help
From: Or Gerlitz @ 2019-02-21 10:21 UTC (permalink / raw)
To: Saeed Mahameed; +Cc: davem@davemloft.net, netdev@vger.kernel.org, Or Gerlitz
In-Reply-To: <33b67a2b9a67bc9fe307edc0a3eeeab875598a09.camel@mellanox.com>
On Wed, Feb 20, 2019 at 10:03 PM Saeed Mahameed <saeedm@mellanox.com> wrote:
> On Tue, 2019-02-19 at 22:36 -0800, David Miller wrote:
>> I need help backporting two changes for -stable. Namely:
> Hi Dave Thanks for trying,
here too
> > 6707f74be8621ae067d2cf1c4485900e2742c20f ("net/mlx5e: Update hw flows
> > when encap source mac changed")
>
> The fixes tag of the above commit is wrong and it should have been
>
> commit e32ee6c78efa6a32bff782bbe7a9970b018996ca
> Author: Eli Britstein <elibr@mellanox.com>
> Date: Mon Dec 3 17:09:54 2018 +0200
>
> net/mlx5e: Support tunnel encap over tagged Ethernet
>
> Before this patch we didn't have the support for "tunnel encap over
> tagged Ethernet" which introduced the whole route_dev logic to generate
> the encap headers, so the patch should only exist in -rc, let's just skip it.
Hi Saeed,
The issue exists prior to the commit you mentioned, we are doing this
code since day one of
tc tunnel offloads support which lacked the neigh update flow
linux-stable.git]# git grep -pe "eth->h_source"
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c=static void
gen_vxlan_header_ipv4(struct net_device *out_dev,
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c:
ether_addr_copy(eth->h_source, out_dev->dev_addr);
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c=static void
gen_vxlan_header_ipv6(struct net_device *out_dev,
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c:
ether_addr_copy(eth->h_source, out_dev->dev_addr);
later when 232c001398ae ("net/mlx5e: Add support to neighbour update
flow") was done, we went short
and did not address the case of source address change. Until the
commit you mentioned, we didn't have the
out_dev vs route_dev notion, but the problem exists and it's possible
to backport the patch by
[1] using e->out_dev instead of e->route_dev
[2] use the hunks from mlx5e_tc_tun_create_header_ipv4/6() in
mlx5e_create_encap_header_ipv4/6()
Or.
^ permalink raw reply
* Re: [PATCH net-next 1/7] net: phy: marvell10g: Use get_features to get the PHY abilities
From: Russell King - ARM Linux admin @ 2019-02-21 10:22 UTC (permalink / raw)
To: Maxime Chevallier
Cc: davem, netdev, linux-kernel, Andrew Lunn, Florian Fainelli,
Heiner Kallweit, linux-arm-kernel, Antoine Tenart,
thomas.petazzoni, gregory.clement, miquel.raynal, nadavh, stefanc,
mw
In-Reply-To: <20190221095128.28188-2-maxime.chevallier@bootlin.com>
On Thu, Feb 21, 2019 at 10:51:22AM +0100, Maxime Chevallier wrote:
> The Alaska family of 10G PHYs has more abilities than the ones listed in
> PHY_10GBIT_FULL_FEATURES, the exact list depending on the model.
>
> Make use of the newly introduced .get_features call to build this list,
> using genphy_c45_pma_read_abilities to build the list of supported
> linkmodes, and adding autoneg ability based on what's reported by the AN
> MMD.
>
> .config_init is still used to validate the interface_mode.
>
> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
> ---
> drivers/net/phy/marvell10g.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
> index 9ea27acf05ad..65ef469adf58 100644
> --- a/drivers/net/phy/marvell10g.c
> +++ b/drivers/net/phy/marvell10g.c
> @@ -233,8 +233,6 @@ static int mv3310_resume(struct phy_device *phydev)
>
> static int mv3310_config_init(struct phy_device *phydev)
> {
> - int ret, val;
> -
> /* Check that the PHY interface type is compatible */
> if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
> phydev->interface != PHY_INTERFACE_MODE_XAUI &&
> @@ -242,6 +240,12 @@ static int mv3310_config_init(struct phy_device *phydev)
> phydev->interface != PHY_INTERFACE_MODE_10GKR)
> return -ENODEV;
>
> + return 0;
> +}
> +
> +static int mv3310_get_features(struct phy_device *phydev)
> +{
> + int ret, val;
Please try to keep the formatting/style consistent in the file you are
editing. A blank line here would do that. Thanks.
> if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
> val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
> if (val < 0)
> @@ -429,7 +433,7 @@ static struct phy_driver mv3310_drivers[] = {
> .phy_id = 0x002b09aa,
> .phy_id_mask = MARVELL_PHY_ID_MASK,
> .name = "mv88x3310",
> - .features = PHY_10GBIT_FEATURES,
> + .get_features = mv3310_get_features,
> .soft_reset = gen10g_no_soft_reset,
> .config_init = mv3310_config_init,
> .probe = mv3310_probe,
> --
> 2.19.2
>
>
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
^ permalink raw reply
* [PATCH net-next v4 0/2] net: phy: at803x: Update delays for RGMII modes
From: Vinod Koul @ 2019-02-21 10:23 UTC (permalink / raw)
To: David S Miller
Cc: linux-arm-msm, Bjorn Andersson, Vinod Koul, netdev, Niklas Cassel,
Andrew Lunn, Florian Fainelli, Nori, Sekhar, Peter Ujfalusi,
Marc Gonzalez
Peter[1] reported that patch cd28d1d6e52e: ("net: phy: at803x: Disable
phy delay for RGMII mode") caused regression on am335x-evmsk board.
This board expects the Phy delay to be enabled but specified RGMII mode
which refers to delays being disabled. So fix this by disabling delay only
for RGMII mode and enable for RGMII_ID and RGMII_TXID/RXID modes.
While at it, as pointed by Dave, don't inline the helpers.
[1]: https://www.spinics.net/lists/netdev/msg550749.html
Changes in v4:
- fix log & comments nbased on Marc's feedback
Vinod Koul (2):
net: phy: at803x: don't inline helpers
net: phy: at803x: disable delay only for RGMII mode
drivers/net/phy/at803x.c | 57 +++++++++++++++++++++++++++++++---------
1 file changed, 44 insertions(+), 13 deletions(-)
--
2.20.1
^ permalink raw reply
* [PATCH net-next v4 1/2] net: phy: at803x: don't inline helpers
From: Vinod Koul @ 2019-02-21 10:23 UTC (permalink / raw)
To: David S Miller
Cc: linux-arm-msm, Bjorn Andersson, Vinod Koul, netdev, Niklas Cassel,
Andrew Lunn, Florian Fainelli, Nori, Sekhar, Peter Ujfalusi,
Marc Gonzalez, Peter Ujfalusi
In-Reply-To: <20190221102315.12946-1-vkoul@kernel.org>
Some helpers were declared with the "inline" function specifier.
It is preferable to let the compiler pick the right optimizations,
so drop the specifier for at803x_disable_rx_delay() and
at803x_disable_tx_delay()
Reviewed-by: Niklas Cassel <niklas.cassel@linaro.org>
Tested-by: Peter Ujfalusi <peter.ujflausi@ti.com>
Reviewed-by: Marc Gonzalez <marc.w.gonzalez@free.fr>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/net/phy/at803x.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 8ff12938ab47..c6e7d800fd7a 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -110,13 +110,13 @@ static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
return phy_write(phydev, AT803X_DEBUG_DATA, val);
}
-static inline int at803x_disable_rx_delay(struct phy_device *phydev)
+static int at803x_disable_rx_delay(struct phy_device *phydev)
{
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
AT803X_DEBUG_RX_CLK_DLY_EN, 0);
}
-static inline int at803x_disable_tx_delay(struct phy_device *phydev)
+static int at803x_disable_tx_delay(struct phy_device *phydev)
{
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
--
2.20.1
^ permalink raw reply related
* [PATCH net-next v4 2/2] net: phy: at803x: disable delay only for RGMII mode
From: Vinod Koul @ 2019-02-21 10:23 UTC (permalink / raw)
To: David S Miller
Cc: linux-arm-msm, Bjorn Andersson, Vinod Koul, netdev, Niklas Cassel,
Andrew Lunn, Florian Fainelli, Nori, Sekhar, Peter Ujfalusi,
Marc Gonzalez, Peter Ujfalusi
In-Reply-To: <20190221102315.12946-1-vkoul@kernel.org>
Per "Documentation/devicetree/bindings/net/ethernet.txt" RGMII mode
should not have delay in PHY whereas RGMII_ID and RGMII_RXID/RGMII_TXID
can have delay in PHY.
So disable the delay only for RGMII mode and enable for other modes.
Also treat the default case as disabled delays.
Fixes: cd28d1d6e52e: ("net: phy: at803x: Disable phy delay for RGMII mode")
Reported-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Reviewed-by: Niklas Cassel <niklas.cassel@linaro.org>
Tested-by: Peter Ujfalusi <peter.ujflausi@ti.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/net/phy/at803x.c | 53 +++++++++++++++++++++++++++++++---------
1 file changed, 42 insertions(+), 11 deletions(-)
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index c6e7d800fd7a..a37532aac4b4 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -110,6 +110,18 @@ static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
return phy_write(phydev, AT803X_DEBUG_DATA, val);
}
+static int at803x_enable_rx_delay(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
+ AT803X_DEBUG_RX_CLK_DLY_EN);
+}
+
+static int at803x_enable_tx_delay(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
+ AT803X_DEBUG_TX_CLK_DLY_EN);
+}
+
static int at803x_disable_rx_delay(struct phy_device *phydev)
{
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
@@ -255,23 +267,42 @@ static int at803x_config_init(struct phy_device *phydev)
if (ret < 0)
return ret;
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
- phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- phydev->interface == PHY_INTERFACE_MODE_RGMII) {
- ret = at803x_disable_rx_delay(phydev);
+ /* The RX and TX delay default is:
+ * after HW reset: RX delay enabled and TX delay disabled
+ * after SW reset: RX delay enabled, while TX delay retains the
+ * value before reset.
+ *
+ * So let's first disable the RX and TX delays in PHY and enable
+ * them based on the mode selected (this also takes care of RGMII
+ * mode where we expect delays to be disabled)
+ */
+
+ ret = at803x_disable_rx_delay(phydev);
+ if (ret < 0)
+ return ret;
+ ret = at803x_disable_tx_delay(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ /* If RGMII_ID or RGMII_RXID are specified enable RX delay,
+ * otherwise keep it disabled
+ */
+ ret = at803x_enable_rx_delay(phydev);
if (ret < 0)
return ret;
}
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
- phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- phydev->interface == PHY_INTERFACE_MODE_RGMII) {
- ret = at803x_disable_tx_delay(phydev);
- if (ret < 0)
- return ret;
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ /* If RGMII_ID or RGMII_TXID are specified enable TX delay,
+ * otherwise keep it disabled
+ */
+ ret = at803x_enable_tx_delay(phydev);
}
- return 0;
+ return ret;
}
static int at803x_ack_interrupt(struct phy_device *phydev)
--
2.20.1
^ permalink raw reply related
* Re: [PATCH RESEND net] net: phy: xgmiitorgmii: Support generic PHY status read
From: Paul Kocialkowski @ 2019-02-21 10:24 UTC (permalink / raw)
To: Michal Simek, Andrew Lunn
Cc: Florian Fainelli, netdev, linux-arm-kernel, linux-kernel,
David S . Miller, Thomas Petazzoni, Heiner Kallweit
In-Reply-To: <f0020e39-7ace-e1e0-e629-b84d6f92b841@xilinx.com>
Hi,
On Wed, 2019-02-20 at 07:58 +0100, Michal Simek wrote:
> Hi,
>
> On 19. 02. 19 18:25, Andrew Lunn wrote:
> > > Thanks for the suggestion! So I had a closer look at that driver to try
> > > and see what could go wrong and it looks like I found a few things
> > > there.
> >
> > Hi Paul
> >
> > Yes, this driver has issues. If i remember correctly, it got merged
> > while i was on vacation. I pointed out a few issues, but the authors
> > never responded. Feel free to fix it up.
>
> Will be good to know who was that person.
>
> I can't do much this week with this because responsible person for this
> driver is out of office this week. That's why please give us some time
> to get back to this.
Understood. I think we need to start a discussion about how the general
design of this driver can be improved.
In particular, I wonder if it could work better to make this driver a
PHY driver that just redirects all its ops to the actual PHY driver,
except for read_status where it should also add some code.
Maybe we could also manage to expose a RGMII PHY mode to the actual PHY
this way. Currently, the PHY mode has to be set to GMII for the MAC to
be configured correctly, but the PHY also gets this information while
it should be told that RGMII is in use. This doesn't seem to play a big
role in PHY configuration though, but it's still inadequate.
What do you think?
--
Paul Kocialkowski, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH net-next 1/7] net: phy: marvell10g: Use get_features to get the PHY abilities
From: Maxime Chevallier @ 2019-02-21 10:31 UTC (permalink / raw)
To: Russell King - ARM Linux admin
Cc: davem, netdev, linux-kernel, Andrew Lunn, Florian Fainelli,
Heiner Kallweit, linux-arm-kernel, Antoine Tenart,
thomas.petazzoni, gregory.clement, miquel.raynal, nadavh, stefanc,
mw
In-Reply-To: <20190221102215.jg7bsxfdjkqrf6xn@shell.armlinux.org.uk>
Hello Russell,
On Thu, 21 Feb 2019 10:22:15 +0000
Russell King - ARM Linux admin <linux@armlinux.org.uk> wrote:
>> + return 0;
>> +}
>> +
>> +static int mv3310_get_features(struct phy_device *phydev)
>> +{
>> + int ret, val;
>
>Please try to keep the formatting/style consistent in the file you are
>editing. A blank line here would do that. Thanks.
Sorry, I missed that (and so did checkpatch apparently). I'll send a V2.
Thanks,
Maxime
^ permalink raw reply
* Re: KASAN: use-after-free Read in br_mdb_ip_get
From: Dmitry Vyukov @ 2019-02-21 10:54 UTC (permalink / raw)
To: Herbert Xu
Cc: Nikolay Aleksandrov, Thomas Graf, syzbot, bridge, David Miller,
LKML, netdev, Roopa Prabhu, syzkaller-bugs
In-Reply-To: <20190220102327.lq2zyqups2fso75z@gondor.apana.org.au>
On Wed, Feb 20, 2019 at 11:23 AM Herbert Xu <herbert@gondor.apana.org.au> wrote:
>
> On Mon, Jan 28, 2019 at 09:28:36AM +0100, Dmitry Vyukov wrote:
> >
> > > Weird, this is the kfree() on the error path of br_multicast_new_group()
> > > when rhashtable_lookup_insert_fast() fails, which means the entry should
> > > not be linked in the rhashtable or the hlist.
> > > All other frees are via kfree_rcu. I'll keep looking..
> >
> > Humm.... +rhashtable.c maintianers
> >
> > The code in br_multicast_new_group is effectively:
> >
> > mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
> > err = rhashtable_lookup_insert_fast(&br->mdb_hash_tbl, &mp->rhnode,
> > br_mdb_rht_params);
> > if (err)
> > kfree(mp);
> >
> > So it looks like rhashtable_lookup_insert_fast both returned an error
> > and left the new object linked in the table. Since it happened only
> > once, it may have something to do with concurrent resizing/shrinking.
>
> I've looked through the rhashtable code in question and everything
> looks OK. So I suspect some earlier corruption has occured to cause
> this anomalous result.
Taking into account that this still happened only once, I tend to
write it off onto a previous silent memory corruption (we have dozens
of known bugs that corrupt memory). So if several people already
looked at it and don't see the root cause, it's probably time to stop
spending time on this until we have more info.
Although, there was also this one:
https://groups.google.com/d/msg/syzkaller-bugs/QfCCSxdB1aM/y2cn9IZJCwAJ
I have not checked if it can be the root cause of this report, but it
points suspiciously close to this stack and when I looked at it, it
the report looked legit.
> Is it possible to collect earlier alloc/free stack traces on the object in question?
You mean even before the alloc/free of the current incarnation this
object? This looks challenging from memory consumption point of view.
Also how many of them will we print in reports? Also the page can go
through page_alloc and then tracking will be even more challenging.
And in the end the object can be corrupted by an out-of-bounds write
or a like. Heap object reuse quarantine should take care of the common
case, and I don't see a reasonable way to handle all possible corner
cases...
^ permalink raw reply
* m88e6390_config_aneg will always reset the phy
From: Rundong Ge @ 2019-02-21 10:55 UTC (permalink / raw)
To: Andrew Lunn; +Cc: Florian Fainelli, hkallweit1, davem, netdev, linux-kernel
Hi Andrew
Before the "net: phy: marvell: Errata for mv88e6390 internal PHYs",
phydev will only be soft reset when register value was changed.
But after this patch, the phydev will always be reset when entering
the "m88e6390_config_aneg".
So is there any side effect of this change?
Thanks
Rundong
^ permalink raw reply
* Re: KMSAN: uninit-value in br_mdb_ip_get
From: Dmitry Vyukov @ 2019-02-21 10:56 UTC (permalink / raw)
To: syzbot
Cc: bridge, David Miller, Alexander Potapenko, LKML, netdev,
Nikolay Aleksandrov, Roopa Prabhu, syzkaller-bugs, Herbert Xu
In-Reply-To: <00000000000047d84e058089773f@google.com>
On Mon, Jan 28, 2019 at 8:13 PM syzbot
<syzbot+8dfe5ee27aa6d2e396c2@syzkaller.appspotmail.com> wrote:
>
> Hello,
>
> syzbot found the following crash on:
>
> HEAD commit: 02f2d5aea531 kmsan: (presumably) fix dma_map_page_attrs()
> git tree: kmsan
> console output: https://syzkaller.appspot.com/x/log.txt?x=173a7310c00000
> kernel config: https://syzkaller.appspot.com/x/.config?x=52c9737ec5618f82
> dashboard link: https://syzkaller.appspot.com/bug?extid=8dfe5ee27aa6d2e396c2
> compiler: clang version 8.0.0 (trunk 350509)
>
> Unfortunately, I don't have any reproducer for this crash yet.
>
> IMPORTANT: if you fix the bug, please add the following tag to the commit:
> Reported-by: syzbot+8dfe5ee27aa6d2e396c2@syzkaller.appspotmail.com
There is also a use-after-free reported at around the same stack:
https://groups.google.com/forum/#!topic/syzkaller-bugs/8V7VqxxTEzc
The question is: can these reports be related? One is root cause of another?
> ==================================================================
> BUG: KMSAN: uninit-value in __rhashtable_lookup
> include/linux/rhashtable.h:505 [inline]
> BUG: KMSAN: uninit-value in rhashtable_lookup
> include/linux/rhashtable.h:534 [inline]
> BUG: KMSAN: uninit-value in br_mdb_ip_get+0x52b/0x740
> net/bridge/br_multicast.c:97
> CPU: 0 PID: 11379 Comm: udevd Not tainted 5.0.0-rc1+ #7
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
> Google 01/01/2011
> Call Trace:
> <IRQ>
> __dump_stack lib/dump_stack.c:77 [inline]
> dump_stack+0x173/0x1d0 lib/dump_stack.c:113
> kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:600
> __msan_warning+0x82/0xf0 mm/kmsan/kmsan_instr.c:313
> __rhashtable_lookup include/linux/rhashtable.h:505 [inline]
> rhashtable_lookup include/linux/rhashtable.h:534 [inline]
> br_mdb_ip_get+0x52b/0x740 net/bridge/br_multicast.c:97
> br_multicast_new_group+0xa7/0x1640 net/bridge/br_multicast.c:467
> br_multicast_add_group+0x242/0xf00 net/bridge/br_multicast.c:552
> br_ip4_multicast_add_group net/bridge/br_multicast.c:606 [inline]
> br_ip4_multicast_igmp3_report net/bridge/br_multicast.c:972 [inline]
> br_multicast_ipv4_rcv net/bridge/br_multicast.c:1615 [inline]
> br_multicast_rcv+0x3a88/0x6560 net/bridge/br_multicast.c:1701
> br_dev_xmit+0xbc5/0x16a0 net/bridge/br_device.c:93
> __netdev_start_xmit include/linux/netdevice.h:4382 [inline]
> netdev_start_xmit include/linux/netdevice.h:4391 [inline]
> xmit_one net/core/dev.c:3278 [inline]
> dev_hard_start_xmit+0x604/0xc40 net/core/dev.c:3294
> __dev_queue_xmit+0x2e48/0x3b80 net/core/dev.c:3864
> dev_queue_xmit+0x4b/0x60 net/core/dev.c:3897
> neigh_hh_output include/net/neighbour.h:498 [inline]
> neigh_output include/net/neighbour.h:506 [inline]
> ip_finish_output2+0x156d/0x1820 net/ipv4/ip_output.c:229
> ip_finish_output+0xd2b/0xfd0 net/ipv4/ip_output.c:317
> NF_HOOK_COND include/linux/netfilter.h:278 [inline]
> ip_output+0x53f/0x610 net/ipv4/ip_output.c:405
> dst_output include/net/dst.h:444 [inline]
> ip_local_out+0x164/0x1d0 net/ipv4/ip_output.c:124
> igmpv3_sendpack net/ipv4/igmp.c:417 [inline]
> igmpv3_send_cr net/ipv4/igmp.c:705 [inline]
> igmp_ifc_timer_expire+0x12cb/0x1aa0 net/ipv4/igmp.c:793
> call_timer_fn+0x285/0x600 kernel/time/timer.c:1325
> expire_timers kernel/time/timer.c:1362 [inline]
> __run_timers+0xdb4/0x11d0 kernel/time/timer.c:1681
> run_timer_softirq+0x2e/0x50 kernel/time/timer.c:1694
> __do_softirq+0x53f/0x93a kernel/softirq.c:293
> invoke_softirq kernel/softirq.c:375 [inline]
> irq_exit+0x214/0x250 kernel/softirq.c:416
> exiting_irq+0xe/0x10 arch/x86/include/asm/apic.h:536
> smp_apic_timer_interrupt+0x48/0x70 arch/x86/kernel/apic/apic.c:1064
> apic_timer_interrupt+0x2e/0x40 arch/x86/entry/entry_64.S:814
> </IRQ>
> RIP: 0010:__msan_chain_origin+0x93/0xe0 mm/kmsan/kmsan_instr.c:201
> Code: 89 f7 e8 f0 e0 ff ff 89 c3 65 ff 0c 25 04 90 03 00 65 8b 04 25 04 90
> 03 00 85 c0 75 30 e8 f5 a2 3f ff 4c 89 7d d0 ff 75 d0 9d <65> 48 8b 04 25
> 28 00 00 00 48 3b 45 e0 75 0d 89 d8 48 83 c4 18 5b
> RSP: 0018:ffff8880a53cf6f0 EFLAGS: 00000246 ORIG_RAX: ffffffffffffff13
> RAX: 0000000000000000 RBX: 00000000a06000af RCX: c7641d3373f0d000
> RDX: 0000000000000003 RSI: 0000000000480020 RDI: 0000000085c0000c
> RBP: ffff8880a53cf720 R08: 0000000000000003 R09: ffff8880a53cf4ac
> R10: ffffffff8ae01788 R11: 0000000000000000 R12: ffff8880a53cfcd0
> R13: ffff8880a53cfcc8 R14: 0000000085c0000c R15: 0000000000000246
> step_into+0x70c/0x1b90 fs/namei.c:1778
> walk_component+0x1d0/0xba0 fs/namei.c:1829
> link_path_walk+0xa9e/0x2160 fs/namei.c:2135
> path_openat+0x30e/0x6b90 fs/namei.c:3533
> do_filp_open+0x2b8/0x710 fs/namei.c:3564
> do_sys_open+0x642/0xa30 fs/open.c:1063
> __do_sys_open fs/open.c:1081 [inline]
> __se_sys_open+0xad/0xc0 fs/open.c:1076
> __x64_sys_open+0x4a/0x70 fs/open.c:1076
> do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291
> entry_SYSCALL_64_after_hwframe+0x63/0xe7
> RIP: 0033:0x7f4526cc5120
> Code: 48 8b 15 1b 4d 2b 00 f7 d8 64 89 02 83 c8 ff c3 90 90 90 90 90 90 90
> 90 90 90 83 3d d5 a4 2b 00 00 75 10 b8 02 00 00 00 0f 05 <48> 3d 01 f0 ff
> ff 73 31 c3 48 83 ec 08 e8 5e 8c 01 00 48 89 04 24
> RSP: 002b:00007ffdb010be48 EFLAGS: 00000246 ORIG_RAX: 0000000000000002
> RAX: ffffffffffffffda RBX: 0000000000ee2fd0 RCX: 00007f4526cc5120
> RDX: 00000000000001b6 RSI: 0000000000080000 RDI: 00007ffdb010bf20
> RBP: 00007ffdb010bec0 R08: 0000000000000008 R09: 0000000000000001
> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000008
> R13: 000000000041f57a R14: 0000000000ed3250 R15: 000000000000000b
>
> Local variable description: ----br_group.i.i@br_multicast_rcv
> Variable was created at:
> br_multicast_rcv+0x1e7/0x6560 net/bridge/br_multicast.c:1690
> br_dev_xmit+0xbc5/0x16a0 net/bridge/br_device.c:93
> ==================================================================
>
>
> ---
> This bug is generated by a bot. It may contain errors.
> See https://goo.gl/tpsmEJ for more information about syzbot.
> syzbot engineers can be reached at syzkaller@googlegroups.com.
>
> syzbot will keep track of this bug report. See:
> https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with
> syzbot.
>
> --
> You received this message because you are subscribed to the Google Groups "syzkaller-bugs" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to syzkaller-bugs+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/syzkaller-bugs/00000000000047d84e058089773f%40google.com.
> For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH] tcp: Reset tcp connections in SYN-SENT state
From: Devi Sandeep Endluri V V @ 2019-02-21 11:01 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, subashab, sharathv, ssaha, stranche
In-Reply-To: <CANn89iJPgzWWor7YeGZvVH92gbJmD96Nwi=1pjfbXO8AgsjyNA@mail.gmail.com>
On Wed, Feb 20, 2019 at 07:47:59AM -0800, Eric Dumazet wrote:
> On Wed, Feb 20, 2019 at 6:28 AM Devi Sandeep Endluri V V
> <dendluri@codeaurora.org> wrote:
> >
> > Userspace sends tcp connection (sock) destroy on network permission
> > change. Kernel though doesn't send reset for the connections in
> > SYN-SENT state and these connections continue to remain. Even as
> > per RFC 793, there is no hard rule to not send RST on ABORT in
> > this state. Change to make sure RST are send for connections in
> > syn-sent state to avoid lingering connections on network switch.
> >
> > References from RFC 793
> >
> > ABORT Call
> >
> > SYN-SENT STATE
> >
> > All queued SENDs and RECEIVEs should be given "connection reset"
> > notification, delete the TCB, enter CLOSED state, and return.
> >
> > SEGMENT ARRIVES
> >
> > If the state is SYN-SENT then
> > If the RST bit is set
> >
> > If the ACK was acceptable then signal the user "error:
> > connection reset", drop the segment, enter CLOSED state,
> > delete TCB, and return. Otherwise (no ACK) drop the segment
> > and return.
> >
> > Signed-off-by: Devi Sandeep Endluri V V <dendluri@codeaurora.org>
> > ---
> > net/ipv4/tcp.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git net/ipv4/tcp.c net/ipv4/tcp.c
> > index cf3c509..8569dc5e 100644
> > --- net/ipv4/tcp.c
> > +++ net/ipv4/tcp.c
> > @@ -2495,7 +2495,7 @@ static inline bool tcp_need_reset(int state)
> > {
> > return (1 << state) &
> > (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 |
> > - TCPF_FIN_WAIT2 | TCPF_SYN_RECV);
> > + TCPF_FIN_WAIT2 | TCPF_SYN_RECV | TCPF_SYN_SENT);
> > }
> >
> > static void tcp_rtx_queue_purge(struct sock *sk)
>
> Hi
>
> 1) I do not believe this patch is complete :
> You have not changed tcp_disconnect() which seems to have dead code
> if we apply your patch.
>
> 2) I am not sure we want to send yet another packet if the prior SYN
> packets elect no answer.
> (It is not clear if your patch applies to this case)
>
> 3) If we do not RESET, the other side has not seen the 3rd packet and
> should eventually exit from SYN_RECV state and die.
>
> 4) A RESET can be lost on the network, and nothing will retransmit it.
>
> Can you describe the use case more precisely, because it seems in
> contradiction of a feature that we plan to upstream.
> (TCP_SILENT_CLOSE : do not send flood of RST/FIN when a gigantic
> server process prematurely dies)
>
> Thanks.
The algorithm for our network switch needs to have all TCP sessions
on the previous network cleaned up. So, we are trying to reset the
connections in SYN-SENT state as well. Is there any other way to
forcefully reset these connections immediately rather than waiting
for the other side to eventually exit and die?
^ permalink raw reply
* Re: [PATCH RESEND net] net: phy: xgmiitorgmii: Support generic PHY status read
From: Michal Simek @ 2019-02-21 11:03 UTC (permalink / raw)
To: Paul Kocialkowski, Michal Simek, Andrew Lunn
Cc: Florian Fainelli, netdev, linux-arm-kernel, linux-kernel,
David S . Miller, Thomas Petazzoni, Heiner Kallweit
In-Reply-To: <adbb183836e22dfc4558beaa818677c24bacf3a8.camel@bootlin.com>
On 21. 02. 19 11:24, Paul Kocialkowski wrote:
> Hi,
>
> On Wed, 2019-02-20 at 07:58 +0100, Michal Simek wrote:
>> Hi,
>>
>> On 19. 02. 19 18:25, Andrew Lunn wrote:
>>>> Thanks for the suggestion! So I had a closer look at that driver to try
>>>> and see what could go wrong and it looks like I found a few things
>>>> there.
>>>
>>> Hi Paul
>>>
>>> Yes, this driver has issues. If i remember correctly, it got merged
>>> while i was on vacation. I pointed out a few issues, but the authors
>>> never responded. Feel free to fix it up.
>>
>> Will be good to know who was that person.
>>
>> I can't do much this week with this because responsible person for this
>> driver is out of office this week. That's why please give us some time
>> to get back to this.
>
> Understood. I think we need to start a discussion about how the general
> design of this driver can be improved.
>
> In particular, I wonder if it could work better to make this driver a
> PHY driver that just redirects all its ops to the actual PHY driver,
> except for read_status where it should also add some code.
I didn't take a look at Linux driver but it should work in a way that it
checks description (more below) and then wait for attached phy to do its
work and on the way back just setup this bridge based on that.
> Maybe we could also manage to expose a RGMII PHY mode to the actual PHY
> this way. Currently, the PHY mode has to be set to GMII for the MAC to
> be configured correctly, but the PHY also gets this information while
> it should be told that RGMII is in use. This doesn't seem to play a big
> role in PHY configuration though, but it's still inadequate.
>
> What do you think?
I stop the driver to be applied to u-boot because exactly this
gmii/rgmii configuration. There is a need that mac is configured to gmii
and this needs to be checked but to phy rgmii needs to be exposed.
I was trying to find out hardware design and board where I can do some
experiments but didn't find out. That's why I need to wait for
colleagues to point me to that.
Thanks,
Michal
^ permalink raw reply
* [patch iproute2 v2] devlink: relax dpipe table show dependency on resources
From: Jiri Pirko @ 2019-02-21 10:55 UTC (permalink / raw)
To: netdev; +Cc: stephen, dsahern, mlxsw
From: Jiri Pirko <jiri@mellanox.com>
Dpipe table show command has a depencency on getting resources.
If resource get command is not supported by the driver, dpipe table
show fails. However, resource is only additional information
in dpipe table show output. So relax the dependency and let
the dpipe tables be shown even if resources get command fails.
Fixes: ead180274caf ("devlink: Add support for resource/dpipe relation")
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
v1->v2:
- removed "!!"
---
devlink/devlink.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/devlink/devlink.c b/devlink/devlink.c
index 3651e90c1159..cced8d619f9f 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -4351,7 +4351,8 @@ static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
- resource_valid = !!nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID];
+ resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
+ ctx->resources;
if (resource_valid) {
table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
table->resource_valid = true;
@@ -4467,12 +4468,9 @@ static int cmd_dpipe_table_show(struct dl *dl)
dl_opts_put(nlh, dl);
err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
&resource_ctx);
- if (err) {
- pr_err("error get resources %s\n", strerror(resource_ctx.err));
- goto err_resource_dump;
- }
+ if (!err)
+ dpipe_ctx.resources = resource_ctx.resources;
- dpipe_ctx.resources = resource_ctx.resources;
flags = NLM_F_REQUEST | NLM_F_ACK;
nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
dl_opts_put(nlh, dl);
@@ -4485,8 +4483,6 @@ static int cmd_dpipe_table_show(struct dl *dl)
dpipe_ctx_fini(&dpipe_ctx);
return 0;
-err_resource_dump:
- resource_ctx_fini(&resource_ctx);
err_resource_ctx_init:
err_headers_get:
dpipe_ctx_fini(&dpipe_ctx);
--
2.14.5
^ permalink raw reply related
* linux-next: Fixes tags need some work in the net-next tree
From: Stephen Rothwell @ 2019-02-21 11:11 UTC (permalink / raw)
To: David Miller, Networking
Cc: Linux Next Mailing List, Linux Kernel Mailing List, Bodong Wang,
Saeed Mahameed
[-- Attachment #1: Type: text/plain, Size: 1140 bytes --]
Hi all,
In commit
1c50d369f560 ("net/mlx5: E-Switch, Disable esw manager vport correctly")
Fixes tag
Fixes: de9e6a8136c5 ("net/mlx5: E-Switch, Properly refer to host PF vport as other vport")
has these problem(s):
- Target SHA1 does not exist
Did you mean
Fixes: cbc44e76bfcd ("net/mlx5: E-Switch, Properly refer to host PF vport as other vport")
In commit
acad70731e63 ("net/mlx5: E-Switch, Fix the warning on vport index out of range")
Fixes tag
Fixes: 22b8ddc86bf4 ("net/mlx5: E-Switch, Assign a different position for uplink rep and vport")
has these problem(s):
- Target SHA1 does not exist
Did you mean
Fixes: 5ae5162066d8 ("net/mlx5: E-Switch, Assign a different position for uplink rep and vport")
In commit
e87636117e9a ("net/mlx5e: Remove unused variable ‘esw’")
Fixes tag
Fixes: 1cd3ab86b713 ("net/mlx5e: Introduce mlx5e_flow_esw_attr_init() helper")
has these problem(s):
- Target SHA1 does not exist
Did you mean
Fixes: 988ab9c7363a ("net/mlx5e: Introduce mlx5e_flow_esw_attr_init() helper")
--
Cheers,
Stephen Rothwell
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH net-next 1/2] xdp: Always use a devmap for XDP_REDIRECT to a device
From: Toke Høiland-Jørgensen @ 2019-02-21 11:56 UTC (permalink / raw)
To: David Miller
Cc: netdev, Jesper Dangaard Brouer, Daniel Borkmann,
Alexei Starovoitov
An XDP program can redirect packets between interfaces using either the
xdp_redirect() helper or the xdp_redirect_map() helper. Apart from the
flexibility of updating maps from userspace, the redirect_map() helper also
uses the map structure to batch packets, which results in a significant
(around 50%) performance boost. However, the xdp_redirect() API is simpler
if one just wants to redirect to another interface, which means people tend
to use this interface and then wonder why they getter worse performance
than expected.
This patch seeks to close this performance difference between the two APIs.
It achieves this by changing xdp_redirect() to use a hidden devmap for
looking up destination interfaces, thus gaining the batching benefit with
no visible difference from the user API point of view.
A hidden per-namespace map is allocated when an XDP program that uses the
non-map xdp_redirect() helper is first loaded. This map is populated with
all available interfaces in its namespace, and kept up to date as
interfaces come and go. Once allocated, the map is kept around until the
namespace is removed.
The hidden map uses the ifindex as map key, which means they are limited to
ifindexes smaller than the map size of 64. A later patch introduces a new
map type to lift this restriction.
Performance numbers:
Before patch:
xdp_redirect: 5426035 pkt/s
xdp_redirect_map: 8412754 pkt/s
After patch:
xdp_redirect: 8314702 pkt/s
xdp_redirect_map: 8411854 pkt/s
This corresponds to a 53% increase in xdp_redirect performance, or a
reduction in per-packet processing time by 64 nanoseconds.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
---
include/linux/bpf.h | 12 +++
include/net/net_namespace.h | 2 -
include/net/netns/xdp.h | 5 +
kernel/bpf/devmap.c | 159 +++++++++++++++++++++++++++++++++++--------
kernel/bpf/verifier.c | 6 ++
net/core/filter.c | 58 +---------------
6 files changed, 157 insertions(+), 85 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bd169a7bcc93..4f8f179df9fd 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -606,6 +606,8 @@ struct xdp_buff;
struct sk_buff;
struct bpf_dtab_netdev *__dev_map_lookup_elem(struct bpf_map *map, u32 key);
+struct bpf_map *__dev_map_get_default_map(struct net_device *dev);
+int dev_map_alloc_default_map(void);
void __dev_map_insert_ctx(struct bpf_map *map, u32 index);
void __dev_map_flush(struct bpf_map *map);
int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_buff *xdp,
@@ -687,6 +689,16 @@ static inline struct net_device *__dev_map_lookup_elem(struct bpf_map *map,
return NULL;
}
+static inline struct bpf_map *__dev_map_get_default_map(struct net_device *dev)
+{
+ return NULL;
+}
+
+static inline int dev_map_alloc_default_map(void)
+{
+ return 0;
+}
+
static inline void __dev_map_insert_ctx(struct bpf_map *map, u32 index)
{
}
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index a68ced28d8f4..6706ecc25d8f 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -162,7 +162,7 @@ struct net {
#if IS_ENABLED(CONFIG_CAN)
struct netns_can can;
#endif
-#ifdef CONFIG_XDP_SOCKETS
+#ifdef CONFIG_BPF_SYSCALL
struct netns_xdp xdp;
#endif
struct sock *diag_nlsk;
diff --git a/include/net/netns/xdp.h b/include/net/netns/xdp.h
index e5734261ba0a..4e2d6394b45d 100644
--- a/include/net/netns/xdp.h
+++ b/include/net/netns/xdp.h
@@ -5,9 +5,14 @@
#include <linux/rculist.h>
#include <linux/mutex.h>
+struct bpf_dtab;
+
struct netns_xdp {
+#ifdef CONFIG_XDP_SOCKETS
struct mutex lock;
struct hlist_head list;
+#endif
+ struct bpf_dtab *default_map;
};
#endif /* __NETNS_XDP_H__ */
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 191b79948424..425077664ac6 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -56,6 +56,7 @@
(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)
#define DEV_MAP_BULK_SIZE 16
+#define DEV_MAP_DEFAULT_SIZE 64
struct xdp_bulk_queue {
struct xdp_frame *q[DEV_MAP_BULK_SIZE];
struct net_device *dev_rx;
@@ -85,23 +86,11 @@ static u64 dev_map_bitmap_size(const union bpf_attr *attr)
return BITS_TO_LONGS((u64) attr->max_entries) * sizeof(unsigned long);
}
-static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
+static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr,
+ bool check_memlock)
{
- struct bpf_dtab *dtab;
- int err = -EINVAL;
u64 cost;
-
- if (!capable(CAP_NET_ADMIN))
- return ERR_PTR(-EPERM);
-
- /* check sanity of attributes */
- if (attr->max_entries == 0 || attr->key_size != 4 ||
- attr->value_size != 4 || attr->map_flags & ~DEV_CREATE_FLAG_MASK)
- return ERR_PTR(-EINVAL);
-
- dtab = kzalloc(sizeof(*dtab), GFP_USER);
- if (!dtab)
- return ERR_PTR(-ENOMEM);
+ int err;
bpf_map_init_from_attr(&dtab->map, attr);
@@ -109,39 +98,63 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
cost = (u64) dtab->map.max_entries * sizeof(struct bpf_dtab_netdev *);
cost += dev_map_bitmap_size(attr) * num_possible_cpus();
if (cost >= U32_MAX - PAGE_SIZE)
- goto free_dtab;
+ return -EINVAL;
dtab->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
- /* if map size is larger than memlock limit, reject it early */
- err = bpf_map_precharge_memlock(dtab->map.pages);
- if (err)
- goto free_dtab;
-
- err = -ENOMEM;
+ if (check_memlock) {
+ /* if map size is larger than memlock limit, reject it early */
+ err = bpf_map_precharge_memlock(dtab->map.pages);
+ if (err)
+ return -EINVAL;
+ }
/* A per cpu bitfield with a bit per possible net device */
dtab->flush_needed = __alloc_percpu_gfp(dev_map_bitmap_size(attr),
__alignof__(unsigned long),
GFP_KERNEL | __GFP_NOWARN);
if (!dtab->flush_needed)
- goto free_dtab;
+ return -ENOMEM;
dtab->netdev_map = bpf_map_area_alloc(dtab->map.max_entries *
sizeof(struct bpf_dtab_netdev *),
dtab->map.numa_node);
- if (!dtab->netdev_map)
- goto free_dtab;
+ if (!dtab->netdev_map) {
+ free_percpu(dtab->flush_needed);
+ return -ENOMEM;
+ }
spin_lock(&dev_map_lock);
list_add_tail_rcu(&dtab->list, &dev_map_list);
spin_unlock(&dev_map_lock);
+ return 0;
+}
+
+static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
+{
+ struct bpf_dtab *dtab;
+ int err = -EINVAL;
+
+ if (!capable(CAP_NET_ADMIN))
+ return ERR_PTR(-EPERM);
+
+ /* check sanity of attributes */
+ if (attr->max_entries == 0 || attr->key_size != 4 ||
+ attr->value_size != 4 || attr->map_flags & ~DEV_CREATE_FLAG_MASK)
+ return ERR_PTR(-EINVAL);
+
+ dtab = kzalloc(sizeof(*dtab), GFP_USER);
+ if (!dtab)
+ return ERR_PTR(-ENOMEM);
+
+ err = dev_map_init_map(dtab, attr, true);
+ if (err) {
+ kfree(dtab);
+ return ERR_PTR(err);
+ }
+
return &dtab->map;
-free_dtab:
- free_percpu(dtab->flush_needed);
- kfree(dtab);
- return ERR_PTR(err);
}
static void dev_map_free(struct bpf_map *map)
@@ -311,6 +324,17 @@ struct bpf_dtab_netdev *__dev_map_lookup_elem(struct bpf_map *map, u32 key)
return obj;
}
+/* This is only being called from xdp_do_redirect() if the xdp_redirect helper
+ * is used; the default map is allocated on XDP program load if the helper is
+ * used, so will always be available at this point.
+ */
+struct bpf_map *__dev_map_get_default_map(struct net_device *dev)
+{
+ struct net *net = dev_net(dev);
+
+ return &net->xdp.default_map->map;
+}
+
/* Runs under RCU-read-side, plus in softirq under NAPI protection.
* Thus, safe percpu variable access.
*/
@@ -496,10 +520,19 @@ static int dev_map_notification(struct notifier_block *notifier,
ulong event, void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct net *net = dev_net(netdev);
+ u32 idx = netdev->ifindex;
struct bpf_dtab *dtab;
int i;
switch (event) {
+ case NETDEV_REGISTER:
+ rcu_read_lock();
+ dtab = READ_ONCE(net->xdp.default_map);
+ if (dtab)
+ dev_map_update_elem(&dtab->map, &idx, &idx, 0);
+ rcu_read_unlock();
+ break;
case NETDEV_UNREGISTER:
/* This rcu_read_lock/unlock pair is needed because
* dev_map_list is an RCU list AND to ensure a delete
@@ -528,16 +561,84 @@ static int dev_map_notification(struct notifier_block *notifier,
return NOTIFY_OK;
}
+static void __net_exit dev_map_net_exit(struct net *net)
+{
+ struct bpf_dtab *dtab;
+
+ dtab = xchg(&net->xdp.default_map, NULL);
+ if (dtab)
+ dev_map_free(&dtab->map);
+}
+
static struct notifier_block dev_map_notifier = {
.notifier_call = dev_map_notification,
};
+static struct pernet_operations dev_map_net_ops = {
+ .exit = dev_map_net_exit,
+};
+
+int dev_map_alloc_default_map(void)
+{
+ struct net *net = current->nsproxy->net_ns;
+ struct bpf_dtab *dtab, *old_dtab;
+ struct net_device *netdev;
+ union bpf_attr attr = {};
+ u32 idx;
+ int err;
+
+ if (READ_ONCE(net->xdp.default_map))
+ return 0;
+
+ dtab = kzalloc(sizeof(*net->xdp.default_map), GFP_USER);
+ if (!dtab)
+ return -ENOMEM;
+
+ attr.max_entries = DEV_MAP_DEFAULT_SIZE;
+ attr.map_type = BPF_MAP_TYPE_DEVMAP;
+ attr.value_size = 4;
+ attr.key_size = 4;
+
+ err = dev_map_init_map(dtab, &attr, false);
+ if (err) {
+ kfree(dtab);
+ return err;
+ }
+
+ for_each_netdev(net, netdev) {
+ if (netdev->ifindex < DEV_MAP_DEFAULT_SIZE) {
+ idx = netdev->ifindex;
+ err = dev_map_update_elem(&dtab->map, &idx, &idx, 0);
+ if (err) {
+ dev_map_free(&dtab->map);
+ return err;
+ }
+ }
+ }
+
+ old_dtab = xchg(&net->xdp.default_map, dtab);
+ if (old_dtab)
+ dev_map_free(&old_dtab->map);
+
+ return 0;
+}
+
static int __init dev_map_init(void)
{
+ int err;
+
/* Assure tracepoint shadow struct _bpf_dtab_netdev is in sync */
BUILD_BUG_ON(offsetof(struct bpf_dtab_netdev, dev) !=
offsetof(struct _bpf_dtab_netdev, dev));
+
register_netdevice_notifier(&dev_map_notifier);
+
+ err = register_pernet_subsys(&dev_map_net_ops);
+ if (err) {
+ unregister_netdevice_notifier(&dev_map_notifier);
+ return err;
+ }
+
return 0;
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b63bc77af2d1..629661db36ee 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7527,6 +7527,12 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
prog->dst_needed = 1;
if (insn->imm == BPF_FUNC_get_prandom_u32)
bpf_user_rnd_init_once();
+ if (insn->imm == BPF_FUNC_redirect) {
+ int err = dev_map_alloc_default_map();
+
+ if (err)
+ return err;
+ }
if (insn->imm == BPF_FUNC_override_return)
prog->kprobe_override = 1;
if (insn->imm == BPF_FUNC_tail_call) {
diff --git a/net/core/filter.c b/net/core/filter.c
index b5a002d7b263..c709b1468bb6 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3326,58 +3326,6 @@ static const struct bpf_func_proto bpf_xdp_adjust_meta_proto = {
.arg2_type = ARG_ANYTHING,
};
-static int __bpf_tx_xdp(struct net_device *dev,
- struct bpf_map *map,
- struct xdp_buff *xdp,
- u32 index)
-{
- struct xdp_frame *xdpf;
- int err, sent;
-
- if (!dev->netdev_ops->ndo_xdp_xmit) {
- return -EOPNOTSUPP;
- }
-
- err = xdp_ok_fwd_dev(dev, xdp->data_end - xdp->data);
- if (unlikely(err))
- return err;
-
- xdpf = convert_to_xdp_frame(xdp);
- if (unlikely(!xdpf))
- return -EOVERFLOW;
-
- sent = dev->netdev_ops->ndo_xdp_xmit(dev, 1, &xdpf, XDP_XMIT_FLUSH);
- if (sent <= 0)
- return sent;
- return 0;
-}
-
-static noinline int
-xdp_do_redirect_slow(struct net_device *dev, struct xdp_buff *xdp,
- struct bpf_prog *xdp_prog, struct bpf_redirect_info *ri)
-{
- struct net_device *fwd;
- u32 index = ri->ifindex;
- int err;
-
- fwd = dev_get_by_index_rcu(dev_net(dev), index);
- ri->ifindex = 0;
- if (unlikely(!fwd)) {
- err = -EINVAL;
- goto err;
- }
-
- err = __bpf_tx_xdp(fwd, NULL, xdp, 0);
- if (unlikely(err))
- goto err;
-
- _trace_xdp_redirect(dev, xdp_prog, index);
- return 0;
-err:
- _trace_xdp_redirect_err(dev, xdp_prog, index, err);
- return err;
-}
-
static int __bpf_tx_xdp_map(struct net_device *dev_rx, void *fwd,
struct bpf_map *map,
struct xdp_buff *xdp,
@@ -3508,10 +3456,10 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
struct bpf_map *map = READ_ONCE(ri->map);
- if (likely(map))
- return xdp_do_redirect_map(dev, xdp, xdp_prog, map, ri);
+ if (unlikely(!map))
+ map = __dev_map_get_default_map(dev);
- return xdp_do_redirect_slow(dev, xdp, xdp_prog, ri);
+ return xdp_do_redirect_map(dev, xdp, xdp_prog, map, ri);
}
EXPORT_SYMBOL_GPL(xdp_do_redirect);
^ permalink raw reply related
* [PATCH net-next 2/2] xdp: Add devmap_idx map type for looking up devices by ifindex
From: Toke Høiland-Jørgensen @ 2019-02-21 11:56 UTC (permalink / raw)
To: David Miller
Cc: netdev, Jesper Dangaard Brouer, Daniel Borkmann,
Alexei Starovoitov
In-Reply-To: <155075021399.13610.12521373406832889226.stgit@alrua-x1>
A common pattern when using xdp_redirect_map() is to create a device map
where the lookup key is simply ifindex. Because device maps are arrays,
this leaves holes in the map, and the map has to be sized to fit the
largest ifindex, regardless of how many devices actually are actually
needed in the map.
This patch adds a second type of device map where the key is interpreted as
an ifindex and looked up using a hashmap, instead of being used as an array
index. This leads to maps being densely packed, so they can be smaller.
The default maps used by xdp_redirect() are changed to use the new map
type, which means that xdp_redirect() is no longer limited to ifindex < 64,
but instead to 64 total simultaneous interfaces per network namespace. This
also provides an easy way to compare the performance of devmap and
devmap_idx:
xdp_redirect_map (devmap): 8394560 pkt/s
xdp_redirect (devmap_idx): 8179480 pkt/s
Difference: 215080 pkt/s or 3.1 nanoseconds per packet.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
---
include/linux/bpf.h | 12 +
include/linux/bpf_types.h | 1
include/trace/events/xdp.h | 3
include/uapi/linux/bpf.h | 1
kernel/bpf/devmap.c | 304 +++++++++++++++++++++++++++----
kernel/bpf/verifier.c | 2
net/core/filter.c | 11 +
tools/bpf/bpftool/map.c | 1
tools/include/uapi/linux/bpf.h | 1
tools/lib/bpf/libbpf_probes.c | 1
tools/testing/selftests/bpf/test_maps.c | 16 ++
11 files changed, 310 insertions(+), 43 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4f8f179df9fd..e7308ff59071 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -606,9 +606,10 @@ struct xdp_buff;
struct sk_buff;
struct bpf_dtab_netdev *__dev_map_lookup_elem(struct bpf_map *map, u32 key);
+struct bpf_dtab_netdev *__dev_map_idx_lookup_elem(struct bpf_map *map, u32 key);
struct bpf_map *__dev_map_get_default_map(struct net_device *dev);
int dev_map_alloc_default_map(void);
-void __dev_map_insert_ctx(struct bpf_map *map, u32 index);
+void __dev_map_insert_ctx(struct bpf_map *map, struct bpf_dtab_netdev *dst);
void __dev_map_flush(struct bpf_map *map);
int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_buff *xdp,
struct net_device *dev_rx);
@@ -689,6 +690,12 @@ static inline struct net_device *__dev_map_lookup_elem(struct bpf_map *map,
return NULL;
}
+static inline struct net_device *__dev_map_idx_lookup_elem(struct bpf_map *map,
+ u32 key)
+{
+ return NULL;
+}
+
static inline struct bpf_map *__dev_map_get_default_map(struct net_device *dev)
{
return NULL;
@@ -699,7 +706,8 @@ static inline int dev_map_alloc_default_map(void)
return 0;
}
-static inline void __dev_map_insert_ctx(struct bpf_map *map, u32 index)
+static inline void __dev_map_insert_ctx(struct bpf_map *map,
+ struct net_device *dst)
{
}
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index 08bf2f1fe553..374c013ca243 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -59,6 +59,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY_OF_MAPS, array_of_maps_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops)
#ifdef CONFIG_NET
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops)
+BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP_IDX, dev_map_idx_ops)
#if defined(CONFIG_BPF_STREAM_PARSER)
BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKMAP, sock_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_SOCKHASH, sock_hash_ops)
diff --git a/include/trace/events/xdp.h b/include/trace/events/xdp.h
index e95cb86b65cf..fcf006d49f67 100644
--- a/include/trace/events/xdp.h
+++ b/include/trace/events/xdp.h
@@ -147,7 +147,8 @@ struct _bpf_dtab_netdev {
#define devmap_ifindex(fwd, map) \
(!fwd ? 0 : \
- ((map->map_type == BPF_MAP_TYPE_DEVMAP) ? \
+ ((map->map_type == BPF_MAP_TYPE_DEVMAP || \
+ map->map_type == BPF_MAP_TYPE_DEVMAP_IDX) ? \
((struct _bpf_dtab_netdev *)fwd)->dev->ifindex : 0))
#define _trace_xdp_redirect_map(dev, xdp, fwd, map, idx) \
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 1777fa0c61e4..a09243a38c2d 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -132,6 +132,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
BPF_MAP_TYPE_QUEUE,
BPF_MAP_TYPE_STACK,
+ BPF_MAP_TYPE_DEVMAP_IDX,
};
/* Note that tracing related programs such as
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 425077664ac6..e9f7b0ad7ff3 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -46,6 +46,12 @@
* notifier hook walks the map we know that new dev references can not be
* added by the user because core infrastructure ensures dev_get_by_index()
* calls will fail at this point.
+ *
+ * The devmap_idx type is a map type which interprets keys as ifindexes and
+ * indexes these using a hashmap. This allows maps that use ifindex as key to be
+ * densely packed instead of having holes in the lookup array for unused
+ * ifindexes. The setup and packet enqueue/send code is shared between the two
+ * types of devmap; only the lookup and insertion is different.
*/
#include <linux/bpf.h>
#include <net/xdp.h>
@@ -65,6 +71,8 @@ struct xdp_bulk_queue {
struct bpf_dtab_netdev {
struct net_device *dev; /* must be first member, due to tracepoint */
+ unsigned int ifindex;
+ struct hlist_node index_hlist;
struct bpf_dtab *dtab;
unsigned int bit;
struct xdp_bulk_queue __percpu *bulkq;
@@ -76,11 +84,29 @@ struct bpf_dtab {
struct bpf_dtab_netdev **netdev_map;
unsigned long __percpu *flush_needed;
struct list_head list;
+
+ /* these are only used for DEVMAP_IDX type maps */
+ unsigned long *bits_used;
+ struct hlist_head *dev_index_head;
+ spinlock_t index_lock;
};
static DEFINE_SPINLOCK(dev_map_lock);
static LIST_HEAD(dev_map_list);
+static struct hlist_head *dev_map_create_hash(void)
+{
+ int i;
+ struct hlist_head *hash;
+
+ hash = kmalloc_array(NETDEV_HASHENTRIES, sizeof(*hash), GFP_KERNEL);
+ if (hash != NULL)
+ for (i = 0; i < NETDEV_HASHENTRIES; i++)
+ INIT_HLIST_HEAD(&hash[i]);
+
+ return hash;
+}
+
static u64 dev_map_bitmap_size(const union bpf_attr *attr)
{
return BITS_TO_LONGS((u64) attr->max_entries) * sizeof(unsigned long);
@@ -97,6 +123,11 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr,
/* make sure page count doesn't overflow */
cost = (u64) dtab->map.max_entries * sizeof(struct bpf_dtab_netdev *);
cost += dev_map_bitmap_size(attr) * num_possible_cpus();
+
+ if (attr->map_type == BPF_MAP_TYPE_DEVMAP_IDX)
+ cost += dev_map_bitmap_size(attr) +
+ sizeof(struct hlist_head) * NETDEV_HASHENTRIES;
+
if (cost >= U32_MAX - PAGE_SIZE)
return -EINVAL;
@@ -119,9 +150,20 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr,
dtab->netdev_map = bpf_map_area_alloc(dtab->map.max_entries *
sizeof(struct bpf_dtab_netdev *),
dtab->map.numa_node);
- if (!dtab->netdev_map) {
- free_percpu(dtab->flush_needed);
- return -ENOMEM;
+ if (!dtab->netdev_map)
+ goto err_map;
+
+ if (attr->map_type == BPF_MAP_TYPE_DEVMAP_IDX) {
+ dtab->bits_used = kzalloc(dev_map_bitmap_size(attr),
+ GFP_KERNEL);
+ if (!dtab->bits_used)
+ goto err_bitmap;
+
+ dtab->dev_index_head = dev_map_create_hash();
+ if (!dtab->dev_index_head)
+ goto err_idx;
+
+ spin_lock_init(&dtab->index_lock);
}
spin_lock(&dev_map_lock);
@@ -129,6 +171,13 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr,
spin_unlock(&dev_map_lock);
return 0;
+ err_idx:
+ kfree(dtab->bits_used);
+ err_bitmap:
+ bpf_map_area_free(dtab->netdev_map);
+ err_map:
+ free_percpu(dtab->flush_needed);
+ return -ENOMEM;
}
static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
@@ -200,6 +249,10 @@ static void dev_map_free(struct bpf_map *map)
kfree(dev);
}
+ if (map->map_type == BPF_MAP_TYPE_DEVMAP_IDX) {
+ kfree(dtab->dev_index_head);
+ kfree(dtab->bits_used);
+ }
free_percpu(dtab->flush_needed);
bpf_map_area_free(dtab->netdev_map);
kfree(dtab);
@@ -222,12 +275,76 @@ static int dev_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
return 0;
}
-void __dev_map_insert_ctx(struct bpf_map *map, u32 bit)
+static inline struct hlist_head *dev_map_index_hash(struct bpf_dtab *dtab,
+ int ifindex)
+{
+ return &dtab->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)];
+}
+
+struct bpf_dtab_netdev *__dev_map_idx_lookup_elem(struct bpf_map *map, u32 key)
+{
+ struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
+ struct hlist_head *head = dev_map_index_hash(dtab, key);
+ struct bpf_dtab_netdev *dev;
+
+ hlist_for_each_entry_rcu(dev, head, index_hlist)
+ if (dev->ifindex == key)
+ return dev;
+
+ return NULL;
+}
+
+static int dev_map_idx_get_next_key(struct bpf_map *map, void *key,
+ void *next_key)
+{
+ struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
+ u32 ifindex, *next = next_key;
+ struct bpf_dtab_netdev *dev, *next_dev;
+ struct hlist_head *head;
+ int i = 0;
+
+ if (!key)
+ goto find_first;
+
+ ifindex = *(u32 *)key;
+
+ dev = __dev_map_idx_lookup_elem(map, ifindex);
+ if (!dev)
+ goto find_first;
+
+ next_dev = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(&dev->index_hlist)),
+ struct bpf_dtab_netdev, index_hlist);
+
+ if (next_dev) {
+ *next = next_dev->ifindex;
+ return 0;
+ }
+
+ i = ifindex & (NETDEV_HASHENTRIES - 1);
+ i++;
+
+ find_first:
+ for (; i < NETDEV_HASHENTRIES; i++) {
+ head = dev_map_index_hash(dtab, i);
+
+ next_dev = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(head)),
+ struct bpf_dtab_netdev,
+ index_hlist);
+ if (next_dev) {
+ *next = next_dev->ifindex;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+void __dev_map_insert_ctx(struct bpf_map *map, struct bpf_dtab_netdev *dst)
{
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
unsigned long *bitmap = this_cpu_ptr(dtab->flush_needed);
- __set_bit(bit, bitmap);
+ __set_bit(dst->bit, bitmap);
}
static int bq_xmit_all(struct bpf_dtab_netdev *obj,
@@ -396,9 +513,16 @@ int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,
static void *dev_map_lookup_elem(struct bpf_map *map, void *key)
{
struct bpf_dtab_netdev *obj = __dev_map_lookup_elem(map, *(u32 *)key);
- struct net_device *dev = obj ? obj->dev : NULL;
- return dev ? &dev->ifindex : NULL;
+ return obj ? &obj->ifindex : NULL;
+}
+
+static void *dev_map_idx_lookup_elem(struct bpf_map *map, void *key)
+{
+ struct bpf_dtab_netdev *obj = __dev_map_idx_lookup_elem(map,
+ *(u32 *)key);
+
+ return obj ? &obj->ifindex : NULL;
}
static void dev_map_flush_old(struct bpf_dtab_netdev *dev)
@@ -453,12 +577,81 @@ static int dev_map_delete_elem(struct bpf_map *map, void *key)
return 0;
}
-static int dev_map_update_elem(struct bpf_map *map, void *key, void *value,
- u64 map_flags)
+static int dev_map_idx_delete_elem(struct bpf_map *map, void *key)
{
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
+ struct bpf_dtab_netdev *old_dev;
+ int k = *(u32 *)key;
+
+ old_dev = __dev_map_idx_lookup_elem(map, k);
+ if (!old_dev)
+ return 0;
+
+ spin_lock(&dtab->index_lock);
+ hlist_del_rcu(&old_dev->index_hlist);
+ spin_unlock(&dtab->index_lock);
+
+ xchg(&dtab->netdev_map[old_dev->bit], NULL);
+ clear_bit_unlock(old_dev->bit, dtab->bits_used);
+ call_rcu(&old_dev->rcu, __dev_map_entry_free);
+ return 0;
+}
+
+
+static bool __dev_map_find_bit(struct bpf_dtab *dtab, unsigned int *bit)
+{
+ unsigned int b = 0;
+
+ retry:
+ b = find_next_zero_bit(dtab->bits_used, dtab->map.max_entries, b);
+
+ if (b >= dtab->map.max_entries)
+ return false;
+
+ if (test_and_set_bit_lock(b, dtab->bits_used))
+ goto retry;
+
+ *bit = b;
+ return true;
+}
+
+static struct bpf_dtab_netdev *__dev_map_alloc_node(struct bpf_dtab *dtab,
+ u32 ifindex,
+ unsigned int bit)
+{
struct net *net = current->nsproxy->net_ns;
gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN;
+ struct bpf_dtab_netdev *dev;
+
+ dev = kmalloc_node(sizeof(*dev), gfp, dtab->map.numa_node);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ dev->bulkq = __alloc_percpu_gfp(sizeof(*dev->bulkq),
+ sizeof(void *), gfp);
+ if (!dev->bulkq) {
+ kfree(dev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dev->dev = dev_get_by_index(net, ifindex);
+ if (!dev->dev) {
+ free_percpu(dev->bulkq);
+ kfree(dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ dev->ifindex = dev->dev->ifindex;
+ dev->bit = bit;
+ dev->dtab = dtab;
+
+ return dev;
+}
+
+static int dev_map_update_elem(struct bpf_map *map, void *key, void *value,
+ u64 map_flags)
+{
+ struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
struct bpf_dtab_netdev *dev, *old_dev;
u32 i = *(u32 *)key;
u32 ifindex = *(u32 *)value;
@@ -473,26 +666,9 @@ static int dev_map_update_elem(struct bpf_map *map, void *key, void *value,
if (!ifindex) {
dev = NULL;
} else {
- dev = kmalloc_node(sizeof(*dev), gfp, map->numa_node);
- if (!dev)
- return -ENOMEM;
-
- dev->bulkq = __alloc_percpu_gfp(sizeof(*dev->bulkq),
- sizeof(void *), gfp);
- if (!dev->bulkq) {
- kfree(dev);
- return -ENOMEM;
- }
-
- dev->dev = dev_get_by_index(net, ifindex);
- if (!dev->dev) {
- free_percpu(dev->bulkq);
- kfree(dev);
- return -EINVAL;
- }
-
- dev->bit = i;
- dev->dtab = dtab;
+ dev = __dev_map_alloc_node(dtab, ifindex, i);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
}
/* Use call_rcu() here to ensure rcu critical sections have completed
@@ -506,6 +682,52 @@ static int dev_map_update_elem(struct bpf_map *map, void *key, void *value,
return 0;
}
+static int dev_map_idx_update_elem(struct bpf_map *map, void *key, void *value,
+ u64 map_flags)
+{
+ struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
+ struct bpf_dtab_netdev *dev, *old_dev;
+ u32 idx = *(u32 *)key;
+ u32 val = *(u32 *)value;
+ u32 bit;
+
+ if (unlikely(map_flags > BPF_EXIST))
+ return -EINVAL;
+ if (unlikely(map_flags == BPF_NOEXIST))
+ return -EEXIST;
+
+ old_dev = __dev_map_idx_lookup_elem(map, idx);
+ if (!val) {
+ if (!old_dev)
+ return 0;
+
+ xchg(&dtab->netdev_map[old_dev->bit], NULL);
+ spin_lock(&dtab->index_lock);
+ hlist_del_rcu(&old_dev->index_hlist);
+ spin_unlock(&dtab->index_lock);
+
+ clear_bit_unlock(old_dev->bit, dtab->bits_used);
+ call_rcu(&old_dev->rcu, __dev_map_entry_free);
+ } else {
+ if (idx != val)
+ return -EINVAL;
+ if (old_dev)
+ return 0;
+ if (!__dev_map_find_bit(dtab, &bit))
+ return -E2BIG;
+ dev = __dev_map_alloc_node(dtab, idx, bit);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ xchg(&dtab->netdev_map[bit], dev);
+ spin_lock(&dtab->index_lock);
+ hlist_add_head_rcu(&dev->index_hlist,
+ dev_map_index_hash(dtab, dev->ifindex));
+ spin_unlock(&dtab->index_lock);
+ }
+ return 0;
+}
+
const struct bpf_map_ops dev_map_ops = {
.map_alloc = dev_map_alloc,
.map_free = dev_map_free,
@@ -516,6 +738,16 @@ const struct bpf_map_ops dev_map_ops = {
.map_check_btf = map_check_no_btf,
};
+const struct bpf_map_ops dev_map_idx_ops = {
+ .map_alloc = dev_map_alloc,
+ .map_free = dev_map_free,
+ .map_get_next_key = dev_map_idx_get_next_key,
+ .map_lookup_elem = dev_map_idx_lookup_elem,
+ .map_update_elem = dev_map_idx_update_elem,
+ .map_delete_elem = dev_map_idx_delete_elem,
+ .map_check_btf = map_check_no_btf,
+};
+
static int dev_map_notification(struct notifier_block *notifier,
ulong event, void *ptr)
{
@@ -595,7 +827,7 @@ int dev_map_alloc_default_map(void)
return -ENOMEM;
attr.max_entries = DEV_MAP_DEFAULT_SIZE;
- attr.map_type = BPF_MAP_TYPE_DEVMAP;
+ attr.map_type = BPF_MAP_TYPE_DEVMAP_IDX;
attr.value_size = 4;
attr.key_size = 4;
@@ -606,13 +838,11 @@ int dev_map_alloc_default_map(void)
}
for_each_netdev(net, netdev) {
- if (netdev->ifindex < DEV_MAP_DEFAULT_SIZE) {
- idx = netdev->ifindex;
- err = dev_map_update_elem(&dtab->map, &idx, &idx, 0);
- if (err) {
- dev_map_free(&dtab->map);
- return err;
- }
+ idx = netdev->ifindex;
+ err = dev_map_update_elem(&dtab->map, &idx, &idx, 0);
+ if (err) {
+ dev_map_free(&dtab->map);
+ return err;
}
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 629661db36ee..d6b9a7f3eb0e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2528,6 +2528,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
* for now.
*/
case BPF_MAP_TYPE_DEVMAP:
+ case BPF_MAP_TYPE_DEVMAP_IDX:
if (func_id != BPF_FUNC_redirect_map)
goto error;
break;
@@ -2600,6 +2601,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
break;
case BPF_FUNC_redirect_map:
if (map->map_type != BPF_MAP_TYPE_DEVMAP &&
+ map->map_type != BPF_MAP_TYPE_DEVMAP_IDX &&
map->map_type != BPF_MAP_TYPE_CPUMAP &&
map->map_type != BPF_MAP_TYPE_XSKMAP)
goto error;
diff --git a/net/core/filter.c b/net/core/filter.c
index c709b1468bb6..305c9bbf1753 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3334,13 +3334,14 @@ static int __bpf_tx_xdp_map(struct net_device *dev_rx, void *fwd,
int err;
switch (map->map_type) {
- case BPF_MAP_TYPE_DEVMAP: {
+ case BPF_MAP_TYPE_DEVMAP:
+ case BPF_MAP_TYPE_DEVMAP_IDX: {
struct bpf_dtab_netdev *dst = fwd;
err = dev_map_enqueue(dst, xdp, dev_rx);
if (unlikely(err))
return err;
- __dev_map_insert_ctx(map, index);
+ __dev_map_insert_ctx(map, dst);
break;
}
case BPF_MAP_TYPE_CPUMAP: {
@@ -3373,6 +3374,7 @@ void xdp_do_flush_map(void)
if (map) {
switch (map->map_type) {
case BPF_MAP_TYPE_DEVMAP:
+ case BPF_MAP_TYPE_DEVMAP_IDX:
__dev_map_flush(map);
break;
case BPF_MAP_TYPE_CPUMAP:
@@ -3393,6 +3395,8 @@ static inline void *__xdp_map_lookup_elem(struct bpf_map *map, u32 index)
switch (map->map_type) {
case BPF_MAP_TYPE_DEVMAP:
return __dev_map_lookup_elem(map, index);
+ case BPF_MAP_TYPE_DEVMAP_IDX:
+ return __dev_map_idx_lookup_elem(map, index);
case BPF_MAP_TYPE_CPUMAP:
return __cpu_map_lookup_elem(map, index);
case BPF_MAP_TYPE_XSKMAP:
@@ -3483,7 +3487,8 @@ static int xdp_do_generic_redirect_map(struct net_device *dev,
goto err;
}
- if (map->map_type == BPF_MAP_TYPE_DEVMAP) {
+ if (map->map_type == BPF_MAP_TYPE_DEVMAP ||
+ map->map_type == BPF_MAP_TYPE_DEVMAP_IDX) {
struct bpf_dtab_netdev *dst = fwd;
err = dev_map_generic_redirect(dst, skb, xdp_prog);
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index e0c650d91784..0864ce33df94 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -37,6 +37,7 @@ const char * const map_type_name[] = {
[BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps",
[BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps",
[BPF_MAP_TYPE_DEVMAP] = "devmap",
+ [BPF_MAP_TYPE_DEVMAP_IDX] = "devmap_idx",
[BPF_MAP_TYPE_SOCKMAP] = "sockmap",
[BPF_MAP_TYPE_CPUMAP] = "cpumap",
[BPF_MAP_TYPE_XSKMAP] = "xskmap",
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 1777fa0c61e4..a09243a38c2d 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -132,6 +132,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
BPF_MAP_TYPE_QUEUE,
BPF_MAP_TYPE_STACK,
+ BPF_MAP_TYPE_DEVMAP_IDX,
};
/* Note that tracing related programs such as
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index 8c3a1c04dcb2..b87b760a1355 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -172,6 +172,7 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
case BPF_MAP_TYPE_HASH_OF_MAPS:
case BPF_MAP_TYPE_DEVMAP:
+ case BPF_MAP_TYPE_DEVMAP_IDX:
case BPF_MAP_TYPE_SOCKMAP:
case BPF_MAP_TYPE_CPUMAP:
case BPF_MAP_TYPE_XSKMAP:
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index 3c627771f965..63681e4647f9 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -519,6 +519,21 @@ static void test_devmap(unsigned int task, void *data)
close(fd);
}
+static void test_devmap_idx(unsigned int task, void *data)
+{
+ int fd;
+ __u32 key, value;
+
+ fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP_IDX, sizeof(key), sizeof(value),
+ 2, 0);
+ if (fd < 0) {
+ printf("Failed to create devmap_idx '%s'!\n", strerror(errno));
+ exit(1);
+ }
+
+ close(fd);
+}
+
static void test_queuemap(unsigned int task, void *data)
{
const int MAP_SIZE = 32;
@@ -1686,6 +1701,7 @@ static void run_all_tests(void)
test_arraymap_percpu_many_keys();
test_devmap(0, NULL);
+ test_devmap_idx(0, NULL);
test_sockmap(0, NULL);
test_map_large();
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox