* [PATCH net-next 2/4] net: dsa: Make most functions take a dsa_port argument
From: Florian Fainelli @ 2017-01-26 18:28 UTC (permalink / raw)
To: netdev; +Cc: andrew, vivien.didelot, davem, Florian Fainelli
In-Reply-To: <20170126182808.13435-1-f.fainelli@gmail.com>
In preparation for allowing platform data, and therefore no valid
device_node pointer, make most DSA functions takes a pointer to a
dsa_port structure whenever possible. While at it, introduce a
dsa_port_is_valid() helper function which checks whether port->dn is
NULL or not at the moment.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
net/dsa/dsa.c | 15 ++++++++------
net/dsa/dsa2.c | 61 +++++++++++++++++++++++++++++-------------------------
net/dsa/dsa_priv.h | 4 ++--
3 files changed, 44 insertions(+), 36 deletions(-)
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 1f3afeb673d6..07e863369e04 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -110,8 +110,9 @@ dsa_switch_probe(struct device *parent, struct device *host_dev, int sw_addr,
/* basic switch operations **************************************************/
int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
- struct device_node *port_dn, int port)
+ struct dsa_port *dport, int port)
{
+ struct device_node *port_dn = dport->dn;
struct phy_device *phydev;
int ret, mode;
@@ -141,15 +142,15 @@ int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
static int dsa_cpu_dsa_setups(struct dsa_switch *ds, struct device *dev)
{
- struct device_node *port_dn;
+ struct dsa_port *dport;
int ret, port;
for (port = 0; port < DSA_MAX_PORTS; port++) {
if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
continue;
- port_dn = ds->ports[port].dn;
- ret = dsa_cpu_dsa_setup(ds, dev, port_dn, port);
+ dport = &ds->ports[port];
+ ret = dsa_cpu_dsa_setup(ds, dev, dport, port);
if (ret)
return ret;
}
@@ -364,8 +365,10 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
return ds;
}
-void dsa_cpu_dsa_destroy(struct device_node *port_dn)
+void dsa_cpu_dsa_destroy(struct dsa_port *port)
{
+ struct device_node *port_dn = port->dn;
+
if (of_phy_is_fixed_link(port_dn))
of_phy_deregister_fixed_link(port_dn);
}
@@ -389,7 +392,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
for (port = 0; port < DSA_MAX_PORTS; port++) {
if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
continue;
- dsa_cpu_dsa_destroy(ds->ports[port].dn);
+ dsa_cpu_dsa_destroy(&ds->ports[port]);
/* Clearing a bit which is not set does no harm */
ds->cpu_port_mask |= ~(1 << port);
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 2cf489c5e90f..56c43ca7c049 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -78,14 +78,19 @@ static void dsa_dst_del_ds(struct dsa_switch_tree *dst,
kref_put(&dst->refcount, dsa_free_dst);
}
-static bool dsa_port_is_dsa(struct device_node *port)
+static bool dsa_port_is_valid(struct dsa_port *port)
{
- return !!of_parse_phandle(port, "link", 0);
+ return !!port->dn;
}
-static bool dsa_port_is_cpu(struct device_node *port)
+static bool dsa_port_is_dsa(struct dsa_port *port)
{
- return !!of_parse_phandle(port, "ethernet", 0);
+ return !!of_parse_phandle(port->dn, "link", 0);
+}
+
+static bool dsa_port_is_cpu(struct dsa_port *port)
+{
+ return !!of_parse_phandle(port->dn, "ethernet", 0);
}
static bool dsa_ds_find_port(struct dsa_switch *ds,
@@ -119,7 +124,7 @@ static struct dsa_switch *dsa_dst_find_port(struct dsa_switch_tree *dst,
static int dsa_port_complete(struct dsa_switch_tree *dst,
struct dsa_switch *src_ds,
- struct device_node *port,
+ struct dsa_port *port,
u32 src_port)
{
struct device_node *link;
@@ -127,7 +132,7 @@ static int dsa_port_complete(struct dsa_switch_tree *dst,
struct dsa_switch *dst_ds;
for (index = 0;; index++) {
- link = of_parse_phandle(port, "link", index);
+ link = of_parse_phandle(port->dn, "link", index);
if (!link)
break;
@@ -150,13 +155,13 @@ static int dsa_port_complete(struct dsa_switch_tree *dst,
*/
static int dsa_ds_complete(struct dsa_switch_tree *dst, struct dsa_switch *ds)
{
- struct device_node *port;
+ struct dsa_port *port;
u32 index;
int err;
for (index = 0; index < DSA_MAX_PORTS; index++) {
- port = ds->ports[index].dn;
- if (!port)
+ port = &ds->ports[index];
+ if (!dsa_port_is_valid(port))
continue;
if (!dsa_port_is_dsa(port))
@@ -196,7 +201,7 @@ static int dsa_dst_complete(struct dsa_switch_tree *dst)
return 0;
}
-static int dsa_dsa_port_apply(struct device_node *port, u32 index,
+static int dsa_dsa_port_apply(struct dsa_port *port, u32 index,
struct dsa_switch *ds)
{
int err;
@@ -211,13 +216,13 @@ static int dsa_dsa_port_apply(struct device_node *port, u32 index,
return 0;
}
-static void dsa_dsa_port_unapply(struct device_node *port, u32 index,
+static void dsa_dsa_port_unapply(struct dsa_port *port, u32 index,
struct dsa_switch *ds)
{
dsa_cpu_dsa_destroy(port);
}
-static int dsa_cpu_port_apply(struct device_node *port, u32 index,
+static int dsa_cpu_port_apply(struct dsa_port *port, u32 index,
struct dsa_switch *ds)
{
int err;
@@ -234,7 +239,7 @@ static int dsa_cpu_port_apply(struct device_node *port, u32 index,
return 0;
}
-static void dsa_cpu_port_unapply(struct device_node *port, u32 index,
+static void dsa_cpu_port_unapply(struct dsa_port *port, u32 index,
struct dsa_switch *ds)
{
dsa_cpu_dsa_destroy(port);
@@ -242,13 +247,13 @@ static void dsa_cpu_port_unapply(struct device_node *port, u32 index,
}
-static int dsa_user_port_apply(struct device_node *port, u32 index,
+static int dsa_user_port_apply(struct dsa_port *port, u32 index,
struct dsa_switch *ds)
{
const char *name;
int err;
- name = of_get_property(port, "label", NULL);
+ name = of_get_property(port->dn, "label", NULL);
if (!name)
name = "eth%d";
@@ -262,7 +267,7 @@ static int dsa_user_port_apply(struct device_node *port, u32 index,
return 0;
}
-static void dsa_user_port_unapply(struct device_node *port, u32 index,
+static void dsa_user_port_unapply(struct dsa_port *port, u32 index,
struct dsa_switch *ds)
{
if (ds->ports[index].netdev) {
@@ -274,7 +279,7 @@ static void dsa_user_port_unapply(struct device_node *port, u32 index,
static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
{
- struct device_node *port;
+ struct dsa_port *port;
u32 index;
int err;
@@ -308,8 +313,8 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
}
for (index = 0; index < DSA_MAX_PORTS; index++) {
- port = ds->ports[index].dn;
- if (!port)
+ port = &ds->ports[index];
+ if (!dsa_port_is_valid(port))
continue;
if (dsa_port_is_dsa(port)) {
@@ -336,12 +341,12 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds)
{
- struct device_node *port;
+ struct dsa_port *port;
u32 index;
for (index = 0; index < DSA_MAX_PORTS; index++) {
- port = ds->ports[index].dn;
- if (!port)
+ port = &ds->ports[index];
+ if (!dsa_port_is_valid(port))
continue;
if (dsa_port_is_dsa(port)) {
@@ -425,7 +430,7 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
dst->applied = false;
}
-static int dsa_cpu_parse(struct device_node *port, u32 index,
+static int dsa_cpu_parse(struct dsa_port *port, u32 index,
struct dsa_switch_tree *dst,
struct dsa_switch *ds)
{
@@ -433,7 +438,7 @@ static int dsa_cpu_parse(struct device_node *port, u32 index,
struct net_device *ethernet_dev;
struct device_node *ethernet;
- ethernet = of_parse_phandle(port, "ethernet", 0);
+ ethernet = of_parse_phandle(port->dn, "ethernet", 0);
if (!ethernet)
return -EINVAL;
@@ -466,13 +471,13 @@ static int dsa_cpu_parse(struct device_node *port, u32 index,
static int dsa_ds_parse(struct dsa_switch_tree *dst, struct dsa_switch *ds)
{
- struct device_node *port;
+ struct dsa_port *port;
u32 index;
int err;
for (index = 0; index < DSA_MAX_PORTS; index++) {
- port = ds->ports[index].dn;
- if (!port)
+ port = &ds->ports[index];
+ if (!dsa_port_is_valid(port))
continue;
if (dsa_port_is_cpu(port)) {
@@ -533,7 +538,7 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds)
* to have access to a correct value, just like what
* net/dsa/dsa.c::dsa_switch_setup_one does.
*/
- if (!dsa_port_is_cpu(port))
+ if (!dsa_port_is_cpu(&ds->ports[reg]))
ds->enabled_port_mask |= 1 << reg;
}
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 63ae1484abae..16194a4bb2fe 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -50,8 +50,8 @@ struct dsa_slave_priv {
/* dsa.c */
int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
- struct device_node *port_dn, int port);
-void dsa_cpu_dsa_destroy(struct device_node *port_dn);
+ struct dsa_port *dport, int port);
+void dsa_cpu_dsa_destroy(struct dsa_port *dport);
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds);
void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds);
--
2.9.3
^ permalink raw reply related
* [PATCH net-next 0/4] net: dsa: Preparatory patches
From: Florian Fainelli @ 2017-01-26 18:28 UTC (permalink / raw)
To: netdev; +Cc: andrew, vivien.didelot, davem, Florian Fainelli
Hi David,
This patch series extracts the 4 patches of the larger: net: dsa: Support for
pdata in dsa2 while we wait for feedback from Greg KH on the device references.
Thanks!
Florian Fainelli (4):
net: dsa: Pass device pointer to dsa_register_switch
net: dsa: Make most functions take a dsa_port argument
net: dsa: Suffix function manipulating device_node with _dn
net: dsa: Move ports assignment closer to error checking
drivers/net/dsa/b53/b53_common.c | 2 +-
drivers/net/dsa/mv88e6xxx/chip.c | 11 ++---
drivers/net/dsa/qca8k.c | 2 +-
include/net/dsa.h | 2 +-
net/dsa/dsa.c | 15 ++++---
net/dsa/dsa2.c | 87 ++++++++++++++++++++++------------------
net/dsa/dsa_priv.h | 4 +-
7 files changed, 67 insertions(+), 56 deletions(-)
--
2.9.3
^ permalink raw reply
* [PATCH net-next 1/4] net: dsa: Pass device pointer to dsa_register_switch
From: Florian Fainelli @ 2017-01-26 18:28 UTC (permalink / raw)
To: netdev; +Cc: andrew, vivien.didelot, davem, Florian Fainelli
In-Reply-To: <20170126182808.13435-1-f.fainelli@gmail.com>
In preparation for allowing dsa_register_switch() to be supplied with
device/platform data, pass down a struct device pointer instead of a
struct device_node.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/dsa/b53/b53_common.c | 2 +-
drivers/net/dsa/mv88e6xxx/chip.c | 11 ++++++-----
drivers/net/dsa/qca8k.c | 2 +-
include/net/dsa.h | 2 +-
net/dsa/dsa2.c | 7 ++++---
5 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 5cbb14f6a03b..bb210b12ad1b 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1894,7 +1894,7 @@ int b53_switch_register(struct b53_device *dev)
pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev);
- return dsa_register_switch(dev->ds, dev->ds->dev->of_node);
+ return dsa_register_switch(dev->ds, dev->ds->dev);
}
EXPORT_SYMBOL(b53_switch_register);
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 5668e778ed1d..12e58ec94b7a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4356,8 +4356,7 @@ static struct dsa_switch_driver mv88e6xxx_switch_drv = {
.ops = &mv88e6xxx_switch_ops,
};
-static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip,
- struct device_node *np)
+static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip)
{
struct device *dev = chip->dev;
struct dsa_switch *ds;
@@ -4372,7 +4371,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip,
dev_set_drvdata(dev, ds);
- return dsa_register_switch(ds, np);
+ return dsa_register_switch(ds, dev);
}
static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip)
@@ -4456,9 +4455,11 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
if (err)
goto out_g2_irq;
- err = mv88e6xxx_register_switch(chip, np);
- if (err)
+ err = mv88e6xxx_register_switch(chip);
+ if (err) {
+ mv88e6xxx_mdio_unregister(chip);
goto out_mdio;
+ }
return 0;
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 54d270d59eb0..c084aa484d2b 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -964,7 +964,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
mutex_init(&priv->reg_mutex);
dev_set_drvdata(&mdiodev->dev, priv);
- return dsa_register_switch(priv->ds, priv->ds->dev->of_node);
+ return dsa_register_switch(priv->ds, &mdiodev->dev);
}
static void
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 08b340403927..92fd795e9573 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -387,7 +387,7 @@ static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
}
void dsa_unregister_switch(struct dsa_switch *ds);
-int dsa_register_switch(struct dsa_switch *ds, struct device_node *np);
+int dsa_register_switch(struct dsa_switch *ds, struct device *dev);
#ifdef CONFIG_PM_SLEEP
int dsa_switch_suspend(struct dsa_switch *ds);
int dsa_switch_resume(struct dsa_switch *ds);
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 866222a8f9bf..2cf489c5e90f 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -578,8 +578,9 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds,
return ports;
}
-static int _dsa_register_switch(struct dsa_switch *ds, struct device_node *np)
+static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
{
+ struct device_node *np = dev->of_node;
struct device_node *ports = dsa_get_ports(ds, np);
struct dsa_switch_tree *dst;
u32 tree, index;
@@ -659,12 +660,12 @@ static int _dsa_register_switch(struct dsa_switch *ds, struct device_node *np)
return err;
}
-int dsa_register_switch(struct dsa_switch *ds, struct device_node *np)
+int dsa_register_switch(struct dsa_switch *ds, struct device *dev)
{
int err;
mutex_lock(&dsa2_mutex);
- err = _dsa_register_switch(ds, np);
+ err = _dsa_register_switch(ds, dev);
mutex_unlock(&dsa2_mutex);
return err;
--
2.9.3
^ permalink raw reply related
* [PATCH net-next 3/4] net: dsa: Suffix function manipulating device_node with _dn
From: Florian Fainelli @ 2017-01-26 18:28 UTC (permalink / raw)
To: netdev; +Cc: andrew, vivien.didelot, davem, Florian Fainelli
In-Reply-To: <20170126182808.13435-1-f.fainelli@gmail.com>
Make it clear that these functions take a device_node structure pointer
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
net/dsa/dsa2.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 56c43ca7c049..4c11619a818b 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -93,8 +93,8 @@ static bool dsa_port_is_cpu(struct dsa_port *port)
return !!of_parse_phandle(port->dn, "ethernet", 0);
}
-static bool dsa_ds_find_port(struct dsa_switch *ds,
- struct device_node *port)
+static bool dsa_ds_find_port_dn(struct dsa_switch *ds,
+ struct device_node *port)
{
u32 index;
@@ -104,8 +104,8 @@ static bool dsa_ds_find_port(struct dsa_switch *ds,
return false;
}
-static struct dsa_switch *dsa_dst_find_port(struct dsa_switch_tree *dst,
- struct device_node *port)
+static struct dsa_switch *dsa_dst_find_port_dn(struct dsa_switch_tree *dst,
+ struct device_node *port)
{
struct dsa_switch *ds;
u32 index;
@@ -115,7 +115,7 @@ static struct dsa_switch *dsa_dst_find_port(struct dsa_switch_tree *dst,
if (!ds)
continue;
- if (dsa_ds_find_port(ds, port))
+ if (dsa_ds_find_port_dn(ds, port))
return ds;
}
@@ -136,7 +136,7 @@ static int dsa_port_complete(struct dsa_switch_tree *dst,
if (!link)
break;
- dst_ds = dsa_dst_find_port(dst, link);
+ dst_ds = dsa_dst_find_port_dn(dst, link);
of_node_put(link);
if (!dst_ds)
@@ -545,7 +545,7 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds)
return 0;
}
-static int dsa_parse_member(struct device_node *np, u32 *tree, u32 *index)
+static int dsa_parse_member_dn(struct device_node *np, u32 *tree, u32 *index)
{
int err;
@@ -591,7 +591,7 @@ static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
u32 tree, index;
int i, err;
- err = dsa_parse_member(np, &tree, &index);
+ err = dsa_parse_member_dn(np, &tree, &index);
if (err)
return err;
--
2.9.3
^ permalink raw reply related
* Re: [PATCH v1] net: phy: micrel: add KSZ8795 ethernet switch
From: Florian Fainelli @ 2017-01-26 18:36 UTC (permalink / raw)
To: Sean Nyekjær, Andrew Lunn; +Cc: netdev
In-Reply-To: <732c14ff-f0cf-67d5-bcf9-cbbf9a4391b3@prevas.dk>
On 01/26/2017 09:51 AM, Sean Nyekjær wrote:
>
>
> On 2017-01-23 16:12, Andrew Lunn wrote:
>> On Mon, Jan 23, 2017 at 08:58:46AM +0100, Sean Nyekjaer wrote:
>>> This is add support for the PHYs in the KSZ8795 5port managed switch.
>>>
>>> It will allow to detect the link between the switch and the soc
>>> and uses the same read_status functions as the KSZ8873MLL switch.
>>>
>>> This ethernet switch have unfortunately the same phy id as KSZ8051.
>>>
>>> Signed-off-by: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
>>> ---
>>> drivers/net/phy/micrel.c | 14 ++++++++++++++
>>> include/linux/micrel_phy.h | 2 ++
>>> 2 files changed, 16 insertions(+)
>>>
>>> diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
>>> index ea92d524d5a8..fa158ae5115b 100644
>>> --- a/drivers/net/phy/micrel.c
>>> +++ b/drivers/net/phy/micrel.c
>>> @@ -1014,6 +1014,20 @@ static struct phy_driver ksphy_driver[] = {
>>> .get_stats = kszphy_get_stats,
>>> .suspend = genphy_suspend,
>>> .resume = genphy_resume,
>>> +}, {
>>> + .phy_id = PHY_ID_KSZ8795,
>>> + .phy_id_mask = MICREL_PHY_ID_MASK,
>>> + .name = "Micrel KSZ8795 Switch",
>> This name is confusing. You are adding support for the PHYs embedded
>> in the switch, not the switch itself. The phylib has no idea these
>> PHYs are inside a switch. It does not matter. It is just a PHY. Please
>> drop the word "Switch".
>>
>> Thanks
>> Andrew
> Okay i'll understand :-)
> I remove the word "Switch" from the commit message and phy name.
> The rest is okay?
> What is generally being done when to phy's have the same id, micrel have
> done this many times...
You need unique names, we have a case like that in
drivers/net/phy/bcm7xxx.c for the 7439 PHY where it exists with two
different IDs, so the first one is named "Broadcom BCM7439" and the
second one is named "Broadcom BCM7439 (2)", feel free to adopt the same
convention, or something else.
The rest of your patch is okay.
--
Florian
^ permalink raw reply
* Re: [PATCH 02/14] tcp: fix mark propagation with fwmark_reflect enabled
From: Eric Dumazet @ 2017-01-26 18:02 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel, davem, netdev
In-Reply-To: <1485448687-6072-3-git-send-email-pablo@netfilter.org>
On Thu, 2017-01-26 at 17:37 +0100, Pablo Neira Ayuso wrote:
> From: Pau Espin Pedrol <pespin.shar@gmail.com>
>
> Otherwise, RST packets generated by the TCP stack for non-existing
> sockets always have mark 0.
> The mark from the original packet is assigned to the netns_ipv4/6
> socket used to send the response so that it can get copied into the
> response skb when the socket sends it.
>
> Fixes: e110861f8609 ("net: add a sysctl to reflect the fwmark on replies")
> Cc: Lorenzo Colitti <lorenzo@google.com>
> Signed-off-by: Pau Espin Pedrol <pau.espin@tessares.net>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
> net/ipv4/ip_output.c | 1 +
> net/ipv6/tcp_ipv6.c | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
> index fac275c48108..b67719f45953 100644
> --- a/net/ipv4/ip_output.c
> +++ b/net/ipv4/ip_output.c
> @@ -1629,6 +1629,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
> sk->sk_protocol = ip_hdr(skb)->protocol;
> sk->sk_bound_dev_if = arg->bound_dev_if;
> sk->sk_sndbuf = sysctl_wmem_default;
> + sk->sk_mark = fl4.flowi4_mark;
> err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
> len, 0, &ipc, &rt, MSG_DONTWAIT);
> if (unlikely(err)) {
> diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
> index 73bc8fc68acd..2b20622a5824 100644
> --- a/net/ipv6/tcp_ipv6.c
> +++ b/net/ipv6/tcp_ipv6.c
> @@ -840,6 +840,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
> dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
> if (!IS_ERR(dst)) {
> skb_dst_set(buff, dst);
> + ctl_sk->sk_mark = fl6.flowi6_mark;
> ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
> TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
> if (rst)
This patch is wrong.
ctl_sk is a shared socket, and tcp_v6_send_response() can be called from
many different cpus at the same time.
^ permalink raw reply
* [PATCH net-next 4/4] net: dsa: Move ports assignment closer to error checking
From: Florian Fainelli @ 2017-01-26 18:28 UTC (permalink / raw)
To: netdev; +Cc: andrew, vivien.didelot, davem, Florian Fainelli
In-Reply-To: <20170126182808.13435-1-f.fainelli@gmail.com>
Move the assignment of ports in _dsa_register_switch() closer to where
it is checked, no functional change. Re-order declarations to be
preserve the inverted christmas tree style.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
net/dsa/dsa2.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 4c11619a818b..75f5d1f8554b 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -586,8 +586,8 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds,
static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
{
struct device_node *np = dev->of_node;
- struct device_node *ports = dsa_get_ports(ds, np);
struct dsa_switch_tree *dst;
+ struct device_node *ports;
u32 tree, index;
int i, err;
@@ -595,6 +595,7 @@ static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev)
if (err)
return err;
+ ports = dsa_get_ports(ds, np);
if (IS_ERR(ports))
return PTR_ERR(ports);
--
2.9.3
^ permalink raw reply related
* Re: [PATCH net] bpf: expose netns inode to bpf programs
From: Alexei Starovoitov @ 2017-01-26 18:32 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Linus Torvalds, Eric W. Biederman, David S . Miller,
Daniel Borkmann, David Ahern, Tejun Heo, Thomas Graf,
Network Development
In-Reply-To: <CALCETrU7FYz=8c2a=FWvvCxFQC3_e0nYjSU6gj62w9K8mWj=Ww@mail.gmail.com>
On 1/26/17 10:12 AM, Andy Lutomirski wrote:
> On Thu, Jan 26, 2017 at 9:46 AM, Alexei Starovoitov <ast@fb.com> wrote:
>> On 1/26/17 8:37 AM, Andy Lutomirski wrote:
>>>>
>>>> Think of bpf programs as safe kernel modules. They don't have
>>>> confined boundaries and program authors, if not careful, can shoot
>>>> themselves in the foot. We're not trying to prevent that because
>>>> it's impossible to check that the program is sane. Just like
>>>> it's impossible to check that kernel module is sane.
>>>> But in case of bpf we check that bpf program is _safe_ from the kernel
>>>> point of view. If it's doing some garbage, it's program's business.
>>>> Does it make more sense now?
>>>>
>>>
>>> With all due respect, I think this is not an acceptable way to think
>>> about BPF at all. If you think of BPF this way, I think there needs
>>> to be a real discussion at KS or similar as to whether this is okay.
>>> The reason is simple: the kernel promises a stable ABI to userspace
>>> but not to kernel modules. By thinking of BPF as more like a module,
>>> you're taking a big shortcut that will either result in ABI breakage
>>> down the road or in committing to a problematic stable ABI.
>>
>>
>> you misunderstood the analogy.
>> bpf abi is certainly stable. that's why we were careful of not
>> exposing anything to it that is not already stable.
>>
>
> In that case I don't understand what you're trying to say. Eric
> thinks your patch exposes a bad interface. A bad interface for
> userspace is a very different thing from a bad interface available to
> kernel modules. Are you saying that BPF is kernel-module-like in that
> the ABI exposed to BPF programs doesn't need to meet the same quality
> standards as userspace ABIs?
of course not.
ns.inum is already exposed to user space as a value.
This patch exposes it to bpf program in a convenient and stable way,
therefore I don't see why it's a big deal to you and Eric and why it
has anything to do with namespaces in general. It doesn't change
any existing behavior and doesn't impose any new restrictions.
Like ns.inum can be moved around. User space visible field
'netns_inum' is a shadow of kernel field. Only 'netns_inum'
has to be stable and that is my headache.
The kernel module analogy is an attempt to explain that programs
can do insane things.
Like the user can create a socket attach a program to it, change
netns, create another socket and attach the same program.
Inside the program it can do 'if (skb->ifindex == xxx)'.
This would be nonsensical program, since ifindex is obviously scoped
by netns and comparing ifindex without regard to netns is bogus.
But kernel cannot prevent users to write such programs.
Hence the kernel module analogy: the kernel cannot prevent
nonsensical modules.
With this patch the user will be able to do
if (skb->netns_inum == ... && skb->ifindex == ...)
which would be more sane thing to do, but without appropriate
control plane, it's also nonsensical, since netns inode and
dev ifindex can disappear while the program is running.
We obviously don't want to pin net_devices and netns-es for the program.
It would be debugging nightmare. Therefore the user has to write
the program understanding all this.
^ permalink raw reply
* Re: netvsc NAPI patch process
From: David Miller @ 2017-01-26 18:06 UTC (permalink / raw)
To: stephen; +Cc: kys, greg, netdev
In-Reply-To: <20170126100405.0eac2dea@xeon-e3>
From: Stephen Hemminger <stephen@networkplumber.org>
Date: Thu, 26 Jan 2017 10:04:05 -0800
> I have a working set of patches to enable NAPI in the netvsc driver.
> The problem is that it requires a set of patches to vmbus layer as well.
> Since vmbus patches have been going through char-misc-next tree rather
> than net-next, it is difficult to stage these.
>
> How about if I send the vmbus patches through normal driver-devel upstream
> and during the 4.10 merge window send the last 3 patches for NAPI for linux-net
> tree to get into 4.10?
Another option is that the char-misc-next folks create a branch with just
the commits you need for NAPI, I pull that into net-next, and then you
can submit the NAPI changes to me.
^ permalink raw reply
* Re: [PATCH net 1/5] ibmvnic: harden interrupt handler
From: Stephen Hemminger @ 2017-01-26 18:28 UTC (permalink / raw)
To: Thomas Falcon; +Cc: netdev, wvoigt, jallen, linuxppc-dev, nfont
In-Reply-To: <1485378143-5084-1-git-send-email-tlfalcon@linux.vnet.ibm.com>
On Wed, 25 Jan 2017 15:02:19 -0600
Thomas Falcon <tlfalcon@linux.vnet.ibm.com> wrote:
> static irqreturn_t ibmvnic_interrupt(int irq, void *instance)
> {
> struct ibmvnic_adapter *adapter = instance;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&adapter->crq.lock, flags);
> + vio_disable_interrupts(adapter->vdev);
> + tasklet_schedule(&adapter->tasklet);
> + spin_unlock_irqrestore(&adapter->crq.lock, flags);
> + return IRQ_HANDLED;
> +}
> +
Why not use NAPI? rather than a tasklet
^ permalink raw reply
* Re: ip_rcv_finish() NULL pointer kernel panic
From: Eric Dumazet @ 2017-01-26 18:14 UTC (permalink / raw)
To: Florian Westphal; +Cc: Roy Keene, netdev, netfilter-devel
In-Reply-To: <1485453601.5145.142.camel@edumazet-glaptop3.roam.corp.google.com>
On Thu, 2017-01-26 at 10:00 -0800, Eric Dumazet wrote:
> On Thu, 2017-01-26 at 17:24 +0100, Florian Westphal wrote:
>
> > I think it makes sense to set dst->incoming
> > to a stub in br_netfilter_rtable_init() to just kfree_skb()+
> > WARN_ON_ONCE(), no need to add code to ip stack or crash kernel
> > due to brnf bug.
>
> Just kfree_skb() would hide bugs.
>
> Dropping packets is not uncommon in networking...
>
> I would rather use at least a WARN_ON_ONCE() before the kfree_skb() ;)
Oh well, I obviously did not parse properly your suggestion.
^ permalink raw reply
* Re: [PATCH net] net: Avoid receiving packets with an l3mdev on unbound UDP sockets
From: David Ahern @ 2017-01-26 18:12 UTC (permalink / raw)
To: Robert Shearman, davem; +Cc: netdev
In-Reply-To: <1485453744-5120-1-git-send-email-rshearma@brocade.com>
On 1/26/17 11:02 AM, Robert Shearman wrote:
> Packets arriving in a VRF currently are delivered to UDP sockets that
> aren't bound to any interface. TCP defaults to not delivering packets
> arriving in a VRF to unbound sockets. IP route lookup and socket
> transmit both assume that unbound means using the default table and
> UDP applications that haven't been changed to be aware of VRFs may not
> function correctly in this case since they may not be able to handle
> overlapping IP address ranges, or be able to send packets back to the
> original sender if required.
>
> So add a sysctl, udp_l3mdev_accept, to control this behaviour with it
> being analgous to the existing tcp_l3mdev_accept, namely to allow a
> process to have a VRF-global listen socket. Have this default to off
> as this is the behaviour that users will expect, given that there is
> no explicit mechanism to set unmodified VRF-unaware application into a
> default VRF.
>
> Signed-off-by: Robert Shearman <rshearma@brocade.com>
> ---
> I've targetted this for the net tree because I believe the expected
> behaviour is different enough from the current behaviour to be
> considered a bug. However, this should also apply to the net-next tree
> as-is if this not deemed a bug.
>
I have almost this exact patch in my tree and I have it marked as not working so 1 or more test cases is failing.
So, really this is just a note that I need to test this and need some time to get to it.
^ permalink raw reply
* Re: [PATCH net] bpf: expose netns inode to bpf programs
From: Andy Lutomirski @ 2017-01-26 18:12 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Linus Torvalds, Eric W. Biederman, David S . Miller,
Daniel Borkmann, David Ahern, Tejun Heo, Thomas Graf,
Network Development
In-Reply-To: <588A35F8.6050909@fb.com>
On Thu, Jan 26, 2017 at 9:46 AM, Alexei Starovoitov <ast@fb.com> wrote:
> On 1/26/17 8:37 AM, Andy Lutomirski wrote:
>>>
>>> Think of bpf programs as safe kernel modules. They don't have
>>> confined boundaries and program authors, if not careful, can shoot
>>> themselves in the foot. We're not trying to prevent that because
>>> it's impossible to check that the program is sane. Just like
>>> it's impossible to check that kernel module is sane.
>>> But in case of bpf we check that bpf program is _safe_ from the kernel
>>> point of view. If it's doing some garbage, it's program's business.
>>> Does it make more sense now?
>>>
>>
>> With all due respect, I think this is not an acceptable way to think
>> about BPF at all. If you think of BPF this way, I think there needs
>> to be a real discussion at KS or similar as to whether this is okay.
>> The reason is simple: the kernel promises a stable ABI to userspace
>> but not to kernel modules. By thinking of BPF as more like a module,
>> you're taking a big shortcut that will either result in ABI breakage
>> down the road or in committing to a problematic stable ABI.
>
>
> you misunderstood the analogy.
> bpf abi is certainly stable. that's why we were careful of not
> exposing anything to it that is not already stable.
>
In that case I don't understand what you're trying to say. Eric
thinks your patch exposes a bad interface. A bad interface for
userspace is a very different thing from a bad interface available to
kernel modules. Are you saying that BPF is kernel-module-like in that
the ABI exposed to BPF programs doesn't need to meet the same quality
standards as userspace ABIs?
--Andy
^ permalink raw reply
* Re: [PATCH net-next v2 0/2] net: ipv6: Improve user experience with multipath routes
From: David Miller @ 2017-01-26 18:00 UTC (permalink / raw)
To: dsa; +Cc: nicolas.dichtel, netdev
In-Reply-To: <c78afc85-8d18-0f63-68b3-63925e5d8c81@cumulusnetworks.com>
From: David Ahern <dsa@cumulusnetworks.com>
Date: Thu, 26 Jan 2017 10:26:51 -0700
> On 1/26/17 7:58 AM, Nicolas Dichtel wrote:
>> Le 24/01/2017 à 17:06, David Miller a écrit :
>>> From: David Ahern <dsa@cumulusnetworks.com>
>>> Date: Fri, 20 Jan 2017 12:31:44 -0700
>>>
>>>> BTW, I am in favor of not requiring a user API for this but just
>>>> doing it. I can't imagine anyone working with multipath routes not
>>>> wanting the efficiency of the RTA_MULTIPATH attribute. These patches
>>>> require an API only because of the rule not to break userspace. If
>>>> we conclude to just do it without an API, the multipath_add and
>>>> multipath_del need to be modified to only send a notification once
>>>> at the end of the actions.
>>>
>>> After some consideration, I agree.
>> Sorry for my late reply but I fear that this will break some userland apps like
>> quagga.
>
> Quagga does not properly handle IPv6 multipath routes received from
> the kernel. I checked this with debian/jessie version and our
> version, and Donald reviewed the source. It is broken.
If this is true, quagga is asbolutely not an argument for this "breaking"
something. It doesn't break anything.
^ permalink raw reply
* Re: [PATCH v1] net: phy: micrel: add KSZ8795 ethernet switch
From: Sean Nyekjær @ 2017-01-26 17:51 UTC (permalink / raw)
To: Andrew Lunn; +Cc: netdev
In-Reply-To: <20170123151219.GE10895@lunn.ch>
On 2017-01-23 16:12, Andrew Lunn wrote:
> On Mon, Jan 23, 2017 at 08:58:46AM +0100, Sean Nyekjaer wrote:
>> This is add support for the PHYs in the KSZ8795 5port managed switch.
>>
>> It will allow to detect the link between the switch and the soc
>> and uses the same read_status functions as the KSZ8873MLL switch.
>>
>> This ethernet switch have unfortunately the same phy id as KSZ8051.
>>
>> Signed-off-by: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
>> ---
>> drivers/net/phy/micrel.c | 14 ++++++++++++++
>> include/linux/micrel_phy.h | 2 ++
>> 2 files changed, 16 insertions(+)
>>
>> diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
>> index ea92d524d5a8..fa158ae5115b 100644
>> --- a/drivers/net/phy/micrel.c
>> +++ b/drivers/net/phy/micrel.c
>> @@ -1014,6 +1014,20 @@ static struct phy_driver ksphy_driver[] = {
>> .get_stats = kszphy_get_stats,
>> .suspend = genphy_suspend,
>> .resume = genphy_resume,
>> +}, {
>> + .phy_id = PHY_ID_KSZ8795,
>> + .phy_id_mask = MICREL_PHY_ID_MASK,
>> + .name = "Micrel KSZ8795 Switch",
> This name is confusing. You are adding support for the PHYs embedded
> in the switch, not the switch itself. The phylib has no idea these
> PHYs are inside a switch. It does not matter. It is just a PHY. Please
> drop the word "Switch".
>
> Thanks
> Andrew
Okay i'll understand :-)
I remove the word "Switch" from the commit message and phy name.
The rest is okay?
What is generally being done when to phy's have the same id, micrel have
done this many times...
/Sean
^ permalink raw reply
* Re: ip_rcv_finish() NULL pointer kernel panic
From: David Miller @ 2017-01-26 18:04 UTC (permalink / raw)
To: fw; +Cc: eric.dumazet, lkml, netdev, netfilter-devel
In-Reply-To: <20170126162433.GB1778@breakpoint.cc>
From: Florian Westphal <fw@strlen.de>
Date: Thu, 26 Jan 2017 17:24:33 +0100
> Eric Dumazet <eric.dumazet@gmail.com> wrote:
>> > Though possibly with different things not setting the "input" function
>> > pointer in the "struct dst_entry".
>> >
>> > include/net/dst.h:
>> > 496 static inline int dst_input(struct sk_buff *skb) {
>> > 498 return skb_dst(skb)->input(skb);
>> > 499 }
>> >
>> > Is there any reason not to check to see if this pointer is NULL before
>> > blindly calling it ?
>>
>> Sure. It can not be NULL at this point.
>>
>> Just look at the code in ip_rcv_finish() :
>>
>> It first make sure to get a valid dst.
>>
>> Something is broken, probably in bridge netfilter code.
>>
>> I suspect the dst here points to &br->fake_rtable, and this is not
>> expected.
>>
>> br_drop_fake_rtable() should have been called somewhere ...
>
> I think it makes sense to set dst->incoming
> to a stub in br_netfilter_rtable_init() to just kfree_skb()+
> WARN_ON_ONCE(), no need to add code to ip stack or crash kernel
> due to brnf bug.
That would certainly make recovery from such bugs must better.
But I have to say that this netfilter bridging fake dst has caused
several dozen bugs over the years, it is fundamentally a serious
problem in and of itself. It provides DST facilities by hand, in a
static object, without using any of the usual methods for creating and
facilitating dst objects.
Therefore every time someone makes an adjustment to common dst code,
this turd (and yes, it _is_ a turd) breaks. Every single time.
So in the long term, instead of polishing this turd, let's get rid of
it.
^ permalink raw reply
* [PATCH net] net: Avoid receiving packets with an l3mdev on unbound UDP sockets
From: Robert Shearman @ 2017-01-26 18:02 UTC (permalink / raw)
To: davem; +Cc: netdev, David Ahern, Robert Shearman
Packets arriving in a VRF currently are delivered to UDP sockets that
aren't bound to any interface. TCP defaults to not delivering packets
arriving in a VRF to unbound sockets. IP route lookup and socket
transmit both assume that unbound means using the default table and
UDP applications that haven't been changed to be aware of VRFs may not
function correctly in this case since they may not be able to handle
overlapping IP address ranges, or be able to send packets back to the
original sender if required.
So add a sysctl, udp_l3mdev_accept, to control this behaviour with it
being analgous to the existing tcp_l3mdev_accept, namely to allow a
process to have a VRF-global listen socket. Have this default to off
as this is the behaviour that users will expect, given that there is
no explicit mechanism to set unmodified VRF-unaware application into a
default VRF.
Signed-off-by: Robert Shearman <rshearma@brocade.com>
---
I've targetted this for the net tree because I believe the expected
behaviour is different enough from the current behaviour to be
considered a bug. However, this should also apply to the net-next tree
as-is if this not deemed a bug.
Documentation/networking/ip-sysctl.txt | 7 +++++++
Documentation/networking/vrf.txt | 7 ++++---
include/net/netns/ipv4.h | 4 ++++
net/ipv4/sysctl_net_ipv4.c | 11 +++++++++++
net/ipv4/udp.c | 27 ++++++++++++++++++++-------
net/ipv6/udp.c | 27 ++++++++++++++++++++-------
6 files changed, 66 insertions(+), 17 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 7dd65c9cf707..fa1f14977a0c 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -742,6 +742,13 @@ tcp_challenge_ack_limit - INTEGER
UDP variables:
+udp_l3mdev_accept - BOOLEAN
+ Enabling this option allows a "global" bound socket to work
+ across L3 master domains (e.g., VRFs) with packets capable of
+ being received regardless of the L3 domain in which they
+ originated. Only valid when the kernel was compiled with
+ CONFIG_NET_L3_MASTER_DEV.
+
udp_mem - vector of 3 INTEGERs: min, pressure, max
Number of pages allowed for queueing by all UDP sockets.
diff --git a/Documentation/networking/vrf.txt b/Documentation/networking/vrf.txt
index 755dab856392..3918dae964d4 100644
--- a/Documentation/networking/vrf.txt
+++ b/Documentation/networking/vrf.txt
@@ -98,10 +98,11 @@ VRF device:
or to specify the output device using cmsg and IP_PKTINFO.
-TCP services running in the default VRF context (ie., not bound to any VRF
-device) can work across all VRF domains by enabling the tcp_l3mdev_accept
-sysctl option:
+TCP & UDP services running in the default VRF context (ie., not bound
+to any VRF device) can work across all VRF domains by enabling the
+tcp_l3mdev_accept and udp_l3mdev_accept sysctl options:
sysctl -w net.ipv4.tcp_l3mdev_accept=1
+ sysctl -w net.ipv4.udp_l3mdev_accept=1
netfilter rules on the VRF device can be used to limit access to services
running in the default VRF context as well.
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 0378e88f6fd3..0822dced1b68 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -112,6 +112,10 @@ struct netns_ipv4 {
unsigned int sysctl_tcp_notsent_lowat;
int sysctl_tcp_tw_reuse;
+#ifdef CONFIG_NET_L3_MASTER_DEV
+ int sysctl_udp_l3mdev_accept;
+#endif
+
int sysctl_igmp_max_memberships;
int sysctl_igmp_max_msf;
int sysctl_igmp_llm_reports;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index b2fa498b15d1..a2ebbe6211ba 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -971,6 +971,17 @@ static struct ctl_table ipv4_net_table[] = {
.extra2 = &one,
},
#endif
+#ifdef CONFIG_NET_L3_MASTER_DEV
+ {
+ .procname = "udp_l3mdev_accept",
+ .data = &init_net.ipv4.sysctl_udp_l3mdev_accept,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+#endif
{ }
};
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1307a7c2e544..c7fcb7395ccf 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -134,6 +134,17 @@ EXPORT_SYMBOL(udp_memory_allocated);
#define MAX_UDP_PORTS 65536
#define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN)
+/* IPCB reference means this can not be used from early demux */
+static bool udp_lib_exact_dif_match(struct net *net, struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
+ if (!net->ipv4.sysctl_udp_l3mdev_accept &&
+ skb && ipv4_l3mdev_skb(IPCB(skb)->flags))
+ return true;
+#endif
+ return false;
+}
+
static int udp_lib_lport_inuse(struct net *net, __u16 num,
const struct udp_hslot *hslot,
unsigned long *bitmap,
@@ -394,7 +405,8 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
static int compute_score(struct sock *sk, struct net *net,
__be32 saddr, __be16 sport,
- __be32 daddr, unsigned short hnum, int dif)
+ __be32 daddr, unsigned short hnum, int dif,
+ bool exact_dif)
{
int score;
struct inet_sock *inet;
@@ -425,7 +437,7 @@ static int compute_score(struct sock *sk, struct net *net,
score += 4;
}
- if (sk->sk_bound_dev_if) {
+ if (sk->sk_bound_dev_if || exact_dif) {
if (sk->sk_bound_dev_if != dif)
return -1;
score += 4;
@@ -450,7 +462,7 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
/* called with rcu_read_lock() */
static struct sock *udp4_lib_lookup2(struct net *net,
__be32 saddr, __be16 sport,
- __be32 daddr, unsigned int hnum, int dif,
+ __be32 daddr, unsigned int hnum, int dif, bool exact_dif,
struct udp_hslot *hslot2,
struct sk_buff *skb)
{
@@ -462,7 +474,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
badness = 0;
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
score = compute_score(sk, net, saddr, sport,
- daddr, hnum, dif);
+ daddr, hnum, dif, exact_dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
@@ -497,6 +509,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
unsigned short hnum = ntohs(dport);
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
+ bool exact_dif = udp_lib_exact_dif_match(net, skb);
int score, badness, matches = 0, reuseport = 0;
u32 hash = 0;
@@ -509,7 +522,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
result = udp4_lib_lookup2(net, saddr, sport,
daddr, hnum, dif,
- hslot2, skb);
+ exact_dif, hslot2, skb);
if (!result) {
unsigned int old_slot2 = slot2;
hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
@@ -524,7 +537,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
result = udp4_lib_lookup2(net, saddr, sport,
daddr, hnum, dif,
- hslot2, skb);
+ exact_dif, hslot2, skb);
}
return result;
}
@@ -533,7 +546,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
badness = 0;
sk_for_each_rcu(sk, &hslot->head) {
score = compute_score(sk, net, saddr, sport,
- daddr, hnum, dif);
+ daddr, hnum, dif, exact_dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 4d5c4eee4b3f..f0bb414329ff 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -55,6 +55,16 @@
#include <trace/events/skb.h>
#include "udp_impl.h"
+static bool udp6_lib_exact_dif_match(struct net *net, struct sk_buff *skb)
+{
+#if defined(CONFIG_NET_L3_MASTER_DEV)
+ if (!net->ipv4.sysctl_udp_l3mdev_accept &&
+ skb && ipv6_l3mdev_skb(IP6CB(skb)->flags))
+ return true;
+#endif
+ return false;
+}
+
static u32 udp6_ehashfn(const struct net *net,
const struct in6_addr *laddr,
const u16 lport,
@@ -118,7 +128,7 @@ static void udp_v6_rehash(struct sock *sk)
static int compute_score(struct sock *sk, struct net *net,
const struct in6_addr *saddr, __be16 sport,
const struct in6_addr *daddr, unsigned short hnum,
- int dif)
+ int dif, bool exact_dif)
{
int score;
struct inet_sock *inet;
@@ -149,7 +159,7 @@ static int compute_score(struct sock *sk, struct net *net,
score++;
}
- if (sk->sk_bound_dev_if) {
+ if (sk->sk_bound_dev_if || exact_dif) {
if (sk->sk_bound_dev_if != dif)
return -1;
score++;
@@ -165,7 +175,7 @@ static int compute_score(struct sock *sk, struct net *net,
static struct sock *udp6_lib_lookup2(struct net *net,
const struct in6_addr *saddr, __be16 sport,
const struct in6_addr *daddr, unsigned int hnum, int dif,
- struct udp_hslot *hslot2,
+ bool exact_dif, struct udp_hslot *hslot2,
struct sk_buff *skb)
{
struct sock *sk, *result;
@@ -176,7 +186,7 @@ static struct sock *udp6_lib_lookup2(struct net *net,
badness = -1;
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
score = compute_score(sk, net, saddr, sport,
- daddr, hnum, dif);
+ daddr, hnum, dif, exact_dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
@@ -212,6 +222,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
unsigned short hnum = ntohs(dport);
unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
+ bool exact_dif = udp6_lib_exact_dif_match(net, skb);
int score, badness, matches = 0, reuseport = 0;
u32 hash = 0;
@@ -223,7 +234,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
goto begin;
result = udp6_lib_lookup2(net, saddr, sport,
- daddr, hnum, dif,
+ daddr, hnum, dif, exact_dif,
hslot2, skb);
if (!result) {
unsigned int old_slot2 = slot2;
@@ -239,7 +250,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
result = udp6_lib_lookup2(net, saddr, sport,
daddr, hnum, dif,
- hslot2, skb);
+ exact_dif, hslot2,
+ skb);
}
return result;
}
@@ -247,7 +259,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
result = NULL;
badness = -1;
sk_for_each_rcu(sk, &hslot->head) {
- score = compute_score(sk, net, saddr, sport, daddr, hnum, dif);
+ score = compute_score(sk, net, saddr, sport, daddr, hnum, dif,
+ exact_dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
--
2.1.4
^ permalink raw reply related
* netvsc NAPI patch process
From: Stephen Hemminger @ 2017-01-26 18:04 UTC (permalink / raw)
To: davem, K. Y. Srinivasan, Greg KH; +Cc: netdev
I have a working set of patches to enable NAPI in the netvsc driver.
The problem is that it requires a set of patches to vmbus layer as well.
Since vmbus patches have been going through char-misc-next tree rather
than net-next, it is difficult to stage these.
How about if I send the vmbus patches through normal driver-devel upstream
and during the 4.10 merge window send the last 3 patches for NAPI for linux-net
tree to get into 4.10?
^ permalink raw reply
* Re: [PATCH] Fix 64 bit addressing support for GEM
From: Florian Fainelli @ 2017-01-26 18:00 UTC (permalink / raw)
To: Rafal Ozieblo, Nicolas Ferre, netdev, linux-kernel,
harinikatakamlinux
In-Reply-To: <1485442837-26598-1-git-send-email-rafalo@cadence.com>
On 01/26/2017 07:00 AM, Rafal Ozieblo wrote:
> This patch adds support for 32 bit GEM in
> 64 bit system. It checks capability at runtime
> and uses appropriate buffer descriptor.
>
> Signed-off-by: Rafal Ozieblo <rafalo@cadence.com>
> ---
> static void *macb_rx_buffer(struct macb *bp, unsigned int index)
> @@ -560,12 +595,32 @@ static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb)
> }
> }
>
> -static inline void macb_set_addr(struct macb_dma_desc *desc, dma_addr_t addr)
> +static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr)
> {
> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> + struct macb_dma_desc_64 *desc_64;
> +
> + if (bp->hw_dma_cap == HW_DMA_CAP_64B) {
> + desc_64 = macb_64b_desc(bp, desc);
> + desc_64->addrh = (u32)(addr >> 32);
Are there specific ordering between the low and high halves of the
address that could influence how the hardware sees it? If so, might be
worth a comment about that, also, consider using upper_32_bits() for
assigning addrh.
> + }
> +#endif
> desc->addr = (u32)addr;
> +}
> +
> +static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc)
> +{
> + dma_addr_t addr = 0;
> #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> - desc->addrh = (u32)(addr >> 32);
> + struct macb_dma_desc_64 *desc_64;
> +
> + if (bp->hw_dma_cap == HW_DMA_CAP_64B) {
> + desc_64 = macb_64b_desc(bp, desc);
> + addr = ((u64)(desc_64->addrh) << 32);
Same here.
> + }
> #endif
> + addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
> + return addr;
> }
>
> static void macb_tx_error_task(struct work_struct *work)
> @@ -574,7 +629,7 @@ static void macb_tx_error_task(struct work_struct *work)
> tx_error_task);
> struct macb *bp = queue->bp;
> struct macb_tx_skb *tx_skb;
> - struct macb_dma_desc *desc;
> + struct macb_dma_desc *desc;
Unrelated change.
> struct sk_buff *skb;
> unsigned int tail;
> unsigned long flags;
> @@ -649,7 +704,7 @@ static void macb_tx_error_task(struct work_struct *work)
>
> /* Set end of TX queue */
> desc = macb_tx_desc(queue, 0);
> - macb_set_addr(desc, 0);
> + macb_set_addr(bp, desc, 0);
> desc->ctrl = MACB_BIT(TX_USED);
>
> /* Make descriptor updates visible to hardware */
> @@ -658,7 +713,8 @@ static void macb_tx_error_task(struct work_struct *work)
> /* Reinitialize the TX desc queue */
> queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma));
> #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> - queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32));
> + if (bp->hw_dma_cap == HW_DMA_CAP_64B)
> + queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32));
upper_32_bits() here as well.
There are more of these pattern that you may want to fix throughout your
entire submission since it makes it clear what part of the address you
are manipulating.
Thanks!
--
Florian
^ permalink raw reply
* Re: ip_rcv_finish() NULL pointer kernel panic
From: Eric Dumazet @ 2017-01-26 18:00 UTC (permalink / raw)
To: Florian Westphal; +Cc: Roy Keene, netdev, netfilter-devel
In-Reply-To: <20170126162433.GB1778@breakpoint.cc>
On Thu, 2017-01-26 at 17:24 +0100, Florian Westphal wrote:
> I think it makes sense to set dst->incoming
> to a stub in br_netfilter_rtable_init() to just kfree_skb()+
> WARN_ON_ONCE(), no need to add code to ip stack or crash kernel
> due to brnf bug.
Just kfree_skb() would hide bugs.
Dropping packets is not uncommon in networking...
I would rather use at least a WARN_ON_ONCE() before the kfree_skb() ;)
^ permalink raw reply
* Re: [PATCH 00/14] Netfilter fixes for net
From: David Miller @ 2017-01-26 17:59 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1485448687-6072-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 26 Jan 2017 17:37:53 +0100
> The following patchset contains a large batch with Netfilter fixes for
> your net tree, they are:
...
> You can pull these changes from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
Pulled, thanks!
^ permalink raw reply
* Re: [PATCH net 2/5] ibmvnic: Fix MTU settings
From: David Miller @ 2017-01-26 17:56 UTC (permalink / raw)
To: tlfalcon; +Cc: netdev, wvoigt, jallen, linuxppc-dev, nfont
In-Reply-To: <783c7683-1cc2-6128-e19c-fd2c3c16cf4b@linux.vnet.ibm.com>
From: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
Date: Thu, 26 Jan 2017 10:44:31 -0600
> On 01/25/2017 10:05 PM, David Miller wrote:
>> From: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>> Date: Wed, 25 Jan 2017 15:02:20 -0600
>>
>>> In the current driver, the MTU is set to the maximum value
>>> capable for the backing device. This patch sets the MTU to the
>>> default value for a Linux net device.
>> Why are you doing this?
>>
>> What happens to users who depend upon the current behavior.
>>
>> They will break, and that isn't acceptable.
>>
> The current behavior was already broken. We were seeing firmware errors when sending jumbo sized packets . We plan to add proper support for jumbo sized packets as soon as possible.
Need to be explained, with a full detailed history of how things got this way,
in your commit message.
^ permalink raw reply
* Re: [PATCH net 1/5] ibmvnic: harden interrupt handler
From: David Miller @ 2017-01-26 17:56 UTC (permalink / raw)
To: tlfalcon; +Cc: netdev, wvoigt, jallen, linuxppc-dev, nfont
In-Reply-To: <0cea7654-6722-5e68-cd05-cc51bbf7a5ae@linux.vnet.ibm.com>
From: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
Date: Thu, 26 Jan 2017 10:44:22 -0600
> On 01/25/2017 10:04 PM, David Miller wrote:
>> From: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>> Date: Wed, 25 Jan 2017 15:02:19 -0600
>>
>>> Move most interrupt handler processing into a tasklet, and
>>> introduce a delay after re-enabling interrupts to fix timing
>>> issues encountered in hardware testing.
>>>
>>> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
>> I don't think you have any idea what the real problem is. This looks
>> like a hack, at best. Next patch you'll increase the delay to "20",
>> right? And if that doesn't work you'll try "40".
>>
>> Or if you do know the reason, you need to explain it in detail in this
>> commit message so that we can properly evaluate this patch.
>
> You're right, I should have given more explanation in the commit message about the bug encountered and our reasons for this sort of fix. The issue is that there are some scenarios during the device init where multiple messages are sent by firmware in one interrupt request.
>
> We have observed behavior where messages are delayed, resulting in the interrupt handler completing before the delayed messages can be processed, fouling up the device bring-up in the device probing and elsewhere. The goal of the delay is to buy some time for the hypervisor to forward all the CRQ messages from the firmware.
Then isn't there an event you can sleep and wait for, or a piece of state for
you to poll and test for in a timeout based loop?
This delay is a bad solution for the problem of waiting for A to happen
before you do B.
^ permalink raw reply
* [PATCH net-next 3/3] sfc: insert catch-all filters for encapsulated traffic
From: Edward Cree @ 2017-01-26 17:54 UTC (permalink / raw)
To: linux-net-drivers, davem; +Cc: netdev
In-Reply-To: <39d8923f-4400-506c-dd50-250636ff83fa@solarflare.com>
8000 series adapters support filtering VXLAN, NVGRE and GENEVE traffic
based on inner fields, and when the NIC recognises such traffic, it
does not match unencapsulated traffic filters any more. So add catch-
all filters for encapsulated traffic on supporting platforms.
Although recognition of VXLAN and GENEVE is based on UDP ports, and thus
will not occur until the driver (on the primary PF) notifies the
firmware of UDP ports to use, NVGRE will always be recognised, hence
without this patch 8000 series adapters will drop all NVGRE traffic.
Partly based on patches by Jon Cooper <jcooper@solarflare.com>.
Signed-off-by: Edward Cree <ecree@solarflare.com>
---
drivers/net/ethernet/sfc/ef10.c | 554 ++++++++++++++++++++++++++++----------
drivers/net/ethernet/sfc/filter.h | 41 ++-
2 files changed, 449 insertions(+), 146 deletions(-)
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index d0c1ed0e..8bec938 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -60,15 +60,33 @@ struct efx_ef10_vlan {
u16 vid;
};
+enum efx_ef10_default_filters {
+ EFX_EF10_BCAST,
+ EFX_EF10_UCDEF,
+ EFX_EF10_MCDEF,
+ EFX_EF10_VXLAN4_UCDEF,
+ EFX_EF10_VXLAN4_MCDEF,
+ EFX_EF10_VXLAN6_UCDEF,
+ EFX_EF10_VXLAN6_MCDEF,
+ EFX_EF10_NVGRE4_UCDEF,
+ EFX_EF10_NVGRE4_MCDEF,
+ EFX_EF10_NVGRE6_UCDEF,
+ EFX_EF10_NVGRE6_MCDEF,
+ EFX_EF10_GENEVE4_UCDEF,
+ EFX_EF10_GENEVE4_MCDEF,
+ EFX_EF10_GENEVE6_UCDEF,
+ EFX_EF10_GENEVE6_MCDEF,
+
+ EFX_EF10_NUM_DEFAULT_FILTERS
+};
+
/* Per-VLAN filters information */
struct efx_ef10_filter_vlan {
struct list_head list;
u16 vid;
u16 uc[EFX_EF10_FILTER_DEV_UC_MAX];
u16 mc[EFX_EF10_FILTER_DEV_MC_MAX];
- u16 ucdef;
- u16 bcast;
- u16 mcdef;
+ u16 default_filters[EFX_EF10_NUM_DEFAULT_FILTERS];
};
struct efx_ef10_dev_addr {
@@ -78,7 +96,7 @@ struct efx_ef10_dev_addr {
struct efx_ef10_filter_table {
/* The MCDI match masks supported by this fw & hw, in order of priority */
u32 rx_match_mcdi_flags[
- MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MAXNUM];
+ MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MAXNUM * 2];
unsigned int rx_match_count;
struct {
@@ -3592,6 +3610,104 @@ efx_ef10_filter_set_entry(struct efx_ef10_filter_table *table,
table->entry[filter_idx].spec = (unsigned long)spec | flags;
}
+static void
+efx_ef10_filter_push_prep_set_match_fields(struct efx_nic *efx,
+ const struct efx_filter_spec *spec,
+ efx_dword_t *inbuf)
+{
+ enum efx_encap_type encap_type = efx_filter_get_encap_type(spec);
+ u32 match_fields = 0, uc_match, mc_match;
+
+ MCDI_SET_DWORD(inbuf, FILTER_OP_IN_OP,
+ efx_ef10_filter_is_exclusive(spec) ?
+ MC_CMD_FILTER_OP_IN_OP_INSERT :
+ MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE);
+
+ /* Convert match flags and values. Unlike almost
+ * everything else in MCDI, these fields are in
+ * network byte order.
+ */
+#define COPY_VALUE(value, mcdi_field) \
+ do { \
+ match_fields |= \
+ 1 << MC_CMD_FILTER_OP_IN_MATCH_ ## \
+ mcdi_field ## _LBN; \
+ BUILD_BUG_ON( \
+ MC_CMD_FILTER_OP_IN_ ## mcdi_field ## _LEN < \
+ sizeof(value)); \
+ memcpy(MCDI_PTR(inbuf, FILTER_OP_IN_ ## mcdi_field), \
+ &value, sizeof(value)); \
+ } while (0)
+#define COPY_FIELD(gen_flag, gen_field, mcdi_field) \
+ if (spec->match_flags & EFX_FILTER_MATCH_ ## gen_flag) { \
+ COPY_VALUE(spec->gen_field, mcdi_field); \
+ }
+ /* Handle encap filters first. They will always be mismatch
+ * (unknown UC or MC) filters
+ */
+ if (encap_type) {
+ /* ether_type and outer_ip_proto need to be variables
+ * because COPY_VALUE wants to memcpy them
+ */
+ __be16 ether_type =
+ htons(encap_type & EFX_ENCAP_FLAG_IPV6 ?
+ ETH_P_IPV6 : ETH_P_IP);
+ u8 vni_type = MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE;
+ u8 outer_ip_proto;
+
+ switch (encap_type & EFX_ENCAP_TYPES_MASK) {
+ case EFX_ENCAP_TYPE_VXLAN:
+ vni_type = MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN;
+ /* fallthrough */
+ case EFX_ENCAP_TYPE_GENEVE:
+ COPY_VALUE(ether_type, ETHER_TYPE);
+ outer_ip_proto = IPPROTO_UDP;
+ COPY_VALUE(outer_ip_proto, IP_PROTO);
+ /* We always need to set the type field, even
+ * though we're not matching on the TNI.
+ */
+ MCDI_POPULATE_DWORD_1(inbuf,
+ FILTER_OP_EXT_IN_VNI_OR_VSID,
+ FILTER_OP_EXT_IN_VNI_TYPE,
+ vni_type);
+ break;
+ case EFX_ENCAP_TYPE_NVGRE:
+ COPY_VALUE(ether_type, ETHER_TYPE);
+ outer_ip_proto = IPPROTO_GRE;
+ COPY_VALUE(outer_ip_proto, IP_PROTO);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ uc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST_LBN;
+ mc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST_LBN;
+ } else {
+ uc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
+ mc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST_LBN;
+ }
+
+ if (spec->match_flags & EFX_FILTER_MATCH_LOC_MAC_IG)
+ match_fields |=
+ is_multicast_ether_addr(spec->loc_mac) ?
+ 1 << mc_match :
+ 1 << uc_match;
+ COPY_FIELD(REM_HOST, rem_host, SRC_IP);
+ COPY_FIELD(LOC_HOST, loc_host, DST_IP);
+ COPY_FIELD(REM_MAC, rem_mac, SRC_MAC);
+ COPY_FIELD(REM_PORT, rem_port, SRC_PORT);
+ COPY_FIELD(LOC_MAC, loc_mac, DST_MAC);
+ COPY_FIELD(LOC_PORT, loc_port, DST_PORT);
+ COPY_FIELD(ETHER_TYPE, ether_type, ETHER_TYPE);
+ COPY_FIELD(INNER_VID, inner_vid, INNER_VLAN);
+ COPY_FIELD(OUTER_VID, outer_vid, OUTER_VLAN);
+ COPY_FIELD(IP_PROTO, ip_proto, IP_PROTO);
+#undef COPY_FIELD
+#undef COPY_VALUE
+ MCDI_SET_DWORD(inbuf, FILTER_OP_IN_MATCH_FIELDS,
+ match_fields);
+}
+
static void efx_ef10_filter_push_prep(struct efx_nic *efx,
const struct efx_filter_spec *spec,
efx_dword_t *inbuf, u64 handle,
@@ -3600,7 +3716,7 @@ static void efx_ef10_filter_push_prep(struct efx_nic *efx,
struct efx_ef10_nic_data *nic_data = efx->nic_data;
u32 flags = spec->flags;
- memset(inbuf, 0, MC_CMD_FILTER_OP_IN_LEN);
+ memset(inbuf, 0, MC_CMD_FILTER_OP_EXT_IN_LEN);
/* Remove RSS flag if we don't have an RSS context. */
if (flags & EFX_FILTER_FLAG_RX_RSS &&
@@ -3613,46 +3729,7 @@ static void efx_ef10_filter_push_prep(struct efx_nic *efx,
MC_CMD_FILTER_OP_IN_OP_REPLACE);
MCDI_SET_QWORD(inbuf, FILTER_OP_IN_HANDLE, handle);
} else {
- u32 match_fields = 0;
-
- MCDI_SET_DWORD(inbuf, FILTER_OP_IN_OP,
- efx_ef10_filter_is_exclusive(spec) ?
- MC_CMD_FILTER_OP_IN_OP_INSERT :
- MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE);
-
- /* Convert match flags and values. Unlike almost
- * everything else in MCDI, these fields are in
- * network byte order.
- */
- if (spec->match_flags & EFX_FILTER_MATCH_LOC_MAC_IG)
- match_fields |=
- is_multicast_ether_addr(spec->loc_mac) ?
- 1 << MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN :
- 1 << MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
-#define COPY_FIELD(gen_flag, gen_field, mcdi_field) \
- if (spec->match_flags & EFX_FILTER_MATCH_ ## gen_flag) { \
- match_fields |= \
- 1 << MC_CMD_FILTER_OP_IN_MATCH_ ## \
- mcdi_field ## _LBN; \
- BUILD_BUG_ON( \
- MC_CMD_FILTER_OP_IN_ ## mcdi_field ## _LEN < \
- sizeof(spec->gen_field)); \
- memcpy(MCDI_PTR(inbuf, FILTER_OP_IN_ ## mcdi_field), \
- &spec->gen_field, sizeof(spec->gen_field)); \
- }
- COPY_FIELD(REM_HOST, rem_host, SRC_IP);
- COPY_FIELD(LOC_HOST, loc_host, DST_IP);
- COPY_FIELD(REM_MAC, rem_mac, SRC_MAC);
- COPY_FIELD(REM_PORT, rem_port, SRC_PORT);
- COPY_FIELD(LOC_MAC, loc_mac, DST_MAC);
- COPY_FIELD(LOC_PORT, loc_port, DST_PORT);
- COPY_FIELD(ETHER_TYPE, ether_type, ETHER_TYPE);
- COPY_FIELD(INNER_VID, inner_vid, INNER_VLAN);
- COPY_FIELD(OUTER_VID, outer_vid, OUTER_VLAN);
- COPY_FIELD(IP_PROTO, ip_proto, IP_PROTO);
-#undef COPY_FIELD
- MCDI_SET_DWORD(inbuf, FILTER_OP_IN_MATCH_FIELDS,
- match_fields);
+ efx_ef10_filter_push_prep_set_match_fields(efx, spec, inbuf);
}
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, nic_data->vport_id);
@@ -3681,8 +3758,8 @@ static int efx_ef10_filter_push(struct efx_nic *efx,
const struct efx_filter_spec *spec,
u64 *handle, bool replacing)
{
- MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_IN_LEN);
- MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_OUT_LEN);
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN);
int rc;
efx_ef10_filter_push_prep(efx, spec, inbuf, *handle, replacing);
@@ -3697,37 +3774,58 @@ static int efx_ef10_filter_push(struct efx_nic *efx,
static u32 efx_ef10_filter_mcdi_flags_from_spec(const struct efx_filter_spec *spec)
{
+ enum efx_encap_type encap_type = efx_filter_get_encap_type(spec);
unsigned int match_flags = spec->match_flags;
+ unsigned int uc_match, mc_match;
u32 mcdi_flags = 0;
- if (match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
- match_flags &= ~EFX_FILTER_MATCH_LOC_MAC_IG;
- mcdi_flags |=
- is_multicast_ether_addr(spec->loc_mac) ?
- (1 << MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) :
- (1 << MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN);
- }
-
-#define MAP_FILTER_TO_MCDI_FLAG(gen_flag, mcdi_field) { \
- unsigned int old_match_flags = match_flags; \
+#define MAP_FILTER_TO_MCDI_FLAG(gen_flag, mcdi_field, encap) { \
+ unsigned int old_match_flags = match_flags; \
match_flags &= ~EFX_FILTER_MATCH_ ## gen_flag; \
if (match_flags != old_match_flags) \
mcdi_flags |= \
- (1 << MC_CMD_FILTER_OP_IN_MATCH_ ## \
- mcdi_field ## _LBN); \
+ (1 << ((encap) ? \
+ MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_ ## \
+ mcdi_field ## _LBN : \
+ MC_CMD_FILTER_OP_EXT_IN_MATCH_ ##\
+ mcdi_field ## _LBN)); \
}
- MAP_FILTER_TO_MCDI_FLAG(REM_HOST, SRC_IP);
- MAP_FILTER_TO_MCDI_FLAG(LOC_HOST, DST_IP);
- MAP_FILTER_TO_MCDI_FLAG(REM_MAC, SRC_MAC);
- MAP_FILTER_TO_MCDI_FLAG(REM_PORT, SRC_PORT);
- MAP_FILTER_TO_MCDI_FLAG(LOC_MAC, DST_MAC);
- MAP_FILTER_TO_MCDI_FLAG(LOC_PORT, DST_PORT);
- MAP_FILTER_TO_MCDI_FLAG(ETHER_TYPE, ETHER_TYPE);
- MAP_FILTER_TO_MCDI_FLAG(INNER_VID, INNER_VLAN);
- MAP_FILTER_TO_MCDI_FLAG(OUTER_VID, OUTER_VLAN);
- MAP_FILTER_TO_MCDI_FLAG(IP_PROTO, IP_PROTO);
+ /* inner or outer based on encap type */
+ MAP_FILTER_TO_MCDI_FLAG(REM_HOST, SRC_IP, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(LOC_HOST, DST_IP, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(REM_MAC, SRC_MAC, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(REM_PORT, SRC_PORT, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(LOC_MAC, DST_MAC, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(LOC_PORT, DST_PORT, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(ETHER_TYPE, ETHER_TYPE, encap_type);
+ MAP_FILTER_TO_MCDI_FLAG(IP_PROTO, IP_PROTO, encap_type);
+ /* always outer */
+ MAP_FILTER_TO_MCDI_FLAG(INNER_VID, INNER_VLAN, false);
+ MAP_FILTER_TO_MCDI_FLAG(OUTER_VID, OUTER_VLAN, false);
#undef MAP_FILTER_TO_MCDI_FLAG
+ /* special handling for encap type, and mismatch */
+ if (encap_type) {
+ match_flags &= ~EFX_FILTER_MATCH_ENCAP_TYPE;
+ mcdi_flags |=
+ (1 << MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE_LBN);
+ mcdi_flags |= (1 << MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO_LBN);
+
+ uc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST_LBN;
+ mc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST_LBN;
+ } else {
+ uc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST_LBN;
+ mc_match = MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST_LBN;
+ }
+
+ if (match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) {
+ match_flags &= ~EFX_FILTER_MATCH_LOC_MAC_IG;
+ mcdi_flags |=
+ is_multicast_ether_addr(spec->loc_mac) ?
+ 1 << mc_match :
+ 1 << uc_match;
+ }
+
/* Did we map them all? */
WARN_ON_ONCE(match_flags);
@@ -4387,29 +4485,54 @@ efx_ef10_filter_rfs_expire_complete(struct efx_nic *efx,
#endif /* CONFIG_RFS_ACCEL */
-static int efx_ef10_filter_match_flags_from_mcdi(u32 mcdi_flags)
+static int efx_ef10_filter_match_flags_from_mcdi(bool encap, u32 mcdi_flags)
{
int match_flags = 0;
-#define MAP_FLAG(gen_flag, mcdi_field) { \
+#define MAP_FLAG(gen_flag, mcdi_field) do { \
u32 old_mcdi_flags = mcdi_flags; \
- mcdi_flags &= ~(1 << MC_CMD_FILTER_OP_IN_MATCH_ ## \
- mcdi_field ## _LBN); \
+ mcdi_flags &= ~(1 << MC_CMD_FILTER_OP_EXT_IN_MATCH_ ## \
+ mcdi_field ## _LBN); \
if (mcdi_flags != old_mcdi_flags) \
match_flags |= EFX_FILTER_MATCH_ ## gen_flag; \
+ } while (0)
+
+ if (encap) {
+ /* encap filters must specify encap type */
+ match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+ /* and imply ethertype and ip proto */
+ mcdi_flags &=
+ ~(1 << MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO_LBN);
+ mcdi_flags &=
+ ~(1 << MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE_LBN);
+ /* VLAN tags refer to the outer packet */
+ MAP_FLAG(INNER_VID, INNER_VLAN);
+ MAP_FLAG(OUTER_VID, OUTER_VLAN);
+ /* everything else refers to the inner packet */
+ MAP_FLAG(LOC_MAC_IG, IFRM_UNKNOWN_UCAST_DST);
+ MAP_FLAG(LOC_MAC_IG, IFRM_UNKNOWN_MCAST_DST);
+ MAP_FLAG(REM_HOST, IFRM_SRC_IP);
+ MAP_FLAG(LOC_HOST, IFRM_DST_IP);
+ MAP_FLAG(REM_MAC, IFRM_SRC_MAC);
+ MAP_FLAG(REM_PORT, IFRM_SRC_PORT);
+ MAP_FLAG(LOC_MAC, IFRM_DST_MAC);
+ MAP_FLAG(LOC_PORT, IFRM_DST_PORT);
+ MAP_FLAG(ETHER_TYPE, IFRM_ETHER_TYPE);
+ MAP_FLAG(IP_PROTO, IFRM_IP_PROTO);
+ } else {
+ MAP_FLAG(LOC_MAC_IG, UNKNOWN_UCAST_DST);
+ MAP_FLAG(LOC_MAC_IG, UNKNOWN_MCAST_DST);
+ MAP_FLAG(REM_HOST, SRC_IP);
+ MAP_FLAG(LOC_HOST, DST_IP);
+ MAP_FLAG(REM_MAC, SRC_MAC);
+ MAP_FLAG(REM_PORT, SRC_PORT);
+ MAP_FLAG(LOC_MAC, DST_MAC);
+ MAP_FLAG(LOC_PORT, DST_PORT);
+ MAP_FLAG(ETHER_TYPE, ETHER_TYPE);
+ MAP_FLAG(INNER_VID, INNER_VLAN);
+ MAP_FLAG(OUTER_VID, OUTER_VLAN);
+ MAP_FLAG(IP_PROTO, IP_PROTO);
}
- MAP_FLAG(LOC_MAC_IG, UNKNOWN_UCAST_DST);
- MAP_FLAG(LOC_MAC_IG, UNKNOWN_MCAST_DST);
- MAP_FLAG(REM_HOST, SRC_IP);
- MAP_FLAG(LOC_HOST, DST_IP);
- MAP_FLAG(REM_MAC, SRC_MAC);
- MAP_FLAG(REM_PORT, SRC_PORT);
- MAP_FLAG(LOC_MAC, DST_MAC);
- MAP_FLAG(LOC_PORT, DST_PORT);
- MAP_FLAG(ETHER_TYPE, ETHER_TYPE);
- MAP_FLAG(INNER_VID, INNER_VLAN);
- MAP_FLAG(OUTER_VID, OUTER_VLAN);
- MAP_FLAG(IP_PROTO, IP_PROTO);
#undef MAP_FLAG
/* Did we map them all? */
@@ -4436,6 +4559,7 @@ static void efx_ef10_filter_cleanup_vlans(struct efx_nic *efx)
}
static bool efx_ef10_filter_match_supported(struct efx_ef10_filter_table *table,
+ bool encap,
enum efx_filter_match_flags match_flags)
{
unsigned int match_pri;
@@ -4444,7 +4568,7 @@ static bool efx_ef10_filter_match_supported(struct efx_ef10_filter_table *table,
for (match_pri = 0;
match_pri < table->rx_match_count;
match_pri++) {
- mf = efx_ef10_filter_match_flags_from_mcdi(
+ mf = efx_ef10_filter_match_flags_from_mcdi(encap,
table->rx_match_mcdi_flags[match_pri]);
if (mf == match_flags)
return true;
@@ -4453,39 +4577,30 @@ static bool efx_ef10_filter_match_supported(struct efx_ef10_filter_table *table,
return false;
}
-static int efx_ef10_filter_table_probe(struct efx_nic *efx)
+static int
+efx_ef10_filter_table_probe_matches(struct efx_nic *efx,
+ struct efx_ef10_filter_table *table,
+ bool encap)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PARSER_DISP_INFO_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX);
- struct efx_ef10_nic_data *nic_data = efx->nic_data;
- struct net_device *net_dev = efx->net_dev;
unsigned int pd_match_pri, pd_match_count;
- struct efx_ef10_filter_table *table;
- struct efx_ef10_vlan *vlan;
size_t outlen;
int rc;
- if (!efx_rwsem_assert_write_locked(&efx->filter_sem))
- return -EINVAL;
-
- if (efx->filter_state) /* already probed */
- return 0;
-
- table = kzalloc(sizeof(*table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
-
/* Find out which RX filter types are supported, and their priorities */
MCDI_SET_DWORD(inbuf, GET_PARSER_DISP_INFO_IN_OP,
+ encap ?
+ MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
rc = efx_mcdi_rpc(efx, MC_CMD_GET_PARSER_DISP_INFO,
inbuf, sizeof(inbuf), outbuf, sizeof(outbuf),
&outlen);
if (rc)
- goto fail;
+ return rc;
+
pd_match_count = MCDI_VAR_ARRAY_LEN(
outlen, GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES);
- table->rx_match_count = 0;
for (pd_match_pri = 0; pd_match_pri < pd_match_count; pd_match_pri++) {
u32 mcdi_flags =
@@ -4493,7 +4608,7 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx)
outbuf,
GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES,
pd_match_pri);
- rc = efx_ef10_filter_match_flags_from_mcdi(mcdi_flags);
+ rc = efx_ef10_filter_match_flags_from_mcdi(encap, mcdi_flags);
if (rc < 0) {
netif_dbg(efx, probe, efx->net_dev,
"%s: fw flags %#x pri %u not supported in driver\n",
@@ -4508,10 +4623,40 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx)
}
}
+ return 0;
+}
+
+static int efx_ef10_filter_table_probe(struct efx_nic *efx)
+{
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ struct net_device *net_dev = efx->net_dev;
+ struct efx_ef10_filter_table *table;
+ struct efx_ef10_vlan *vlan;
+ int rc;
+
+ if (!efx_rwsem_assert_write_locked(&efx->filter_sem))
+ return -EINVAL;
+
+ if (efx->filter_state) /* already probed */
+ return 0;
+
+ table = kzalloc(sizeof(*table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ table->rx_match_count = 0;
+ rc = efx_ef10_filter_table_probe_matches(efx, table, false);
+ if (rc)
+ goto fail;
+ if (nic_data->datapath_caps &
+ (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN))
+ rc = efx_ef10_filter_table_probe_matches(efx, table, true);
+ if (rc)
+ goto fail;
if ((efx_supported_features(efx) & NETIF_F_HW_VLAN_CTAG_FILTER) &&
- !(efx_ef10_filter_match_supported(table,
+ !(efx_ef10_filter_match_supported(table, false,
(EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC)) &&
- efx_ef10_filter_match_supported(table,
+ efx_ef10_filter_match_supported(table, false,
(EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC_IG)))) {
netif_info(efx, probe, net_dev,
"VLAN filters are not supported in this firmware variant\n");
@@ -4563,7 +4708,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
unsigned int filter_idx;
u32 mcdi_flags;
int match_pri;
- int rc;
+ int rc, i;
WARN_ON(!rwsem_is_locked(&efx->filter_sem));
@@ -4606,14 +4751,12 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
if (rc) {
not_restored:
- list_for_each_entry(vlan, &table->vlan_list, list) {
- if (vlan->ucdef == filter_idx)
- vlan->ucdef = EFX_EF10_FILTER_ID_INVALID;
- if (vlan->mcdef == filter_idx)
- vlan->mcdef = EFX_EF10_FILTER_ID_INVALID;
- if (vlan->bcast == filter_idx)
- vlan->bcast = EFX_EF10_FILTER_ID_INVALID;
- }
+ list_for_each_entry(vlan, &table->vlan_list, list)
+ for (i = 0; i < EFX_EF10_NUM_DEFAULT_FILTERS; ++i)
+ if (vlan->default_filters[i] == filter_idx)
+ vlan->default_filters[i] =
+ EFX_EF10_FILTER_ID_INVALID;
+
kfree(spec);
efx_ef10_filter_set_entry(table, filter_idx, NULL, 0);
} else {
@@ -4712,9 +4855,8 @@ static void _efx_ef10_filter_vlan_mark_old(struct efx_nic *efx,
efx_ef10_filter_mark_one_old(efx, &vlan->uc[i]);
for (i = 0; i < table->dev_mc_count; i++)
efx_ef10_filter_mark_one_old(efx, &vlan->mc[i]);
- efx_ef10_filter_mark_one_old(efx, &vlan->ucdef);
- efx_ef10_filter_mark_one_old(efx, &vlan->bcast);
- efx_ef10_filter_mark_one_old(efx, &vlan->mcdef);
+ for (i = 0; i < EFX_EF10_NUM_DEFAULT_FILTERS; i++)
+ efx_ef10_filter_mark_one_old(efx, &vlan->default_filters[i]);
}
/* Mark old filters that may need to be removed.
@@ -4832,6 +4974,8 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
if (multicast && rollback) {
/* Also need an Ethernet broadcast filter */
+ EFX_WARN_ON_PARANOID(vlan->default_filters[EFX_EF10_BCAST] !=
+ EFX_EF10_FILTER_ID_INVALID);
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
eth_broadcast_addr(baddr);
efx_filter_set_eth_local(&spec, vlan->vid, baddr);
@@ -4848,9 +4992,8 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
}
return rc;
} else {
- EFX_WARN_ON_PARANOID(vlan->bcast !=
- EFX_EF10_FILTER_ID_INVALID);
- vlan->bcast = efx_ef10_filter_get_unsafe_id(efx, rc);
+ vlan->default_filters[EFX_EF10_BCAST] =
+ efx_ef10_filter_get_unsafe_id(efx, rc);
}
}
@@ -4859,6 +5002,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
static int efx_ef10_filter_insert_def(struct efx_nic *efx,
struct efx_ef10_filter_vlan *vlan,
+ enum efx_encap_type encap_type,
bool multicast, bool rollback)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
@@ -4866,6 +5010,7 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx,
struct efx_filter_spec spec;
u8 baddr[ETH_ALEN];
int rc;
+ u16 *id;
filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0;
@@ -4876,19 +5021,75 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx,
else
efx_filter_set_uc_def(&spec);
+ if (encap_type) {
+ if (nic_data->datapath_caps &
+ (1 << MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN))
+ efx_filter_set_encap_type(&spec, encap_type);
+ else
+ /* don't insert encap filters on non-supporting
+ * platforms. ID will be left as INVALID.
+ */
+ return 0;
+ }
+
if (vlan->vid != EFX_FILTER_VID_UNSPEC)
efx_filter_set_eth_local(&spec, vlan->vid, NULL);
rc = efx_ef10_filter_insert(efx, &spec, true);
if (rc < 0) {
+ const char *um = multicast ? "Multicast" : "Unicast";
+ const char *encap_name = "";
+ const char *encap_ipv = "";
+
+ if ((encap_type & EFX_ENCAP_TYPES_MASK) ==
+ EFX_ENCAP_TYPE_VXLAN)
+ encap_name = "VXLAN ";
+ else if ((encap_type & EFX_ENCAP_TYPES_MASK) ==
+ EFX_ENCAP_TYPE_NVGRE)
+ encap_name = "NVGRE ";
+ else if ((encap_type & EFX_ENCAP_TYPES_MASK) ==
+ EFX_ENCAP_TYPE_GENEVE)
+ encap_name = "GENEVE ";
+ if (encap_type & EFX_ENCAP_FLAG_IPV6)
+ encap_ipv = "IPv6 ";
+ else if (encap_type)
+ encap_ipv = "IPv4 ";
+
+ /* unprivileged functions can't insert mismatch filters
+ * for encapsulated or unicast traffic, so downgrade
+ * those warnings to debug.
+ */
netif_cond_dbg(efx, drv, efx->net_dev,
- rc == -EPERM, warn,
- "%scast mismatch filter insert failed rc=%d\n",
- multicast ? "Multi" : "Uni", rc);
+ rc == -EPERM && (encap_type || !multicast), warn,
+ "%s%s%s mismatch filter insert failed rc=%d\n",
+ encap_name, encap_ipv, um, rc);
} else if (multicast) {
- EFX_WARN_ON_PARANOID(vlan->mcdef != EFX_EF10_FILTER_ID_INVALID);
- vlan->mcdef = efx_ef10_filter_get_unsafe_id(efx, rc);
- if (!nic_data->workaround_26807) {
+ /* mapping from encap types to default filter IDs (multicast) */
+ static enum efx_ef10_default_filters map[] = {
+ [EFX_ENCAP_TYPE_NONE] = EFX_EF10_MCDEF,
+ [EFX_ENCAP_TYPE_VXLAN] = EFX_EF10_VXLAN4_MCDEF,
+ [EFX_ENCAP_TYPE_NVGRE] = EFX_EF10_NVGRE4_MCDEF,
+ [EFX_ENCAP_TYPE_GENEVE] = EFX_EF10_GENEVE4_MCDEF,
+ [EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6] =
+ EFX_EF10_VXLAN6_MCDEF,
+ [EFX_ENCAP_TYPE_NVGRE | EFX_ENCAP_FLAG_IPV6] =
+ EFX_EF10_NVGRE6_MCDEF,
+ [EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6] =
+ EFX_EF10_GENEVE6_MCDEF,
+ };
+
+ /* quick bounds check (BCAST result impossible) */
+ BUILD_BUG_ON(EFX_EF10_BCAST != 0);
+ if (encap_type > ARRAY_SIZE(map) || map[encap_type] == 0) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ /* then follow map */
+ id = &vlan->default_filters[map[encap_type]];
+
+ EFX_WARN_ON_PARANOID(*id != EFX_EF10_FILTER_ID_INVALID);
+ *id = efx_ef10_filter_get_unsafe_id(efx, rc);
+ if (!nic_data->workaround_26807 && !encap_type) {
/* Also need an Ethernet broadcast filter */
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
filter_flags, 0);
@@ -4903,20 +5104,44 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx,
/* Roll back the mc_def filter */
efx_ef10_filter_remove_unsafe(
efx, EFX_FILTER_PRI_AUTO,
- vlan->mcdef);
- vlan->mcdef = EFX_EF10_FILTER_ID_INVALID;
+ *id);
+ *id = EFX_EF10_FILTER_ID_INVALID;
return rc;
}
} else {
- EFX_WARN_ON_PARANOID(vlan->bcast !=
- EFX_EF10_FILTER_ID_INVALID);
- vlan->bcast = efx_ef10_filter_get_unsafe_id(efx, rc);
+ EFX_WARN_ON_PARANOID(
+ vlan->default_filters[EFX_EF10_BCAST] !=
+ EFX_EF10_FILTER_ID_INVALID);
+ vlan->default_filters[EFX_EF10_BCAST] =
+ efx_ef10_filter_get_unsafe_id(efx, rc);
}
}
rc = 0;
} else {
- EFX_WARN_ON_PARANOID(vlan->ucdef != EFX_EF10_FILTER_ID_INVALID);
- vlan->ucdef = rc;
+ /* mapping from encap types to default filter IDs (unicast) */
+ static enum efx_ef10_default_filters map[] = {
+ [EFX_ENCAP_TYPE_NONE] = EFX_EF10_UCDEF,
+ [EFX_ENCAP_TYPE_VXLAN] = EFX_EF10_VXLAN4_UCDEF,
+ [EFX_ENCAP_TYPE_NVGRE] = EFX_EF10_NVGRE4_UCDEF,
+ [EFX_ENCAP_TYPE_GENEVE] = EFX_EF10_GENEVE4_UCDEF,
+ [EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6] =
+ EFX_EF10_VXLAN6_UCDEF,
+ [EFX_ENCAP_TYPE_NVGRE | EFX_ENCAP_FLAG_IPV6] =
+ EFX_EF10_NVGRE6_UCDEF,
+ [EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6] =
+ EFX_EF10_GENEVE6_UCDEF,
+ };
+
+ /* quick bounds check (BCAST result impossible) */
+ BUILD_BUG_ON(EFX_EF10_BCAST != 0);
+ if (encap_type > ARRAY_SIZE(map) || map[encap_type] == 0) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ /* then follow map */
+ id = &vlan->default_filters[map[encap_type]];
+ EFX_WARN_ON_PARANOID(*id != EFX_EF10_FILTER_ID_INVALID);
+ *id = rc;
rc = 0;
}
return rc;
@@ -5039,7 +5264,8 @@ static void efx_ef10_filter_vlan_sync_rx_mode(struct efx_nic *efx,
/* Insert/renew unicast filters */
if (table->uc_promisc) {
- efx_ef10_filter_insert_def(efx, vlan, false, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_NONE,
+ false, false);
efx_ef10_filter_insert_addr_list(efx, vlan, false, false);
} else {
/* If any of the filters failed to insert, fall back to
@@ -5047,8 +5273,25 @@ static void efx_ef10_filter_vlan_sync_rx_mode(struct efx_nic *efx,
* our individual unicast filters.
*/
if (efx_ef10_filter_insert_addr_list(efx, vlan, false, false))
- efx_ef10_filter_insert_def(efx, vlan, false, false);
+ efx_ef10_filter_insert_def(efx, vlan,
+ EFX_ENCAP_TYPE_NONE,
+ false, false);
}
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_VXLAN,
+ false, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_VXLAN |
+ EFX_ENCAP_FLAG_IPV6,
+ false, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_NVGRE,
+ false, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_NVGRE |
+ EFX_ENCAP_FLAG_IPV6,
+ false, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_GENEVE,
+ false, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_GENEVE |
+ EFX_ENCAP_FLAG_IPV6,
+ false, false);
/* Insert/renew multicast filters */
/* If changing promiscuous state with cascaded multicast filters, remove
@@ -5062,7 +5305,9 @@ static void efx_ef10_filter_vlan_sync_rx_mode(struct efx_nic *efx,
/* If we failed to insert promiscuous filters, rollback
* and fall back to individual multicast filters
*/
- if (efx_ef10_filter_insert_def(efx, vlan, true, true)) {
+ if (efx_ef10_filter_insert_def(efx, vlan,
+ EFX_ENCAP_TYPE_NONE,
+ true, true)) {
/* Changing promisc state, so remove old filters */
efx_ef10_filter_remove_old(efx);
efx_ef10_filter_insert_addr_list(efx, vlan,
@@ -5072,7 +5317,9 @@ static void efx_ef10_filter_vlan_sync_rx_mode(struct efx_nic *efx,
/* If we failed to insert promiscuous filters, don't
* rollback. Regardless, also insert the mc_list
*/
- efx_ef10_filter_insert_def(efx, vlan, true, false);
+ efx_ef10_filter_insert_def(efx, vlan,
+ EFX_ENCAP_TYPE_NONE,
+ true, false);
efx_ef10_filter_insert_addr_list(efx, vlan, true, false);
}
} else {
@@ -5085,11 +5332,28 @@ static void efx_ef10_filter_vlan_sync_rx_mode(struct efx_nic *efx,
/* Changing promisc state, so remove old filters */
if (nic_data->workaround_26807)
efx_ef10_filter_remove_old(efx);
- if (efx_ef10_filter_insert_def(efx, vlan, true, true))
+ if (efx_ef10_filter_insert_def(efx, vlan,
+ EFX_ENCAP_TYPE_NONE,
+ true, true))
efx_ef10_filter_insert_addr_list(efx, vlan,
true, false);
}
}
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_VXLAN,
+ true, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_VXLAN |
+ EFX_ENCAP_FLAG_IPV6,
+ true, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_NVGRE,
+ true, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_NVGRE |
+ EFX_ENCAP_FLAG_IPV6,
+ true, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_GENEVE,
+ true, false);
+ efx_ef10_filter_insert_def(efx, vlan, EFX_ENCAP_TYPE_GENEVE |
+ EFX_ENCAP_FLAG_IPV6,
+ true, false);
}
/* Caller must hold efx->filter_sem for read if race against
@@ -5176,9 +5440,8 @@ static int efx_ef10_filter_add_vlan(struct efx_nic *efx, u16 vid)
vlan->uc[i] = EFX_EF10_FILTER_ID_INVALID;
for (i = 0; i < ARRAY_SIZE(vlan->mc); i++)
vlan->mc[i] = EFX_EF10_FILTER_ID_INVALID;
- vlan->ucdef = EFX_EF10_FILTER_ID_INVALID;
- vlan->bcast = EFX_EF10_FILTER_ID_INVALID;
- vlan->mcdef = EFX_EF10_FILTER_ID_INVALID;
+ for (i = 0; i < EFX_EF10_NUM_DEFAULT_FILTERS; i++)
+ vlan->default_filters[i] = EFX_EF10_FILTER_ID_INVALID;
list_add_tail(&vlan->list, &table->vlan_list);
@@ -5205,9 +5468,10 @@ static void efx_ef10_filter_del_vlan_internal(struct efx_nic *efx,
for (i = 0; i < ARRAY_SIZE(vlan->mc); i++)
efx_ef10_filter_remove_unsafe(efx, EFX_FILTER_PRI_AUTO,
vlan->mc[i]);
- efx_ef10_filter_remove_unsafe(efx, EFX_FILTER_PRI_AUTO, vlan->ucdef);
- efx_ef10_filter_remove_unsafe(efx, EFX_FILTER_PRI_AUTO, vlan->bcast);
- efx_ef10_filter_remove_unsafe(efx, EFX_FILTER_PRI_AUTO, vlan->mcdef);
+ for (i = 0; i < EFX_EF10_NUM_DEFAULT_FILTERS; i++)
+ if (vlan->default_filters[i] != EFX_EF10_FILTER_ID_INVALID)
+ efx_ef10_filter_remove_unsafe(efx, EFX_FILTER_PRI_AUTO,
+ vlan->default_filters[i]);
kfree(vlan);
}
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index d0ed7f7..8189a1c 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -27,6 +27,7 @@
* @EFX_FILTER_MATCH_OUTER_VID: Match by outer VLAN ID
* @EFX_FILTER_MATCH_IP_PROTO: Match by IP transport protocol
* @EFX_FILTER_MATCH_LOC_MAC_IG: Match by local MAC address I/G bit.
+ * @EFX_FILTER_MATCH_ENCAP_TYPE: Match by encapsulation type.
* Used for RX default unicast and multicast/broadcast filters.
*
* Only some combinations are supported, depending on NIC type:
@@ -54,6 +55,7 @@ enum efx_filter_match_flags {
EFX_FILTER_MATCH_OUTER_VID = 0x0100,
EFX_FILTER_MATCH_IP_PROTO = 0x0200,
EFX_FILTER_MATCH_LOC_MAC_IG = 0x0400,
+ EFX_FILTER_MATCH_ENCAP_TYPE = 0x0800,
};
/**
@@ -98,6 +100,26 @@ enum efx_filter_flags {
EFX_FILTER_FLAG_TX = 0x10,
};
+/** enum efx_encap_type - types of encapsulation
+ * @EFX_ENCAP_TYPE_NONE: no encapsulation
+ * @EFX_ENCAP_TYPE_VXLAN: VXLAN encapsulation
+ * @EFX_ENCAP_TYPE_NVGRE: NVGRE encapsulation
+ * @EFX_ENCAP_TYPE_GENEVE: GENEVE encapsulation
+ * @EFX_ENCAP_FLAG_IPV6: indicates IPv6 outer frame
+ *
+ * Contains both enumerated types and flags.
+ * To get just the type, OR with @EFX_ENCAP_TYPES_MASK.
+ */
+enum efx_encap_type {
+ EFX_ENCAP_TYPE_NONE = 0,
+ EFX_ENCAP_TYPE_VXLAN = 1,
+ EFX_ENCAP_TYPE_NVGRE = 2,
+ EFX_ENCAP_TYPE_GENEVE = 3,
+
+ EFX_ENCAP_TYPES_MASK = 7,
+ EFX_ENCAP_FLAG_IPV6 = 8,
+};
+
/**
* struct efx_filter_spec - specification for a hardware filter
* @match_flags: Match type flags, from &enum efx_filter_match_flags
@@ -118,6 +140,8 @@ enum efx_filter_flags {
* @rem_host: Remote IP host to match, if %EFX_FILTER_MATCH_REM_HOST is set
* @loc_port: Local TCP/UDP port to match, if %EFX_FILTER_MATCH_LOC_PORT is set
* @rem_port: Remote TCP/UDP port to match, if %EFX_FILTER_MATCH_REM_PORT is set
+ * @encap_type: Encapsulation type to match (from &enum efx_encap_type), if
+ * %EFX_FILTER_MATCH_ENCAP_TYPE is set
*
* The efx_filter_init_rx() or efx_filter_init_tx() function *must* be
* used to initialise the structure. The efx_filter_set_*() functions
@@ -144,7 +168,8 @@ struct efx_filter_spec {
__be32 rem_host[4];
__be16 loc_port;
__be16 rem_port;
- /* total 64 bytes */
+ u32 encap_type:4;
+ /* total 65 bytes */
};
enum {
@@ -269,4 +294,18 @@ static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec)
return 0;
}
+static inline void efx_filter_set_encap_type(struct efx_filter_spec *spec,
+ enum efx_encap_type encap_type)
+{
+ spec->match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
+ spec->encap_type = encap_type;
+}
+
+static inline enum efx_encap_type efx_filter_get_encap_type(
+ const struct efx_filter_spec *spec)
+{
+ if (spec->match_flags & EFX_FILTER_MATCH_ENCAP_TYPE)
+ return spec->encap_type;
+ return EFX_ENCAP_TYPE_NONE;
+}
#endif /* EFX_FILTER_H */
^ permalink raw reply related
* [PATCH net-next 2/3] sfc: refactor debug-or-warnings printks
From: Edward Cree @ 2017-01-26 17:53 UTC (permalink / raw)
To: linux-net-drivers, davem; +Cc: netdev
In-Reply-To: <39d8923f-4400-506c-dd50-250636ff83fa@solarflare.com>
From: Jon Cooper <jcooper@solarflare.com>
Rationalise several debug-or-warnings printks in to a macro that switches
between netif_dbg and netif_warn to make output more consistent.
Signed-off-by: Edward Cree <ecree@solarflare.com>
---
drivers/net/ethernet/sfc/ef10.c | 8 ++++----
drivers/net/ethernet/sfc/mcdi.c | 19 ++++++++-----------
drivers/net/ethernet/sfc/net_driver.h | 9 +++++++++
3 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index b64b47b..d0c1ed0e 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -4881,10 +4881,10 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx,
rc = efx_ef10_filter_insert(efx, &spec, true);
if (rc < 0) {
- netif_printk(efx, drv, rc == -EPERM ? KERN_DEBUG : KERN_WARNING,
- efx->net_dev,
- "%scast mismatch filter insert failed rc=%d\n",
- multicast ? "Multi" : "Uni", rc);
+ netif_cond_dbg(efx, drv, efx->net_dev,
+ rc == -EPERM, warn,
+ "%scast mismatch filter insert failed rc=%d\n",
+ multicast ? "Multi" : "Uni", rc);
} else if (multicast) {
EFX_WARN_ON_PARANOID(vlan->mcdef != EFX_EF10_FILTER_ID_INVALID);
vlan->mcdef = efx_ef10_filter_get_unsafe_id(efx, rc);
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 9956513..24b271b 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -837,11 +837,9 @@ static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned int cmd,
outbuf, outlen, outlen_actual,
quiet, NULL, raw_rc);
} else {
- netif_printk(efx, hw,
- rc == -EPERM ? KERN_DEBUG : KERN_ERR,
- efx->net_dev,
- "MC command 0x%x failed after proxy auth rc=%d\n",
- cmd, rc);
+ netif_cond_dbg(efx, hw, efx->net_dev, rc == -EPERM, err,
+ "MC command 0x%x failed after proxy auth rc=%d\n",
+ cmd, rc);
if (rc == -EINTR || rc == -EIO)
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
@@ -1084,10 +1082,9 @@ void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
code = MCDI_DWORD(outbuf, ERR_CODE);
if (outlen >= MC_CMD_ERR_ARG_OFST + 4)
err_arg = MCDI_DWORD(outbuf, ERR_ARG);
- netif_printk(efx, hw, rc == -EPERM ? KERN_DEBUG : KERN_ERR,
- efx->net_dev,
- "MC command 0x%x inlen %zu failed rc=%d (raw=%d) arg=%d\n",
- cmd, inlen, rc, code, err_arg);
+ netif_cond_dbg(efx, hw, efx->net_dev, rc == -EPERM, err,
+ "MC command 0x%x inlen %zu failed rc=%d (raw=%d) arg=%d\n",
+ cmd, inlen, rc, code, err_arg);
}
/* Switch to polled MCDI completions. This can be called in various
@@ -2057,8 +2054,8 @@ int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out,
/* Older firmware lacks GET_WORKAROUNDS and this isn't especially
* terrifying. The call site will have to deal with it though.
*/
- netif_printk(efx, hw, rc == -ENOSYS ? KERN_DEBUG : KERN_ERR,
- efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
+ netif_cond_dbg(efx, hw, efx->net_dev, rc == -ENOSYS, err,
+ "%s: failed rc=%d\n", __func__, rc);
return rc;
}
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 5927c20..c640955 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -51,6 +51,15 @@
#define EFX_WARN_ON_PARANOID(x) do {} while (0)
#endif
+/* if @cond then downgrade to debug, else print at @level */
+#define netif_cond_dbg(priv, type, netdev, cond, level, fmt, args...) \
+ do { \
+ if (cond) \
+ netif_dbg(priv, type, netdev, fmt, ##args); \
+ else \
+ netif_ ## level(priv, type, netdev, fmt, ##args); \
+ } while (0)
+
/**************************************************************************
*
* Efx data structures
^ 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