* Re: [PATCH net-next v3 2/2] tcp: allow to turn tcp timestamp randomization off
From: David Miller @ 2016-12-02 17:50 UTC (permalink / raw)
To: fw; +Cc: netdev
In-Reply-To: <1480588327-2902-2-git-send-email-fw@strlen.de>
From: Florian Westphal <fw@strlen.de>
Date: Thu, 1 Dec 2016 11:32:07 +0100
> Eric says: "By looking at tcpdump, and TS val of xmit packets of multiple
> flows, we can deduct the relative qdisc delays (think of fq pacing).
> This should work even if we have one flow per remote peer."
>
> Having random per flow (or host) offsets doesn't allow that anymore so add
> a way to turn this off.
>
> Suggested-by: Eric Dumazet <edumazet@google.com>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> Acked-by: Yuchung Cheng <ycheng@google.com>
Applied.
^ permalink raw reply
* Re: arp_filter and IPv6 ND
From: Saku Ytti @ 2016-12-02 17:51 UTC (permalink / raw)
To: Hannes Frederic Sowa; +Cc: netdev
In-Reply-To: <cead0544-5a5b-ccd0-e02d-abb44a41c054@stressinduktion.org>
On 2 December 2016 at 18:45, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> next-hop-self attribute on your neighbor in that direction? BGP in
> general doesn't lead to ND entry installs, protocols like IS-IS afair
> can short circuit here.
That's the whole problem, Linux does not think of ND or ARP as
interface specific thing, but as global thing. ND and ARP will happily
answer to query from any interface if any other interface has said IP.
I'm not sure why the Loopback ended up in Cisco ND Cache, answer is
either Cisco queried for it or Linux did gratuitous answer. I believe
gratuitous.
> Hmm, I would keep the Loopback announcements out of the BGP.
It's extremely common way to do anycast, but not interesting for the
topic at hand.
> For enterprise and cloud stuff it is certainly very surprising, as some
> isolations don't work as expected. OTOH it is really easy to build up
> home networks and things are more plug and play.
Can you give me practical example when the behaviour is desirable, my
imagination is failing me. I'm not arguing, I just want to understand
it, as I've never had the need myself.
I've never ran into setup which needs it, but cursory googling shows
several people having broken networks because of the behaviour. If it
is needed, I'm sure it's esoteric setup and perhaps saner default
would that extra sysctl config is needed to get this interface
agnostic ARP/ND behaviour.
> Some RFCs require that for some router implementations (CPE), on the
> other hand weak end model in Linux was probably inherited by IPv4. The
> addition of duplicate address detection (which of course only makes
> sense in strong end systems) to IPv6, basically shows that IPv6 is more
> or less designed to be a strong end system model.
>
> Anyway, a patch to suppress ndisc requests on those interfaces will
> probably be accepted.
Grand, not that I feel comfortable writing it. I'd rather see the
whole suppression functionality moved to neighbour.c from being AFI
specific.
--
++ytti
^ permalink raw reply
* Re: [PATCH/RFC net-next 0/2] net/sched: cls_flower: Support matching on ICMP
From: Simon Horman @ 2016-12-02 17:52 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, David S. Miller, Jay Vosburgh, Veaceslav Falico,
Andy Gospodarek, Jamal Hadi Salim, Jiri Pirko
In-Reply-To: <20161202171048.GE1883@nanopsycho.orion>
On Fri, Dec 02, 2016 at 06:10:48PM +0100, Jiri Pirko wrote:
> Fri, Dec 02, 2016 at 10:52:30AM CET, simon.horman@netronome.com wrote:
> >Hi,
> >
> >this series add supports for matching on ICMP type and code to cls_flower.
> >This is modeled on existing support for matching on L4 ports. The updates
> >to the dissector are intended to allow for code and storage re-use.
>
> Looks fine to me. Thanks!
Thanks, I'll drop the RFC designation and repost.
^ permalink raw reply
* Re: [PATCH/RFC iproute2/net-next 0/3] tc: flower: Support matching on ICMP
From: Simon Horman @ 2016-12-02 17:52 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, Stephen Hemminger, Jamal Hadi Salim, Jiri Pirko
In-Reply-To: <20161202171020.GD1883@nanopsycho.orion>
On Fri, Dec 02, 2016 at 06:10:20PM +0100, Jiri Pirko wrote:
> Fri, Dec 02, 2016 at 10:59:42AM CET, simon.horman@netronome.com wrote:
> >Add support for matching on ICMP type and code to flower. This is modeled
> >on existing support for matching on L4 ports.
> >
> >The second patch provided a minor cleanup which is in keeping with
> >they style used in the last patch.
> >
> >This is marked as an RFC to match the same designation given to the
> >corresponding kernel patches.
>
> Looks nice, I only have those 2 enum nitpicks.
Thanks, I'll fix those and repost.
^ permalink raw reply
* Re: [PATCH 4/6] net: ethernet: ti: cpts: add ptp pps support
From: Grygorii Strashko @ 2016-12-02 17:58 UTC (permalink / raw)
To: Richard Cochran
Cc: Murali Karicheri, Wingman Kwok, David S. Miller, netdev,
Mugunthan V N, Sekhar Nori, linux-kernel, linux-omap, Rob Herring,
devicetree
In-Reply-To: <20161202095848.GA14586@localhost.localdomain>
Hi Richard,
On 12/02/2016 03:58 AM, Richard Cochran wrote:
> On Wed, Nov 30, 2016 at 11:17:38PM +0100, Richard Cochran wrote:
>> On Wed, Nov 30, 2016 at 02:43:57PM -0600, Grygorii Strashko wrote:
>>> Sry, but this is questionable - code for pps comes from TI internal
>>> branches (SDK releases) where it survived for a pretty long time.
>
> Actually, there is a way to get an accurate PPS from the am335x. See
> this recent thread:
>
> https://www.mail-archive.com/linuxptp-devel@lists.sourceforge.net/msg01726.html
>
> That is the way to go, and so, please drop this present patch.
>
thanks for the links - it sounds very interesting.
As I understood, people trying to enable PPS on am335 device with the
goal to have PPS signal generated on some SoC pin and therefore they use DMtimer.
Also, as i understood, the Timer Load Register (TLDR) is corrected once
a second at each HW_TS_PUSH - as result, if freq was corrected during current sec
there will be some HW_TS_PUSH generation jitter any way.
Above solution is a bit complex for keystone 2 SoCs, as CPTS itself on these SoCs has
output pin (ts_comp) which can be used for PPS signal generation. So, I think,
similar results can be achieved by removing PPS correction code from cpts_ptp_adjfreq()
and updating CPTS_TS_LOAD_VAL once a sec in cpts_overflow_check().
or I missed smth?
--
regards,
-grygorii
^ permalink raw reply
* [PATCHv2 net-next 0/4] MV88E6390 batch two
From: Andrew Lunn @ 2016-12-02 18:02 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
This is the second batch of patches adding support for the
MV88e6390. They are not sufficient to make it work properly.
The mv88e6390 has a much expanded set of priority maps. Refactor the
existing code, and implement basic support for the new device.
Similarly, the monitor control register has been reworked.
The mv88e6390 has something odd in its EDSA tagging implementation,
which means it is not possible to use it. So we need to use DSA
tagging. This is the first device with EDSA support where we need to
use DSA, and the code does not support this. So two patches refactor
the existing code. The two different register definitions are
separated out, and using DSA on an EDSA capable device is added.
v2:
Add port prefix
Add helper function for 6390
Add _IEEE_ into #defines
Split monitor_ctrl into a number of separate ops.
Remove 6390 code which is management, used in a later patch
s/EGREES/EGRESS/.
Broke up setup_port_dsa() and set_port_dsa() into a number of ops
Andrew Lunn (4):
net: dsa: mv88e6xxx: Implement mv88e6390 tag remap
net: dsa: mv88e6xxx: Monitor and Management tables
net: dsa: mv88e6xxx: Move the tagging protocol into info
net: dsa: mv88e6xxx: Refactor CPU and DSA port setup
drivers/net/dsa/mv88e6xxx/chip.c | 339 ++++++++++++++++++++++++++--------
drivers/net/dsa/mv88e6xxx/global1.c | 69 +++++++
drivers/net/dsa/mv88e6xxx/global1.h | 4 +
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 62 +++++--
drivers/net/dsa/mv88e6xxx/port.c | 181 ++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 15 ++
6 files changed, 583 insertions(+), 87 deletions(-)
--
2.10.2
^ permalink raw reply
* [PATCHv2 net-next 3/4] net: dsa: mv88e6xxx: Move the tagging protocol into info
From: Andrew Lunn @ 2016-12-02 18:02 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1480701779-30633-1-git-send-email-andrew@lunn.ch>
Older chips support a single tagging protocol, DSA. New chips support
both DSA and EDSA, an enhanced version. Having both as an option
changes the register layouts. Up until now, it has been assumed that
if EDSA is supported, it will be used. Hence the register layout has
been determined by which protocol should be used. However, mv88e6390
has a different implementation of EDSA, which requires we need to use
the DSA tagging. Hence separate the selection of the protocol from the
register layout.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 33 +++++++++++++++++++++++++++------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 17 ++++-------------
2 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 6e981bedd028..80efee6f5e16 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2482,7 +2482,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
PORT_CONTROL_STATE_FORWARDING;
if (dsa_is_cpu_port(ds, port)) {
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_EDSA))
+ if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA |
PORT_CONTROL_FORWARD_UNKNOWN_MC;
else
@@ -2611,7 +2611,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
/* Port Ethertype: use the Ethertype DSA Ethertype
* value.
*/
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_EDSA)) {
+ if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) {
err = mv88e6xxx_port_write(chip, port, PORT_ETH_TYPE,
ETH_P_EDSA);
if (err)
@@ -3637,6 +3637,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 8,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6097,
.ops = &mv88e6085_ops,
},
@@ -3651,6 +3652,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 8,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6095,
.ops = &mv88e6095_ops,
},
@@ -3679,6 +3681,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
.ops = &mv88e6123_ops,
},
@@ -3693,6 +3696,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6185,
.ops = &mv88e6131_ops,
},
@@ -3707,6 +3711,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
.ops = &mv88e6161_ops,
},
@@ -3721,6 +3726,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
.ops = &mv88e6165_ops,
},
@@ -3735,6 +3741,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6171_ops,
},
@@ -3749,6 +3756,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6172_ops,
},
@@ -3763,6 +3771,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6175_ops,
},
@@ -3777,6 +3786,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6176_ops,
},
@@ -3791,6 +3801,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 8,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6185,
.ops = &mv88e6185_ops,
},
@@ -3803,6 +3814,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.num_ports = 11, /* 10 + Z80 */
.port_base_addr = 0x0,
.global1_addr = 0x1b,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.age_time_coeff = 15000,
.g1_irqs = 9,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
@@ -3819,6 +3831,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6190x_ops,
},
@@ -3832,6 +3845,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.port_base_addr = 0x0,
.global1_addr = 0x1b,
.age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6391_ops,
},
@@ -3846,6 +3861,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6240_ops,
},
@@ -3860,6 +3876,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6290_ops,
},
@@ -3874,6 +3891,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 8,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6320,
.ops = &mv88e6320_ops,
},
@@ -3888,6 +3906,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 8,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6320,
.ops = &mv88e6321_ops,
},
@@ -3902,6 +3921,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6350_ops,
},
@@ -3916,6 +3936,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
.ops = &mv88e6351_ops,
},
@@ -3930,6 +3951,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
.ops = &mv88e6352_ops,
},
@@ -3943,6 +3965,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6390_ops,
},
@@ -3956,6 +3979,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.global1_addr = 0x1b,
.age_time_coeff = 15000,
.g1_irqs = 9,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
.flags = MV88E6XXX_FLAGS_FAMILY_6390,
.ops = &mv88e6390x_ops,
},
@@ -4056,10 +4080,7 @@ static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds)
{
struct mv88e6xxx_chip *chip = ds->priv;
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_EDSA))
- return DSA_TAG_PROTO_EDSA;
-
- return DSA_TAG_PROTO_DSA;
+ return chip->info->tag_protocol;
}
static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index a6dd192652e8..2c51e3a8a890 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -438,12 +438,6 @@ enum mv88e6xxx_family {
};
enum mv88e6xxx_cap {
- /* Two different tag protocols can be used by the driver. All
- * switches support DSA, but only later generations support
- * EDSA.
- */
- MV88E6XXX_CAP_EDSA,
-
/* Energy Efficient Ethernet.
*/
MV88E6XXX_CAP_EEE,
@@ -506,7 +500,6 @@ enum mv88e6xxx_cap {
};
/* Bitmask of capabilities */
-#define MV88E6XXX_FLAG_EDSA BIT_ULL(MV88E6XXX_CAP_EDSA)
#define MV88E6XXX_FLAG_EEE BIT_ULL(MV88E6XXX_CAP_EEE)
#define MV88E6XXX_FLAG_SMI_CMD BIT_ULL(MV88E6XXX_CAP_SMI_CMD)
@@ -601,8 +594,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6320 \
- (MV88E6XXX_FLAG_EDSA | \
- MV88E6XXX_FLAG_EEE | \
+ (MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
@@ -616,8 +608,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAGS_PVT)
#define MV88E6XXX_FLAGS_FAMILY_6351 \
- (MV88E6XXX_FLAG_EDSA | \
- MV88E6XXX_FLAG_G1_ATU_FID | \
+ (MV88E6XXX_FLAG_G1_ATU_FID | \
MV88E6XXX_FLAG_G1_VTU_FID | \
MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_INT | \
@@ -633,8 +624,7 @@ enum mv88e6xxx_cap {
MV88E6XXX_FLAGS_PVT)
#define MV88E6XXX_FLAGS_FAMILY_6352 \
- (MV88E6XXX_FLAG_EDSA | \
- MV88E6XXX_FLAG_EEE | \
+ (MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_G1_ATU_FID | \
MV88E6XXX_FLAG_G1_VTU_FID | \
MV88E6XXX_FLAG_GLOBAL2 | \
@@ -676,6 +666,7 @@ struct mv88e6xxx_info {
unsigned int global1_addr;
unsigned int age_time_coeff;
unsigned int g1_irqs;
+ enum dsa_tag_protocol tag_protocol;
unsigned long long flags;
const struct mv88e6xxx_ops *ops;
};
--
2.10.2
^ permalink raw reply related
* [PATCHv2 net-next 4/4] net: dsa: mv88e6xxx: Refactor CPU and DSA port setup
From: Andrew Lunn @ 2016-12-02 18:02 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1480701779-30633-1-git-send-email-andrew@lunn.ch>
Older chips only support DSA tagging. Newer chips have both DSA and
EDSA tagging. Refactor the code by adding port functions for setting the
frame mode, egress mode, and if to forward unknown frames.
This results in the helper mv88e6xxx_6065_family() becoming unused, so
remove it.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 205 ++++++++++++++++++++++++++--------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 20 ++++
drivers/net/dsa/mv88e6xxx/port.c | 118 +++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 13 +++
4 files changed, 308 insertions(+), 48 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 80efee6f5e16..d1e6a0760a75 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -677,11 +677,6 @@ static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, int addr,
return err;
}
-static bool mv88e6xxx_6065_family(struct mv88e6xxx_chip *chip)
-{
- return chip->info->family == MV88E6XXX_FAMILY_6065;
-}
-
static bool mv88e6xxx_6095_family(struct mv88e6xxx_chip *chip)
{
return chip->info->family == MV88E6XXX_FAMILY_6095;
@@ -2438,6 +2433,80 @@ static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
return err;
}
+static int mv88e6xxx_setup_port_dsa(struct mv88e6xxx_chip *chip, int port,
+ int upstream_port)
+{
+ int err;
+
+ err = chip->info->ops->port_set_frame_mode(
+ chip, port, MV88E6XXX_FRAME_MODE_DSA);
+ if (err)
+ return err;
+
+ err = chip->info->ops->port_set_egress_unknowns(
+ chip, port, port == upstream_port);
+ if (err)
+ return err;
+
+ if (chip->info->ops->port_set_ether_type)
+ return chip->info->ops->port_set_ether_type(
+ chip, port, ETH_P_EDSA);
+
+ return 0;
+}
+
+static int mv88e6xxx_setup_port_cpu(struct mv88e6xxx_chip *chip, int port)
+{
+ int err;
+
+ switch (chip->info->tag_protocol) {
+ case DSA_TAG_PROTO_EDSA:
+ err = chip->info->ops->port_set_frame_mode(
+ chip, port, MV88E6XXX_FRAME_MODE_ETHERTYPE);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_set_egress_mode(
+ chip, port, PORT_CONTROL_EGRESS_ADD_TAG);
+ if (err)
+ return err;
+
+ if (chip->info->ops->port_set_ether_type)
+ err = chip->info->ops->port_set_ether_type(
+ chip, port, ETH_P_EDSA);
+ break;
+
+ case DSA_TAG_PROTO_DSA:
+ err = chip->info->ops->port_set_frame_mode(
+ chip, port, MV88E6XXX_FRAME_MODE_DSA);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_set_egress_mode(
+ chip, port, PORT_CONTROL_EGRESS_UNMODIFIED);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (err)
+ return err;
+
+ return chip->info->ops->port_set_egress_unknowns(chip, port, true);
+}
+
+static int mv88e6xxx_setup_port_normal(struct mv88e6xxx_chip *chip, int port)
+{
+ int err;
+
+ err = chip->info->ops->port_set_frame_mode(
+ chip, port, MV88E6XXX_FRAME_MODE_NORMAL);
+ if (err)
+ return err;
+
+ return chip->info->ops->port_set_egress_unknowns(chip, port, false);
+}
+
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
{
struct dsa_switch *ds = chip->ds;
@@ -2473,44 +2542,25 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
* If this is the upstream port for this switch, enable
* forwarding of unknown unicasts and multicasts.
*/
- reg = 0;
- if (mv88e6xxx_6352_family(chip) || mv88e6xxx_6351_family(chip) ||
- mv88e6xxx_6165_family(chip) || mv88e6xxx_6097_family(chip) ||
- mv88e6xxx_6095_family(chip) || mv88e6xxx_6065_family(chip) ||
- mv88e6xxx_6185_family(chip) || mv88e6xxx_6320_family(chip))
- reg = PORT_CONTROL_IGMP_MLD_SNOOP |
+ reg = PORT_CONTROL_IGMP_MLD_SNOOP |
PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP |
PORT_CONTROL_STATE_FORWARDING;
+ err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
+ if (err)
+ return err;
+
if (dsa_is_cpu_port(ds, port)) {
- if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA)
- reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA |
- PORT_CONTROL_FORWARD_UNKNOWN_MC;
- else
- reg |= PORT_CONTROL_DSA_TAG;
- reg |= PORT_CONTROL_EGRESS_ADD_TAG |
- PORT_CONTROL_FORWARD_UNKNOWN;
- }
- if (dsa_is_dsa_port(ds, port)) {
- if (mv88e6xxx_6095_family(chip) ||
- mv88e6xxx_6185_family(chip))
- reg |= PORT_CONTROL_DSA_TAG;
- if (mv88e6xxx_6352_family(chip) ||
- mv88e6xxx_6351_family(chip) ||
- mv88e6xxx_6165_family(chip) ||
- mv88e6xxx_6097_family(chip) ||
- mv88e6xxx_6320_family(chip)) {
- reg |= PORT_CONTROL_FRAME_MODE_DSA;
+ err = mv88e6xxx_setup_port_cpu(chip, port);
+ } else {
+ if (dsa_is_dsa_port(ds, port)) {
+ err = mv88e6xxx_setup_port_dsa(chip, port,
+ dsa_upstream_port(ds));
+ } else {
+ err = mv88e6xxx_setup_port_normal(chip, port);
}
-
- if (port == dsa_upstream_port(ds))
- reg |= PORT_CONTROL_FORWARD_UNKNOWN |
- PORT_CONTROL_FORWARD_UNKNOWN_MC;
- }
- if (reg) {
- err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
- if (err)
- return err;
}
+ if (err)
+ return err;
/* If this port is connected to a SerDes, make sure the SerDes is not
* powered down.
@@ -2607,16 +2657,6 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
0x0000);
if (err)
return err;
-
- /* Port Ethertype: use the Ethertype DSA Ethertype
- * value.
- */
- if (chip->info->tag_protocol == DSA_TAG_PROTO_EDSA) {
- err = mv88e6xxx_port_write(chip, port, PORT_ETH_TYPE,
- ETH_P_EDSA);
- if (err)
- return err;
- }
}
if (chip->info->ops->port_tag_remap) {
@@ -3182,6 +3222,9 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3198,6 +3241,8 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_set_frame_mode = mv88e6085_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6085_port_set_egress_unknowns,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3213,6 +3258,9 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3229,6 +3277,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_set_frame_mode = mv88e6085_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6085_port_set_egress_unknowns,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3246,6 +3296,9 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3263,6 +3316,9 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3297,6 +3353,9 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3317,6 +3376,9 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3335,6 +3397,9 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3355,6 +3420,9 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3371,6 +3439,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_set_frame_mode = mv88e6085_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6085_port_set_egress_unknowns,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3389,6 +3459,9 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3408,6 +3481,9 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390x_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3427,6 +3503,9 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3448,6 +3527,9 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3466,6 +3548,9 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3486,6 +3571,9 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -3505,6 +3593,9 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -3523,6 +3614,9 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3541,6 +3635,9 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3561,6 +3658,9 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3579,6 +3679,9 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3598,6 +3701,9 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390x_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3617,6 +3723,9 @@ static const struct mv88e6xxx_ops mv88e6391_ops = {
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
.port_tag_remap = mv88e6390_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_unknowns = mv88e6351_port_set_egress_unknowns,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 2c51e3a8a890..9dd94d7f58d6 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -110,6 +110,7 @@
#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12)
#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12)
#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12)
+#define PORT_CONTROL_EGRESS_MASK (0x3 << 12)
#define PORT_CONTROL_HEADER BIT(11)
#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10)
#define PORT_CONTROL_DOUBLE_TAG BIT(9)
@@ -117,6 +118,7 @@
#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8)
#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8)
#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8)
+#define PORT_CONTROL_FRAME_MASK (0x3 << 8)
#define PORT_CONTROL_DSA_TAG BIT(8)
#define PORT_CONTROL_VLAN_TUNNEL BIT(7)
#define PORT_CONTROL_TAG_IF_BOTH BIT(6)
@@ -124,6 +126,10 @@
#define PORT_CONTROL_USE_TAG BIT(4)
#define PORT_CONTROL_FORWARD_UNKNOWN_MC BIT(3)
#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2)
+#define PORT_CONTROL_NOT_EGRESS_UNKNOWN_DA (0x0 << 2)
+#define PORT_CONTROL_NOT_EGRESS_UNKNOWN_MULTICAST_DA (0x1 << 2)
+#define PORT_CONTROL_NOT_EGRESS_UNKNOWN_UNITCAST_DA (0x2 << 2)
+#define PORT_CONTROL_EGRESS_ALL_UNKNOWN_DA (0x3 << 2)
#define PORT_CONTROL_STATE_MASK 0x03
#define PORT_CONTROL_STATE_DISABLED 0x00
#define PORT_CONTROL_STATE_BLOCKING 0x01
@@ -396,6 +402,13 @@
#define MV88E6XXX_N_FID 4096
+enum mv88e6xxx_frame_mode {
+ MV88E6XXX_FRAME_MODE_NORMAL,
+ MV88E6XXX_FRAME_MODE_DSA,
+ MV88E6XXX_FRAME_MODE_PROVIDER,
+ MV88E6XXX_FRAME_MODE_ETHERTYPE,
+};
+
/* List of supported models */
enum mv88e6xxx_model {
MV88E6085,
@@ -814,6 +827,13 @@ struct mv88e6xxx_ops {
int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port);
+ int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port,
+ enum mv88e6xxx_frame_mode mode);
+ int (*port_set_egress_unknowns)(struct mv88e6xxx_chip *chip, int port,
+ bool on);
+ int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port,
+ u16 etype);
+
/* Snapshot the statistics for a port. The statistics can then
* be read back a leisure but still with a consistent view.
*/
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 3d03ea3a2c0d..cf6674911abf 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -335,6 +335,116 @@ int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
return 0;
}
+int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
+ u16 mode)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®);
+ if (err)
+ return err;
+
+ reg &= ~PORT_CONTROL_EGRESS_MASK;
+ reg |= mode;
+
+ return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
+}
+
+int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
+ enum mv88e6xxx_frame_mode mode)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®);
+ if (err)
+ return err;
+
+ reg &= ~PORT_CONTROL_FRAME_MODE_DSA;
+
+ switch (mode) {
+ case MV88E6XXX_FRAME_MODE_NORMAL:
+ reg |= PORT_CONTROL_FRAME_MODE_NORMAL;
+ break;
+ case MV88E6XXX_FRAME_MODE_DSA:
+ reg |= PORT_CONTROL_FRAME_MODE_DSA;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
+}
+
+int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
+ enum mv88e6xxx_frame_mode mode)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®);
+ if (err)
+ return err;
+
+ reg &= ~PORT_CONTROL_FRAME_MASK;
+
+ switch (mode) {
+ case MV88E6XXX_FRAME_MODE_NORMAL:
+ reg |= PORT_CONTROL_FRAME_MODE_NORMAL;
+ break;
+ case MV88E6XXX_FRAME_MODE_DSA:
+ reg |= PORT_CONTROL_FRAME_MODE_DSA;
+ break;
+ case MV88E6XXX_FRAME_MODE_PROVIDER:
+ reg |= PORT_CONTROL_FRAME_MODE_PROVIDER;
+ break;
+ case MV88E6XXX_FRAME_MODE_ETHERTYPE:
+ reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
+}
+
+int mv88e6085_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
+ bool on)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®);
+ if (err)
+ return err;
+
+ if (on)
+ reg |= PORT_CONTROL_FORWARD_UNKNOWN;
+ else
+ reg &= ~PORT_CONTROL_FORWARD_UNKNOWN;
+
+ return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
+}
+
+int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
+ bool on)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®);
+ if (err)
+ return err;
+
+ if (on)
+ reg |= PORT_CONTROL_EGRESS_ALL_UNKNOWN_DA;
+ else
+ reg &= ~PORT_CONTROL_EGRESS_ALL_UNKNOWN_DA;
+
+ return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
+}
+
/* Offset 0x05: Port Control 1 */
/* Offset 0x06: Port Based VLAN Map */
@@ -497,6 +607,14 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
return 0;
}
+/* Offset 0x0f: Port Ether type */
+
+int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype)
+{
+ return mv88e6xxx_port_write(chip, port, PORT_ETH_TYPE, etype);
+}
+
/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
* Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
*/
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 5fab4606662b..83cb3440e067 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -50,5 +50,18 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
u16 mode);
int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port);
+int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,
+ u16 mode);
+int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
+ enum mv88e6xxx_frame_mode mode);
+int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,
+ enum mv88e6xxx_frame_mode mode);
+int mv88e6085_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
+ bool on);
+int mv88e6351_port_set_egress_unknowns(struct mv88e6xxx_chip *chip, int port,
+ bool on);
+int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
+ u16 etype);
+
#endif /* _MV88E6XXX_PORT_H */
--
2.10.2
^ permalink raw reply related
* [PATCHv2 net-next 1/4] net: dsa: mv88e6xxx: Implement mv88e6390 tag remap
From: Andrew Lunn @ 2016-12-02 18:02 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1480701779-30633-1-git-send-email-andrew@lunn.ch>
The mv88e6390 does not have the two registers to set the frame
priority map. Instead it has an indirection registers for setting a
number of different priority maps. Refactor the old code into an
function, implement the mv88e6390 version, and use an op to call the
right one.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
v2:
Add port prefix
Add helper function for 6390
Add _IEEE_ into #defines
---
drivers/net/dsa/mv88e6xxx/chip.c | 37 ++++++++++++--------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 12 +++++++
drivers/net/dsa/mv88e6xxx/port.c | 63 +++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 2 ++
4 files changed, 101 insertions(+), 13 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ce2f7ff8066e..ff4bd2f74357 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2617,20 +2617,10 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
if (err)
return err;
}
+ }
- /* Tag Remap: use an identity 802.1p prio -> switch
- * prio mapping.
- */
- err = mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_0123,
- 0x3210);
- if (err)
- return err;
-
- /* Tag Remap 2: use an identity 802.1p prio -> switch
- * prio mapping.
- */
- err = mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_4567,
- 0x7654);
+ if (chip->info->ops->port_tag_remap) {
+ err = chip->info->ops->port_tag_remap(chip, port);
if (err)
return err;
}
@@ -3189,6 +3179,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3217,6 +3208,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3245,6 +3237,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3259,6 +3252,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6xxx_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3288,6 +3282,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3305,6 +3300,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3320,6 +3316,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3337,6 +3334,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3366,6 +3364,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3382,6 +3381,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390x_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3398,6 +3398,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3416,6 +3417,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3431,6 +3433,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3448,6 +3451,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -3464,6 +3468,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
@@ -3479,6 +3484,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3494,6 +3500,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6185_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3511,6 +3518,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
.stats_snapshot = mv88e6320_g1_stats_snapshot,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
@@ -3526,6 +3534,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3542,6 +3551,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390x_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
@@ -3558,6 +3568,7 @@ static const struct mv88e6xxx_ops mv88e6391_ops = {
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
.port_set_speed = mv88e6390_port_set_speed,
+ .port_tag_remap = mv88e6390_port_tag_remap,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index ab52c3772c78..a6e9dba665c1 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -172,6 +172,16 @@
#define PORT_OUT_FILTERED 0x13
#define PORT_TAG_REGMAP_0123 0x18
#define PORT_TAG_REGMAP_4567 0x19
+#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */
+#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15)
+#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12)
+#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9
#define GLOBAL_STATUS 0x00
#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */
@@ -800,6 +810,8 @@ struct mv88e6xxx_ops {
*/
int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed);
+ int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port);
+
/* Snapshot the statistics for a port. The statistics can then
* be read back a leisure but still with a consistent view.
*/
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index af4772d86086..3d03ea3a2c0d 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -496,3 +496,66 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
return 0;
}
+
+/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]
+ * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
+ */
+
+int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
+{
+ int err;
+
+ /* Use a direct priority mapping for all IEEE tagged frames */
+ err = mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_0123, 0x3210);
+ if (err)
+ return err;
+
+ return mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_4567, 0x7654);
+}
+
+static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,
+ int port, u16 table,
+ u8 pointer, u16 data)
+{
+ u16 reg;
+
+ reg = PORT_IEEE_PRIO_MAP_TABLE_UPDATE |
+ table |
+ (pointer << PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT) |
+ data;
+
+ return mv88e6xxx_port_write(chip, port, PORT_IEEE_PRIO_MAP_TABLE, reg);
+}
+
+int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
+{
+ int err, i;
+
+ for (i = 0; i <= 7; i++) {
+ err = mv88e6xxx_port_ieeepmt_write(
+ chip, port, PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP,
+ i, (i | i << 4));
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_ieeepmt_write(
+ chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP,
+ i, i);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_ieeepmt_write(
+ chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP,
+ i, i);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_port_ieeepmt_write(
+ chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP,
+ i, i);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index 499129c1489c..5fab4606662b 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -48,5 +48,7 @@ int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
u16 mode);
+int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port);
#endif /* _MV88E6XXX_PORT_H */
--
2.10.2
^ permalink raw reply related
* [PATCHv2 net-next 2/4] net: dsa: mv88e6xxx: Monitor and Management tables
From: Andrew Lunn @ 2016-12-02 18:02 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1480701779-30633-1-git-send-email-andrew@lunn.ch>
The mv88e6390 changes the monitor control register into the Monitor
and Management control, which is an indirection register to various
registers.
Add ops to set the CPU port and the ingress/egress port for both
register layouts, to global1
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 68 +++++++++++++++++++++++++++++-----
drivers/net/dsa/mv88e6xxx/global1.c | 69 +++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/global1.h | 4 ++
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 13 +++++++
4 files changed, 145 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ff4bd2f74357..6e981bedd028 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2747,15 +2747,17 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip)
if (err)
return err;
- /* Configure the upstream port, and configure it as the port to which
- * ingress and egress and ARP monitor frames are to be sent.
- */
- reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
- upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT |
- upstream_port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
- err = mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
- if (err)
- return err;
+ if (chip->info->ops->g1_set_cpu_port) {
+ err = chip->info->ops->g1_set_cpu_port(chip, upstream_port);
+ if (err)
+ return err;
+ }
+
+ if (chip->info->ops->g1_set_egress_port) {
+ err = chip->info->ops->g1_set_egress_port(chip, upstream_port);
+ if (err)
+ return err;
+ }
/* Disable remote management, and set the switch's DSA device number. */
err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2,
@@ -3184,6 +3186,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6095_ops = {
@@ -3213,6 +3217,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6123_ops = {
@@ -3227,6 +3233,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6131_ops = {
@@ -3242,6 +3250,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -3257,6 +3267,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -3271,6 +3283,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3287,6 +3301,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6172_ops = {
@@ -3305,6 +3321,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -3321,6 +3339,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6176_ops = {
@@ -3339,6 +3359,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -3353,6 +3375,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6190_ops = {
@@ -3370,6 +3394,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -3387,6 +3413,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -3404,6 +3432,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3422,6 +3452,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -3439,6 +3471,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3456,6 +3490,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6320_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3473,6 +3509,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6320_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3489,6 +3527,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6351_ops = {
@@ -3505,6 +3545,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3523,6 +3565,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
+ .g1_set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6095_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3540,6 +3584,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3557,6 +3603,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_ops mv88e6391_ops = {
@@ -3574,6 +3622,8 @@ static const struct mv88e6xxx_ops mv88e6391_ops = {
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
+ .g1_set_cpu_port = mv88e6390_g1_set_cpu_port,
+ .g1_set_egress_port = mv88e6390_g1_set_egress_port,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 5fcf23dbf04b..688547026e15 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -33,6 +33,75 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
}
+/* Offset 0x1a: Monitor Control */
+/* Offset 0x1a: Monitor & MGMT Control on some devices */
+
+int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
+{
+ u16 reg;
+ int err;
+
+ err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®);
+ if (err)
+ return err;
+
+ reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
+ GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
+
+ reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
+ port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
+}
+
+/* Older generations also call this the ARP destination. It has been
+ * generalized in more modern devices such that more than ARP can
+ * egress it
+ */
+int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
+{
+ u16 reg;
+ int err;
+
+ err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®);
+ if (err)
+ return err;
+
+ reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
+ reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
+}
+
+static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
+ u16 pointer, u8 data)
+{
+ u16 reg;
+
+ reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
+
+ return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
+}
+
+int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
+{
+ int err;
+
+ err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
+ port);
+ if (err)
+ return err;
+
+ return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
+ port);
+}
+
+int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
+{
+ return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
+ port);
+}
+
/* Offset 0x1c: Global Control 2 */
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index df3794cdbfb9..0c979550052f 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -25,5 +25,9 @@ int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip);
void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val);
+int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port);
+int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
+int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
#endif /* _MV88E6XXX_GLOBAL1_H */
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index a6e9dba665c1..a6dd192652e8 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -287,10 +287,21 @@
#define GLOBAL_CORE_TAG_TYPE 0x19
#define GLOBAL_MONITOR_CONTROL 0x1a
#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12
+#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12)
#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8
+#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8)
#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4
+#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4)
#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0
#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0)
+#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15)
+#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8)
+#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8)
+#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8)
+#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8)
+#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8)
+#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8)
+#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8)
#define GLOBAL_CONTROL_2 0x1c
#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000
#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000
@@ -827,6 +838,8 @@ struct mv88e6xxx_ops {
void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data);
void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port,
uint64_t *data);
+ int (*g1_set_cpu_port)(struct mv88e6xxx_chip *chip, int port);
+ int (*g1_set_egress_port)(struct mv88e6xxx_chip *chip, int port);
};
#define STATS_TYPE_PORT BIT(0)
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 0/2] net/sched: cls_flower: Support matching on ICMP
From: Simon Horman @ 2016-12-02 18:05 UTC (permalink / raw)
To: David Miller
Cc: netdev, Jay Vosburgh, Veaceslav Falico, Andy Gospodarek,
Jamal Hadi Salim, Jiri Pirko, Simon Horman
Hi,
this series add supports for matching on ICMP type and code to cls_flower.
This is modeled on existing support for matching on L4 ports. The updates
to the dissector are intended to allow for code and storage re-use.
Change since RFC:
* Drop RFC designation after positive review from Jiri
Simon Horman (2):
flow dissector: ICMP support
net/sched: cls_flower: Support matching on ICMP type and code
drivers/net/bonding/bond_main.c | 6 +++--
include/linux/skbuff.h | 5 +++++
include/net/flow_dissector.h | 50 ++++++++++++++++++++++++++++++++++++++---
include/uapi/linux/pkt_cls.h | 10 +++++++++
net/core/flow_dissector.c | 34 +++++++++++++++++++++++++---
net/sched/cls_flow.c | 4 ++--
net/sched/cls_flower.c | 42 ++++++++++++++++++++++++++++++++++
7 files changed, 141 insertions(+), 10 deletions(-)
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply
* [PATCH net-next 1/2] flow dissector: ICMP support
From: Simon Horman @ 2016-12-02 18:05 UTC (permalink / raw)
To: David Miller
Cc: netdev, Jay Vosburgh, Veaceslav Falico, Andy Gospodarek,
Jamal Hadi Salim, Jiri Pirko, Simon Horman
In-Reply-To: <1480701951-3686-1-git-send-email-simon.horman@netronome.com>
Allow dissection of ICMP(V6) type and code. This re-uses transport layer
port dissection code as although ICMP is not a transport protocol and their
type and code are not ports this allows sharing of both code and storage.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
drivers/net/bonding/bond_main.c | 6 ++++--
include/linux/skbuff.h | 5 +++++
include/net/flow_dissector.h | 30 +++++++++++++++++++++++++++---
net/core/flow_dissector.c | 34 +++++++++++++++++++++++++++++++---
net/sched/cls_flow.c | 4 ++--
5 files changed, 69 insertions(+), 10 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8029dd4912b6..a6f75cfb2bf7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3181,7 +3181,8 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
} else {
return false;
}
- if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0)
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 &&
+ proto >= 0 && !skb_flow_is_icmp_any(skb, proto))
fk->ports.ports = skb_flow_get_ports(skb, noff, proto);
return true;
@@ -3209,7 +3210,8 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
return bond_eth_hash(skb);
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 ||
- bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23)
+ bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23 ||
+ flow_keys_are_icmp_any(&flow))
hash = bond_eth_hash(skb);
else
hash = (__force u32)flow.ports.ports;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9c535fbccf2c..44a8f69a9198 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1094,6 +1094,11 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
void *data, int hlen_proto);
+static inline bool skb_flow_is_icmp_any(const struct sk_buff *skb, u8 ip_proto)
+{
+ return flow_protos_are_icmp_any(skb->protocol, ip_proto);
+}
+
static inline __be32 skb_flow_get_ports(const struct sk_buff *skb,
int thoff, u8 ip_proto)
{
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index c4f31666afd2..8880025914e3 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -2,6 +2,7 @@
#define _NET_FLOW_DISSECTOR_H
#include <linux/types.h>
+#include <linux/in.h>
#include <linux/in6.h>
#include <uapi/linux/if_ether.h>
@@ -89,10 +90,15 @@ struct flow_dissector_key_addrs {
};
/**
- * flow_dissector_key_tp_ports:
- * @ports: port numbers of Transport header
+ * flow_dissector_key_ports:
+ * @ports: port numbers of Transport header or
+ * type and code of ICMP header
+ * ports: source (high) and destination (low) port numbers
* src: source port number
* dst: destination port number
+ * icmp: ICMP type (high) and code (low)
+ * type: ICMP type
+ * type: ICMP code
*/
struct flow_dissector_key_ports {
union {
@@ -101,6 +107,11 @@ struct flow_dissector_key_ports {
__be16 src;
__be16 dst;
};
+ __be16 icmp;
+ struct {
+ u8 type;
+ u8 code;
+ };
};
};
@@ -188,9 +199,22 @@ struct flow_keys_digest {
void make_flow_keys_digest(struct flow_keys_digest *digest,
const struct flow_keys *flow);
+static inline bool flow_protos_are_icmp_any(__be16 n_proto, u8 ip_proto)
+{
+ return (n_proto == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP) ||
+ (n_proto == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6);
+}
+
+static inline bool flow_keys_are_icmp_any(const struct flow_keys *keys)
+{
+ return flow_protos_are_icmp_any(keys->basic.n_proto,
+ keys->basic.ip_proto);
+}
+
static inline bool flow_keys_have_l4(const struct flow_keys *keys)
{
- return (keys->ports.ports || keys->tags.flow_label);
+ return (!flow_keys_are_icmp_any(keys) && keys->ports.ports) ||
+ keys->tags.flow_label;
}
u32 flow_hash_from_keys(struct flow_keys *keys);
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 1eb6f949e5b2..0584b4bb4390 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -58,6 +58,28 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
EXPORT_SYMBOL(skb_flow_dissector_init);
/**
+ * skb_flow_get_be16 - extract be16 entity
+ * @skb: sk_buff to extract from
+ * @poff: offset to extract at
+ * @data: raw buffer pointer to the packet
+ * @hlen: packet header length
+ *
+ * The function will try to retrieve a be32 entity at
+ * offset poff
+ */
+__be16 skb_flow_get_be16(const struct sk_buff *skb, int poff, void *data,
+ int hlen)
+{
+ __be16 *u, _u;
+
+ u = __skb_header_pointer(skb, poff, sizeof(_u), data, hlen, &_u);
+ if (u)
+ return *u;
+
+ return 0;
+}
+
+/**
* __skb_flow_get_ports - extract the upper layer ports and return them
* @skb: sk_buff to extract the ports from
* @thoff: transport header offset
@@ -542,8 +564,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
key_ports = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_PORTS,
target_container);
- key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
- data, hlen);
+ if (flow_protos_are_icmp_any(proto, ip_proto))
+ key_ports->icmp = skb_flow_get_be16(skb, nhoff, data,
+ hlen);
+ else
+ key_ports->ports = __skb_flow_get_ports(skb, nhoff,
+ ip_proto, data,
+ hlen);
}
out_good:
@@ -718,7 +745,8 @@ void make_flow_keys_digest(struct flow_keys_digest *digest,
data->n_proto = flow->basic.n_proto;
data->ip_proto = flow->basic.ip_proto;
- data->ports = flow->ports.ports;
+ if (flow_keys_have_l4(flow))
+ data->ports = flow->ports.ports;
data->src = flow->addrs.v4addrs.src;
data->dst = flow->addrs.v4addrs.dst;
}
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index e39672394c7b..a1a7ae71aa62 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -96,7 +96,7 @@ static u32 flow_get_proto(const struct sk_buff *skb,
static u32 flow_get_proto_src(const struct sk_buff *skb,
const struct flow_keys *flow)
{
- if (flow->ports.ports)
+ if (!flow_keys_are_icmp_any(flow) && flow->ports.ports)
return ntohs(flow->ports.src);
return addr_fold(skb->sk);
@@ -105,7 +105,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb,
static u32 flow_get_proto_dst(const struct sk_buff *skb,
const struct flow_keys *flow)
{
- if (flow->ports.ports)
+ if (!flow_keys_are_icmp_any(flow) && flow->ports.ports)
return ntohs(flow->ports.dst);
return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb);
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH net-next 2/2] net/sched: cls_flower: Support matching on ICMP type and code
From: Simon Horman @ 2016-12-02 18:05 UTC (permalink / raw)
To: David Miller
Cc: netdev, Jay Vosburgh, Veaceslav Falico, Andy Gospodarek,
Jamal Hadi Salim, Jiri Pirko, Simon Horman
In-Reply-To: <1480701951-3686-1-git-send-email-simon.horman@netronome.com>
Support matching on ICMP type and code.
Example usage:
tc qdisc add dev eth0 ingress
tc filter add dev eth0 protocol ip parent ffff: flower \
indev eth0 ip_proto icmp type 8 code 0 action drop
tc filter add dev eth0 protocol ipv6 parent ffff: flower \
indev eth0 ip_proto icmpv6 type 128 code 0 action drop
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
include/net/flow_dissector.h | 24 ++++++++++++++++++++++--
include/uapi/linux/pkt_cls.h | 10 ++++++++++
net/sched/cls_flower.c | 42 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index 8880025914e3..5540dfa18872 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -199,10 +199,30 @@ struct flow_keys_digest {
void make_flow_keys_digest(struct flow_keys_digest *digest,
const struct flow_keys *flow);
+static inline bool flow_protos_are_icmpv4(__be16 n_proto, u8 ip_proto)
+{
+ return n_proto == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP;
+}
+
+static inline bool flow_protos_are_icmpv6(__be16 n_proto, u8 ip_proto)
+{
+ return n_proto == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6;
+}
+
static inline bool flow_protos_are_icmp_any(__be16 n_proto, u8 ip_proto)
{
- return (n_proto == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP) ||
- (n_proto == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6);
+ return flow_protos_are_icmpv4(n_proto, ip_proto) ||
+ flow_protos_are_icmpv6(n_proto, ip_proto);
+}
+
+static inline bool flow_basic_key_is_icmpv4(const struct flow_dissector_key_basic *basic)
+{
+ return flow_protos_are_icmpv4(basic->n_proto, basic->ip_proto);
+}
+
+static inline bool flow_basic_key_is_icmpv6(const struct flow_dissector_key_basic *basic)
+{
+ return flow_protos_are_icmpv6(basic->n_proto, basic->ip_proto);
}
static inline bool flow_keys_are_icmp_any(const struct flow_keys *keys)
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 86786d45ee66..58160fe80b80 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -457,6 +457,16 @@ enum {
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT, /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_ICMPV4_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,/* u8 */
+
__TCA_FLOWER_MAX,
};
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index e8dd09af0d0c..412efa7de226 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -355,6 +355,14 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 },
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 },
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 },
+ [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 },
+ [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
};
static void fl_set_key_val(struct nlattr **tb,
@@ -471,6 +479,20 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
&mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
sizeof(key->tp.dst));
+ } else if (flow_basic_key_is_icmpv4(&key->basic)) {
+ fl_set_key_val(tb, &key->tp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
+ &mask->tp.type, TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
+ sizeof(key->tp.type));
+ fl_set_key_val(tb, &key->tp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
+ &mask->tp.code, TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
+ sizeof(key->tp.code));
+ } else if (flow_basic_key_is_icmpv6(&key->basic)) {
+ fl_set_key_val(tb, &key->tp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
+ &mask->tp.type, TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
+ sizeof(key->tp.type));
+ fl_set_key_val(tb, &key->tp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
+ &mask->tp.code, TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
+ sizeof(key->tp.code));
}
if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
@@ -943,6 +965,26 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
&mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
sizeof(key->tp.dst))))
goto nla_put_failure;
+ else if (flow_basic_key_is_icmpv4(&key->basic) &&
+ (fl_dump_key_val(skb, &key->tp.type,
+ TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->tp.type,
+ TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
+ sizeof(key->tp.type)) ||
+ fl_dump_key_val(skb, &key->tp.code,
+ TCA_FLOWER_KEY_ICMPV4_CODE, &mask->tp.code,
+ TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
+ sizeof(key->tp.code))))
+ goto nla_put_failure;
+ else if (flow_basic_key_is_icmpv6(&key->basic) &&
+ (fl_dump_key_val(skb, &key->tp.type,
+ TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->tp.type,
+ TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
+ sizeof(key->tp.type)) ||
+ fl_dump_key_val(skb, &key->tp.code,
+ TCA_FLOWER_KEY_ICMPV6_CODE, &mask->tp.code,
+ TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
+ sizeof(key->tp.code))))
+ goto nla_put_failure;
if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
(fl_dump_key_val(skb, &key->enc_ipv4.src,
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* Re: [flamebait] xdp, well meaning but pointless
From: Hannes Frederic Sowa @ 2016-12-02 18:12 UTC (permalink / raw)
To: Tom Herbert
Cc: Jesper Dangaard Brouer, Thomas Graf, Florian Westphal,
Linux Kernel Network Developers
In-Reply-To: <CALx6S3787YVgOUT0nUOA9Q2yJE2tPE3GcnT=Xf=LUVMvMtjEyw@mail.gmail.com>
On 02.12.2016 17:59, Tom Herbert wrote:
> On Fri, Dec 2, 2016 at 3:54 AM, Hannes Frederic Sowa
> <hannes@stressinduktion.org> wrote:
>> On 02.12.2016 11:24, Jesper Dangaard Brouer wrote:
>>> On Thu, 1 Dec 2016 13:51:32 -0800
>>> Tom Herbert <tom@herbertland.com> wrote:
>>>
>>>>>> The technical plenary at last IETF on Seoul a couple of weeks ago was
>>>>>> exclusively focussed on DDOS in light of the recent attack against
>>>>>> Dyn. There were speakers form Cloudflare and Dyn. The Cloudflare
>>>>>> presentation by Nick Sullivan
>>>>>> (https://www.ietf.org/proceedings/97/slides/slides-97-ietf-sessb-how-to-stay-online-harsh-realities-of-operating-in-a-hostile-network-nick-sullivan-01.pdf)
>>>>>> alluded to some implementation of DDOS mitigation. In particular, on
>>>>>> slide 6 Nick gave some numbers for drop rates in DDOS. The "kernel"
>>>
>>> slide 14
>>>
>>>>>> numbers he gave we're based in iptables+BPF and that was a whole
>>>>>> 1.2Mpps-- somehow that seems ridiculously to me (I said so at the mic
>>>>>> and that's also when I introduced XDP to whole IETF :-) ). If that's
>>>>>> the best we can do the Internet is in a world hurt. DDOS mitigation
>>>>>> alone is probably a sufficient motivation to look at XDP. We need
>>>>>> something that drops bad packets as quickly as possible when under
>>>>>> attack, we need this to be integrated into the stack, we need it to be
>>>>>> programmable to deal with the increasing savvy of attackers, and we
>>>>>> don't want to be forced to be dependent on HW solutions. This is why
>>>>>> we created XDP!
>>>
>>> The 1.2Mpps number is a bit low, but we are unfortunately in that
>>> ballpark.
>>>
>>>>> I totally understand that. But in my reply to David in this thread I
>>>>> mentioned DNS apex processing as being problematic which is actually
>>>>> being referred in your linked slide deck on page 9 ("What do floods look
>>>>> like") and the problematic of parsing DNS packets in XDP due to string
>>>>> processing and looping inside eBPF.
>>>
>>> That is a weak argument. You do realize CloudFlare actually use eBPF to
>>> do this exact filtering, and (so-far) eBPF for parsing DNS have been
>>> sufficient for them.
>>
>> You are talking about this code on the following slides (I actually
>> transcribed it for you here and disassembled):
>>
>> l0: ld #0x14
>> l1: ldxb 4*([0]&0xf)
>> l2: add x
>> l3: tax
>> l4: ld [x+0]
>> l5: jeq #0x7657861, l6, l13
>> l6: ld [x+4]
>> l7: jeq #0x6d706c65, l8, l13
>> l8: ld [x+8]
>> l9: jeq #0x3636f6d, l10, l13
>> l10: ldb [x+12]
>> l11: jeq #0, l12, l13
>> l12: ret #0x1
>> l13: ret #0
>>
>> You can offload this to u32 in hardware if that is what you want.
>>
>> The reason this works is because of netfilter, which allows them to
>> dynamically generate BPF programs and insert and delete them from
>> chains, do intersection or unions of them.
>>
>> If you have a freestanding program like in XDP the complexity space is a
>> different one and not comparable to this at all.
>>
> I don't understand this comment about complexity especially in regards
> to the idea of offloading u32 to hardware. Relying on hardware to do
> anything always leads to more complexity than an equivalent SW
> implementation for the same functionality. The only reason we ever use
> a hardware mechanisms is if it gives *significantly* better
> performance. If the performance difference isn't there then doing
> things in SW is going to be the better path (as we see in XDP).
I am just wondering why the u32 filter wasn't mentioned in their slide
deck. If all what Cloudflare needs are those kind of matches, they are
in fact actually easier to generate than an cBPF program. It is not a
good example of how a real world DoS filter in XDP would look like.
If you argue XDP as a C function hook that can call arbitrary code in
the driver before submitting that to the networking stack, yep, that is
not complex at all. Depending on how those modules will be maintained,
they either end up in the kernel and will be updated on major changes or
are 3rd party and people have to update them and also depend on the
driver features.
But this opens up a whole new can of worms also. I haven't really
thought this through completely, but last time the patches were nack'ed
with lots of strong opinions and I tended to agree with them. I am
revisiting this position.
Certainly you can build real-world DoS protection with this function
pointer hook and C code in the driver. In this case a user space
solution still has advantages because of maintainability, as e.g. with
netmap or dpdk you are again decoupled from the in-kernel API/ABI and
don't need to test, recompile etc. on each kernel upgrade. If the module
ends up in the kernel, those problems might also disappear.
For XDP+eBPF to provide a full DoS mitigation (protocol parsing,
sampling and dropping) solution seems to be too complex for me because
of the arguments I stated in my previous mail.
Bye,
Hannes
^ permalink raw reply
* [PROBLEM]: IPv6 ICMP Ancillary Data IPV6_PKTINFO sendmsg() invalid argument
From: Thomas Lloyd @ 2016-12-02 18:19 UTC (permalink / raw)
To: netdev
Hi All,
First post here; any pointers or improvements for bug reporting are
welcome.
[1.] One line summary of the problem:
sendmsg() with ancillary data of type IPV6_PKTINFO fails with invalid
argument and further possible memory corruption.
---------------------------------
[2.] Full description of the problem/report:
As part of my project I am attempting to perform IPv6 neighbour
solicitations to discover the MAC address of my local neighbours.
In the included test code link-local src and dst addresses are used to
send neighbour solicitations along with specifying the network interface
in IPV6_PKTINFO ancillary data.
In my test environment I have a Ubuntu 16.04 LTS Server/Router and a
Ubuntu 16.04 LTS Desktop.
These are both hosted on a Windows 10 Host as Virtual Guests.
Router/Server Interfaces:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
link/ether 08:00:27:c5:0e:76 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fec5:e76/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
link/ether 08:00:27:0a:c1:80 brd ff:ff:ff:ff:ff:ff
inet6 2001:db8:1000:baba::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe0a:c180/64 scope link
valid_lft forever preferred_lft forever
Eth0 is set up for NAT to a physical IPv4 network but is unused in this
test setup.
Eth1 is IPv6 and is the radvd interface attatched to an internal virtual
box network interface.
In my client environment I have three network interfaces:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
state UP group default qlen 1000
link/ether 08:00:27:b9:42:47 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.121/24 brd 192.168.100.255 scope global dynamic
enp0s3
valid_lft 79320sec preferred_lft 79320sec
inet6 fe80::5523:e7df:d12c:681/64 scope link
valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
state UP group default qlen 1000
link/ether 08:00:27:1a:a7:22 brd ff:ff:ff:ff:ff:ff
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
state UP group default qlen 1000
link/ether 08:00:27:35:13:22 brd ff:ff:ff:ff:ff:ff
inet6 2001:db8:1000:baba:b30a:ed85:8568:cc66/64 scope global
noprefixroute dynamic
valid_lft 86389sec preferred_lft 14389sec
inet6 fe80::cffe:e7ef:a03a:34cb/64 scope link
valid_lft forever preferred_lft forever
enp0s3 is a bridged physical wired connection on the host to an ipv4
network with router / gateway, ipv6 is active but not used.
enp0s8 is a bridged physical wifi connection on the host to another ipv4
subnet within the same network on the same router / gateway ipv6 is active
but not used .
enp0d9 is an internal virtual box network connected directly to another
Ubuntu guest as an IPv6 stateless router (the neighbour I am solicitating)
this interfaces is ipv4 enabled but not used.
The expected behaviour is to use the sendmsg() system call and specify the
outgoing interface for the neighbour sonication message using the
IPV6_PKTINFO ancillary data as detailed in the RFC3542 links below.
6.1. Specifying/Receiving the Interface
https://tools.ietf.org/html/rfc3542.html#section-6.1
6.7 Summary of Outgoing Interface Selection
https://tools.ietf.org/html/rfc3542.html#section-6.7
The actual behaviour is for the sendmsg() system call to fail with errno
set to 22, Invalid Argument.
A note of interest is that if a perror() call is made to report this
problem a seg fault in mallo.c is encountered. I have not performed
further investigation.
You can see this has been commented after the sendmsg() system call in the
demo code.
Warning:
In my testing I have removed the IPV6_PKTINFO ancillary data and have
found that if the IPv6 router is not available at boot by default enp0s3
is used to send the packet.
I will send another e-mail further describing the behaviour with the
subject:
[PROBLEM]: IPv6 Link-Local Routing through wrong interface
---------------------------------
[3.] Keywords (i.e., modules, networking, kernel):
networking, ipv6, link-local, ancillary
---------------------------------
[4.] Kernel version (from /proc/version):
Linux version 4.4.0-51-generic (buildd@lcy01-08) (gcc version 5.4.0
20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) ) #72-Ubuntu SMP Thu Nov 24
18:29:54 UTC 2016
Linux version 4.8.11-1-ARCH (builduser@tobias) (gcc version 6.2.1 20160830
(GCC) ) #1 SMP PREEMPT Sun Nov 27 09:26:14 CET 2016
---------------------------------
[5.] Output of Oops.. message (if applicable) with symbolic information
resolved (see Documentation/oops-tracing.txt)
---------------------------------
[6.] A small shell script or example program which triggers the problem
(if possible)
/* Copyright (C) 2011-2015 P.D. Buchan (mailto:pdbuchan@yahoo.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Send an IPv6 ICMP neighbor solicitation packet.
// Change hoplimit and specify interface using ancillary
// data method.
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // close()
#include <string.h> // strcpy, memset(), and memcpy()
#include <netinet/icmp6.h> // struct nd_neighbor_solicit, which
contains icmp6_hdr, ND_NEIGHBOR_SOLICIT
#include <netinet/in.h> // IPPROTO_IPV6, IPPROTO_ICMPV6,
INET6_ADDRSTRLEN
#include <netinet/ip.h> // IP_MAXPACKET (65535)
#include <arpa/inet.h> // inet_ntop()
#include <netdb.h> // struct addrinfo
#include <sys/ioctl.h> // macro ioctl is defined
#include <bits/ioctls.h> // defines values for argument "request" of
ioctl. Here, we need SIOCGIFHWADDR
#include <bits/socket.h> // structs msghdr and cmsghdr
#include <net/if.h> // struct ifreq
#include <linux/ipv6.h>
#include <stdint.h>
#include <errno.h> // errno, perror()
// Definition of pktinfo6 created from definition of in6_pktinfo in
netinet/in.h.
// This should remove "redefinition of in6_pktinfo" errors in some linux
variants.
typedef struct _pktinfo6 pktinfo6;
struct _pktinfo6 {
struct in6_addr ipi6_addr;
int ipi6_ifindex;
};
// Function prototypes
uint16_t checksum (uint16_t *, int);
char *allocate_strmem (int);
uint8_t *allocate_ustrmem (int);
int
main (int argc, char **argv)
{
int NS_HDRLEN = sizeof (struct nd_neighbor_solicit); // Length of NS
message header
int optlen = 8; // Option Type (1 byte) + Length (1 byte) + Length of
MAC address (6 bytes)
int i, sd, status, ifindex, cmsglen, psdhdrlen;
struct addrinfo hints;
struct addrinfo *res;
struct sockaddr_in6 *ipv6, src, dst, dstsnmc;
struct nd_neighbor_solicit *ns;
socklen_t srclen;
uint8_t *outpack, *options, *psdhdr, hoplimit;
struct msghdr msghdr, msghdr2 ;
struct ifreq ifr;
struct cmsghdr *cmsghdr1, *cmsghdr2;
pktinfo6 *pktinfo;
struct iovec iov[2];
char *target, *source, *interface;
void *tmp;
// Allocate memory for various arrays.
interface = allocate_strmem (40);
target = allocate_strmem (INET6_ADDRSTRLEN);
source = allocate_strmem (INET6_ADDRSTRLEN);
outpack = allocate_ustrmem (IP_MAXPACKET);
options = allocate_ustrmem (optlen);
psdhdr = allocate_ustrmem (IP_MAXPACKET);
// Interface to send packet through.
strcpy (interface, "enp0s9");
// Source (node sending solicitation) IPv6 unicast address, or
// the IPv6 unspecified address (::
// You need to fill this out.
//strcpy (source, "fe80::cffe:e7ef:a03a:34cb");
strcpy (source, "::");
// Target (which must be link-local) hostname or IPv6 address (node
we're requesting an advertisement from).
// You need to fill this out.
strcpy (target, "fe80::a00:27ff:fe0a:c180");
// Fill out hints for getaddrinfo().
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = hints.ai_flags | AI_CANONNAME;
// Resolve source using getaddrinfo().
if ((status = getaddrinfo (source, NULL, &hints, &res)) != 0) {
fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (status));
return (EXIT_FAILURE);
}
memset (&src, 0, sizeof (src));
memcpy (&src, res->ai_addr, res->ai_addrlen);
srclen = res->ai_addrlen;
memcpy (psdhdr, src.sin6_addr.s6_addr, 16 * sizeof (uint8_t)); // Copy
to checksum pseudo-header
freeaddrinfo (res);
// Resolve target using getaddrinfo().
if ((status = getaddrinfo (target, NULL, &hints, &res)) != 0) {
fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (status));
return (EXIT_FAILURE);
}
memset (&dst, 0, sizeof (dst));
memset (&dstsnmc, 0, sizeof (dstsnmc));
memcpy (&dst, res->ai_addr, res->ai_addrlen);
memcpy (&dstsnmc, res->ai_addr, res->ai_addrlen);
// Report target's unicast address.
ipv6 = (struct sockaddr_in6 *) res->ai_addr;
tmp = &(ipv6->sin6_addr);
memset (target, 0, INET6_ADDRSTRLEN * sizeof (char));
if (inet_ntop (AF_INET6, tmp, target, INET6_ADDRSTRLEN) == NULL) {
status = errno;
fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror
(status));
exit (EXIT_FAILURE);
}
printf ("Target unicast IPv6 address: %s\n", target);
freeaddrinfo (res);
// Convert target's IPv6 unicast address to solicited-node multicast
address.
// Section 2.7.1 of RFC 4291.
dstsnmc.sin6_addr.s6_addr[0]= 255;
dstsnmc.sin6_addr.s6_addr[1]=2;
for (i=2; i<11; i++) {
dstsnmc.sin6_addr.s6_addr[i] = 0;
}
dstsnmc.sin6_addr.s6_addr[11]=1;
dstsnmc.sin6_addr.s6_addr[12]=255;
// Report target's solicited-node multicast address.
ipv6 = (struct sockaddr_in6 *) &dstsnmc;
tmp = &(ipv6->sin6_addr);
memset (target, 0, INET6_ADDRSTRLEN * sizeof (char));
if (inet_ntop (AF_INET6, tmp, target, INET6_ADDRSTRLEN) == NULL) {
status = errno;
fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror
(status));
exit (EXIT_FAILURE);
}
printf ("Target solicited-node multicast address: %s\n", target);
memcpy (psdhdr + 16, dstsnmc.sin6_addr.s6_addr, 16 * sizeof (uint8_t));
// Solicited-node multicast address goes into pseudo-header
// Request a socket descriptor sd.
if ((sd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
perror ("Failed to get socket descriptor ");
exit (EXIT_FAILURE);
}
// Use ioctl() to look up soliciting node's (i.e., source's) interface
name and get its MAC address.
memset (&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) {
perror ("ioctl() failed to get source MAC address ");
return (EXIT_FAILURE);
}
// Copy source MAC address into options buffer.
options[0] = 1; // Option Type - "source link layer address"
(Section 4.6 of RFC 4861)
options[1] = optlen / 8; // Option Length - units of 8 octets (RFC
4861)
for (i=0; i<6; i++) {
options[i+2] = (uint8_t) ifr.ifr_addr.sa_data[i];
}
// Report soliciting node MAC address to stdout.
printf ("MAC address for interface %s is ", interface);
for (i=0; i<5; i++) {
printf ("%02x:", options[i+2]);
}
printf ("%02x\n", options[5+2]);
// Always bind otherwise the packet will be sent out on the first active
site-local or link-local interface.
// Bind the socket descriptor to the source address if not site-local or
link-local.
if (!(psdhdr[0] == 0xfe)) {
if (bind (sd, (struct sockaddr *) &src, srclen) < 0) {
perror ("Failed to bind the socket descriptor to the source address
");
exit (EXIT_FAILURE);
}
}
// Find interface index from interface name.
// This will be put in cmsghdr data in order to specify the interface we
want to use.
if ((ifindex = if_nametoindex (interface)) == 0) {
perror ("if_nametoindex() failed to obtain interface index ");
exit (EXIT_FAILURE);
}
printf ("Soliciting node's index for interface %s is %i\n", interface,
ifindex);
// Define first part of buffer outpack to be a neighbor solicit struct.
ns = (struct nd_neighbor_solicit *) outpack;
memset (ns, 0, sizeof (*ns));
// Populate icmp6_hdr portion of neighbor solicit struct.
ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_SOLICIT; // 135 (RFC 4861)
ns->nd_ns_hdr.icmp6_code = 0; // zero for neighbor
solicitation (RFC 4861)
ns->nd_ns_hdr.icmp6_cksum = htons(0); // zero when calculating
checksum
ns->nd_ns_reserved = htonl(0); // Reserved - must be set to
zero (RFC 4861)
ns->nd_ns_target = dst.sin6_addr; // Target address (NOT
MULTICAST) (as type in6_addr)
// Append options to end of neighbor solicit struct.
memcpy (outpack + NS_HDRLEN, options, optlen * sizeof (uint8_t));
// Need a pseudo-header for checksum calculation. Define length. (RFC
2460)
// Length = source IP (16 bytes) + destination IP (16 bytes)
// + upper layer packet length (4 bytes) + zero (3 bytes)
// + next header (1 byte)
psdhdrlen = 16 + 16 + 4 + 3 + 1 + NS_HDRLEN + optlen;
// Prepare msghdr for sendmsg().
memset (&msghdr, 0, sizeof (msghdr));
msghdr.msg_name = &dstsnmc; // Destination IPv6 address (solicited node
multicast) (as struct sockaddr_in6)
msghdr.msg_namelen = sizeof (dstsnmc);
memset (&iov, 0, sizeof (iov));
iov[0].iov_base = (uint8_t *) outpack; // Point msghdr to buffer
outpack
iov[0].iov_len = NS_HDRLEN + optlen;
msghdr.msg_iov = iov; // scatter/gather array
msghdr.msg_iovlen = 1; // number of elements in
scatter/gather array
// Tell msghdr we're adding cmsghdr data to change hop limit and specify
interface.
// Allocate some memory for our cmsghdr data.
cmsglen = CMSG_SPACE (sizeof (int)) + CMSG_SPACE (sizeof (pktinfo));
msghdr.msg_control = allocate_ustrmem (cmsglen);
msghdr.msg_controllen = cmsglen;
// Change hop limit to 255 as required for neighbor solicitation (RFC
4861).
hoplimit = 255u;
cmsghdr1 = CMSG_FIRSTHDR (&msghdr);
if(NULL == cmsghdr1)
{
fprintf (stderr, "NULL Returned out of Memory");
exit (EXIT_FAILURE);
}
cmsghdr1->cmsg_level = IPPROTO_IPV6;
cmsghdr1->cmsg_type = IPV6_HOPLIMIT; // We want to change hop limit
cmsghdr1->cmsg_len = CMSG_LEN (sizeof (int));
*(CMSG_DATA (cmsghdr1)) = hoplimit;
// Specify source interface index for this packet via cmsghdr data.
cmsghdr2 = CMSG_NXTHDR (&msghdr, cmsghdr1);
if(NULL == cmsghdr2)
{
fprintf (stderr, "NULL Returned out of Memory");
exit (EXIT_FAILURE);
}
cmsghdr2->cmsg_level = IPPROTO_IPV6;
cmsghdr2->cmsg_type = IPV6_PKTINFO; // We want to specify interface
here
cmsghdr2->cmsg_len = CMSG_LEN (sizeof (pktinfo));
pktinfo = (pktinfo6 *) CMSG_DATA (cmsghdr2);
pktinfo->ipi6_ifindex = ifindex;
pktinfo->ipi6_ifindex = 0;
// Compute ICMPv6 checksum (RFC 2460).
// psdhdr[0 to 15] = source IPv6 address, set earlier.
// psdhdr[16 to 31] = destination IPv6 address, set earlier.
psdhdr[32] = 0; // Length should not be greater than 65535 (i.e., 2
bytes)
psdhdr[33] = 0; // Length should not be greater than 65535 (i.e., 2
bytes)
psdhdr[34] = (NS_HDRLEN + optlen) / 256; // Upper layer packet length
psdhdr[35] = (NS_HDRLEN + optlen) % 256; // Upper layer packet length
psdhdr[36] = 0; // Must be zero
psdhdr[37] = 0; // Must be zero
psdhdr[38] = 0; // Must be zero
psdhdr[39] = IPPROTO_ICMPV6;
memcpy (psdhdr + 40, outpack, (NS_HDRLEN + optlen) * sizeof (uint8_t));
ns->nd_ns_hdr.icmp6_cksum = checksum ((uint16_t *) psdhdr, psdhdrlen);
printf ("Checksum: %x\n", ntohs (ns->nd_ns_hdr.icmp6_cksum));
if (sendmsg (sd, &msghdr, 0) < 0) {
// perror ("sendmsg() failed ");
fprintf (stderr,"[%d] %s\n", errno, strerror(errno));
exit (EXIT_FAILURE);
}
close (sd);
// Free allocated memory.
free (interface);
free (target);
free (source);
free (outpack);
free (options);
free (psdhdr);
free (msghdr.msg_control);
return (EXIT_SUCCESS);
}
// Computing the internet checksum (RFC 1071).
// Note that the internet checksum does not preclude collisions.
uint16_t
checksum (uint16_t *addr, int len)
{
int count = len;
register uint32_t sum = 0;
uint16_t answer = 0;
// Sum up 2-byte values until none or only one byte left.
while (count > 1) {
sum += *(addr++);
count -= 2;
}
// Add left-over byte, if any.
if (count > 0) {
sum += *(uint8_t *) addr;
}
// Fold 32-bit sum into 16 bits; we lose information by doing this,
// increasing the chances of a collision.
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
// Checksum is one's compliment of sum.
answer = ~sum;
return (answer);
}
// Allocate memory for an array of chars.
char *
allocate_strmem (int len)
{
void *tmp;
if (len <= 0) {
fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in
allocate_strmem().\n", len);
exit (EXIT_FAILURE);
}
tmp = (char *) malloc (len * sizeof (char));
if (tmp != NULL) {
memset (tmp, 0, len * sizeof (char));
return (tmp);
} else {
fprintf (stderr, "ERROR: Cannot allocate memory for array
allocate_strmem().\n");
exit (EXIT_FAILURE);
}
}
// Allocate memory for an array of unsigned chars.
uint8_t *
allocate_ustrmem (int len)
{
void *tmp;
if (len <= 0) {
fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in
allocate_ustrmem().\n", len);
exit (EXIT_FAILURE);
}
tmp = (uint8_t *) malloc (len * sizeof (uint8_t));
if (tmp != NULL) {
memset (tmp, 0, len * sizeof (uint8_t));
return (tmp);
} else {
fprintf (stderr, "ERROR: Cannot allocate memory for array
allocate_ustrmem().\n");
exit (EXIT_FAILURE);
}
}
---------------------------------
[7.] Environment
Host -> Windows 10 - VirtualBox Version 5.1.10 r112026 (Qt5.6.2)
Guest -> Ubuntu 16.04 (Up to date)
Guest -> Arch Linux (Latest)
-------------
[7.1] Software
Linux tom-VirtualBox 4.4.0-51-generic #72-Ubuntu SMP Thu Nov 24 18:29:54
UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
GNU C 5.4.0
GNU Make 4.1
Binutils
2.26.1
Util-linux
2.27.1
Mount 2.27.1
Module-init-tools 22
E2fsprogs 1.42.13
Pcmciautils 018
PPP
2.4.7
Linux C Library 2.23
Dynamic linker (ldd) 2.23
Linux C++ Library 6.0.21
Procps
3.3.10
Net-tools 1.60
Kbd
1.15.5
Console-tools 1.15.5
Sh-utils 8.25
Udev 229
Wireless-tools 30
Modules Loaded 8250_fintek
ablk_helper aesni_intel aes_x86_64 ahci autofs4 binfmt_misc crc32_pclmul
crct10dif_pclmul cryptd drm drm_kms_helper e1000 fb_sys_fops fjes gf128mul
ghash_clmulni_intel glue_helper hid hid_generic i2c_piix4 input_leds
joydev libahci lp lrw mac_hid parport parport_pc pata_acpi ppdev psmouse
serio_raw syscopyarea sysfillrect sysimgblt ttm usbhid vboxguest vboxsf
vboxvideo video
Linux archbox 4.8.11-1-ARCH #1 SMP PREEMPT Sun Nov 27 09:26:14 CET 2016
x86_64 GNU/Linux
GNU C 6.2.1
GNU Make 4.2.1
Binutils 2.27
Util-linux 2.28.2
Mount 2.28.2
Module-init-tools 23
E2fsprogs 1.43.3
Jfsutils 1.1.15
Reiserfsprogs 3.6.25
Xfsprogs 4.8.0
Pcmciautils 018
Linux C Library 2.24
Dynamic linker (ldd) 2.24
Linux C++ Library 6.0.22
Kbd 2.0.3
Console-tools 2.0.3
Sh-utils 8.25
Udev 232
Modules Loaded ablk_helper ac ac97_bus acpi_cpufreq aesni_intel
aes_x86_64 ata_generic ata_piix atkbd battery button cdrom cfg80211 crc16
crc32c_intel crc32_pclmul crct10dif_pclmul cryptd e1000 ehci_hcd ehci_pci
evdev ext4 fjes fscrypto gf128mul ghash_clmulni_intel glue_helper hid
hid_generic i2c_piix4 i8042 input_leds intel_agp intel_gtt intel_rapl_perf
ip_tables jbd2 joydev led_class libata libps2 lrw mac_hid mbcache mousedev
ohci_hcd ohci_pci parport parport_pc pata_acpi pcspkr ppdev psmouse rfkill
sch_fq_codel scsi_mod sd_mod serio serio_raw snd snd_ac97_codec
snd_intel8x0 snd_pcm snd_timer soundcore sr_mod tpm tpm_tis tpm_tis_core
usb_common usbcore usbhid video x_tables
-------------
[7.2.] Processor information
(Ubuntu)
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 94
model name : Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
stepping : 3
cpu MHz : 2591.818
cache size : 6144 KB
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 22
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep
mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm
constant_tsc rep_good nopl xtopology nonstop_tsc pni pclmulqdq monitor
ssse3 cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx rdrand lahf_lm abm
3dnowprefetch rdseed clflushopt
bugs :
bogomips : 5183.63
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:
(Arch)
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 94
model name : Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
stepping : 3
cpu MHz : 2591.998
cache size : 6144 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 22
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca
cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm
constant_tsc rep_good nopl xtopology nonstop_tsc eagerfpu pni pclmulqdq
ssse3 cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx rdrand
hypervisor lahf_lm abm 3dnowprefetch rdseed clflushopt
bugs :
bogomips : 5186.99
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 94
model name : Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
stepping : 3
cpu MHz : 2591.998
cache size : 6144 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 22
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca
cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm
constant_tsc rep_good nopl xtopology nonstop_tsc eagerfpu pni pclmulqdq
ssse3 cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx rdrand
hypervisor lahf_lm abm 3dnowprefetch rdseed clflushopt
bugs :
bogomips : 5186.99
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:
-------------
[7.3.] Module information
(Ubuntu)
vboxsf 45056 0 - Live 0x0000000000000000 (OE)
binfmt_misc 20480 1 - Live 0x0000000000000000
crct10dif_pclmul 16384 0 - Live 0x0000000000000000
crc32_pclmul 16384 0 - Live 0x0000000000000000
ghash_clmulni_intel 16384 0 - Live 0x0000000000000000
vboxvideo 49152 2 - Live 0x0000000000000000 (OE)
ttm 94208 1 vboxvideo, Live 0x0000000000000000
aesni_intel 167936 0 - Live 0x0000000000000000
aes_x86_64 20480 1 aesni_intel, Live 0x0000000000000000
lrw 16384 1 aesni_intel, Live 0x0000000000000000
drm_kms_helper 155648 1 vboxvideo, Live 0x0000000000000000
gf128mul 16384 1 lrw, Live 0x0000000000000000
glue_helper 16384 1 aesni_intel, Live 0x0000000000000000
ablk_helper 16384 1 aesni_intel, Live 0x0000000000000000
cryptd 20480 3 ghash_clmulni_intel,aesni_intel,ablk_helper, Live
0x0000000000000000
drm 364544 5 vboxvideo,ttm,drm_kms_helper, Live 0x0000000000000000
joydev 20480 0 - Live 0x0000000000000000
fb_sys_fops 16384 1 drm_kms_helper, Live 0x0000000000000000
input_leds 16384 0 - Live 0x0000000000000000
serio_raw 16384 0 - Live 0x0000000000000000
syscopyarea 16384 2 vboxvideo,drm_kms_helper, Live 0x0000000000000000
sysfillrect 16384 2 vboxvideo,drm_kms_helper, Live 0x0000000000000000
sysimgblt 16384 2 vboxvideo,drm_kms_helper, Live 0x0000000000000000
vboxguest 282624 6 vboxsf,vboxvideo, Live 0x0000000000000000 (OE)
i2c_piix4 24576 0 - Live 0x0000000000000000
8250_fintek 16384 0 - Live 0x0000000000000000
mac_hid 16384 0 - Live 0x0000000000000000
parport_pc 32768 0 - Live 0x0000000000000000
ppdev 20480 0 - Live 0x0000000000000000
lp 20480 0 - Live 0x0000000000000000
parport 49152 3 parport_pc,ppdev,lp, Live 0x0000000000000000
autofs4 40960 2 - Live 0x0000000000000000
hid_generic 16384 0 - Live 0x0000000000000000
usbhid 49152 0 - Live 0x0000000000000000
hid 118784 2 hid_generic,usbhid, Live 0x0000000000000000
psmouse 131072 0 - Live 0x0000000000000000
ahci 36864 3 - Live 0x0000000000000000
libahci 32768 1 ahci, Live 0x0000000000000000
fjes 28672 0 - Live 0x0000000000000000
video 40960 0 - Live 0x0000000000000000
e1000 135168 0 - Live 0x0000000000000000
pata_acpi 16384 0 - Live 0x0000000000000000
(Arch)
cfg80211 495616 0 - Live 0xffffffffa0416000
rfkill 20480 2 cfg80211, Live 0xffffffffa0394000
ppdev 20480 0 - Live 0xffffffffa0410000
crct10dif_pclmul 16384 0 - Live 0xffffffffa040b000
crc32_pclmul 16384 0 - Live 0xffffffffa0406000
crc32c_intel 24576 0 - Live 0xffffffffa03fb000
ghash_clmulni_intel 16384 0 - Live 0xffffffffa03f6000
aesni_intel 167936 0 - Live 0xffffffffa03c3000
aes_x86_64 20480 1 aesni_intel, Live 0xffffffffa03bd000
lrw 16384 1 aesni_intel, Live 0xffffffffa03b8000
gf128mul 16384 1 lrw, Live 0xffffffffa03b3000
glue_helper 16384 1 aesni_intel, Live 0xffffffffa03a3000
ablk_helper 16384 1 aesni_intel, Live 0xffffffffa039e000
cryptd 20480 3 ghash_clmulni_intel,aesni_intel,ablk_helper, Live
0xffffffffa03a8000
intel_rapl_perf 16384 0 - Live 0xffffffffa0387000
input_leds 16384 0 - Live 0xffffffffa0382000
pcspkr 16384 0 - Live 0xffffffffa031f000
evdev 24576 3 - Live 0xffffffffa038d000
psmouse 126976 0 - Live 0xffffffffa0362000
led_class 16384 1 input_leds, Live 0xffffffffa0359000
joydev 20480 0 - Live 0xffffffffa0335000
mousedev 20480 0 - Live 0xffffffffa02f8000
mac_hid 16384 0 - Live 0xffffffffa02dd000
parport_pc 28672 0 - Live 0xffffffffa02e8000
parport 40960 2 ppdev,parport_pc, Live 0xffffffffa032a000
acpi_cpufreq 20480 0 - Live 0xffffffffa0324000
fjes 28672 0 - Live 0xffffffffa028a000
battery 20480 0 - Live 0xffffffffa0306000
tpm_tis 16384 0 - Live 0xffffffffa02e3000
intel_agp 20480 0 - Live 0xffffffffa0315000
tpm_tis_core 20480 1 tpm_tis, Live 0xffffffffa030f000
ac 16384 0 - Live 0xffffffffa0301000
button 16384 0 - Live 0xffffffffa02f3000
tpm 36864 2 tpm_tis,tpm_tis_core, Live 0xffffffffa02d3000
video 36864 0 - Live 0xffffffffa02c9000
e1000 131072 0 - Live 0xffffffffa02a8000
i2c_piix4 24576 0 - Live 0xffffffffa0232000
intel_gtt 20480 1 intel_agp, Live 0xffffffffa02a2000
snd_intel8x0 36864 0 - Live 0xffffffffa0293000
snd_ac97_codec 118784 1 snd_intel8x0, Live 0xffffffffa026c000
ac97_bus 16384 1 snd_ac97_codec, Live 0xffffffffa0098000
snd_pcm 90112 2 snd_intel8x0,snd_ac97_codec, Live 0xffffffffa0249000
snd_timer 28672 1 snd_pcm, Live 0xffffffffa023c000
snd 69632 4 snd_intel8x0,snd_ac97_codec,snd_pcm,snd_timer, Live
0xffffffffa0220000
soundcore 16384 1 snd, Live 0xffffffffa0080000
sch_fq_codel 20480 2 - Live 0xffffffffa021a000
ip_tables 28672 0 - Live 0xffffffffa0145000
x_tables 28672 1 ip_tables, Live 0xffffffffa0150000
ext4 524288 1 - Live 0xffffffffa0199000
crc16 16384 1 ext4, Live 0xffffffffa00a9000
jbd2 90112 1 ext4, Live 0xffffffffa00f9000
fscrypto 24576 1 ext4, Live 0xffffffffa00f2000
mbcache 16384 2 ext4, Live 0xffffffffa0068000
hid_generic 16384 0 - Live 0xffffffffa006e000
usbhid 49152 0 - Live 0xffffffffa018c000
hid 114688 2 hid_generic,usbhid, Live 0xffffffffa016f000
sr_mod 24576 0 - Live 0xffffffffa00b4000
cdrom 53248 1 sr_mod, Live 0xffffffffa00e4000
sd_mod 36864 3 - Live 0xffffffffa005e000
ata_generic 16384 0 - Live 0xffffffffa001c000
pata_acpi 16384 0 - Live 0xffffffffa0017000
ohci_pci 16384 0 - Live 0xffffffffa0012000
serio_raw 16384 0 - Live 0xffffffffa00af000
atkbd 24576 0 - Live 0xffffffffa00a2000
libps2 16384 2 psmouse,atkbd, Live 0xffffffffa009d000
ata_piix 36864 2 - Live 0xffffffffa008e000
ehci_pci 16384 0 - Live 0xffffffffa0085000
ohci_hcd 49152 1 ohci_pci, Live 0xffffffffa0073000
ehci_hcd 73728 1 ehci_pci, Live 0xffffffffa015c000
libata 208896 3 ata_generic,pata_acpi,ata_piix, Live 0xffffffffa0111000
scsi_mod 159744 3 sr_mod,sd_mod,libata, Live 0xffffffffa00bc000
usbcore 208896 5 usbhid,ohci_pci,ohci_hcd,ehci_pci,ehci_hcd, Live
0xffffffffa002a000
usb_common 16384 1 usbcore, Live 0xffffffffa0022000
i8042 28672 0 - Live 0xffffffffa000a000
serio 20480 6 psmouse,serio_raw,atkbd,i8042, Live 0xffffffffa0000000
--
Registered Office: Actual Experience plc
Quay House, The Ambury, Bath BA1 1UA,
Registered No. 06838738, VAT No. 971 9696 56
The information transmitted is intended only for the person or entity to
which it is addressed and may contain confidential and/or privileged
material. Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by persons or
entities other than the intended recipient is prohibited. If you received
this in error, please contact the sender and delete the material from any
computer. Although we routinely screen for viruses, addressees should check
this e-mail and any attachment for viruses. We make no warranty as to
absence of viruses in this e-mail or any attachments.
^ permalink raw reply
* Re: [WIP] net+mlx4: auto doorbell
From: Eric Dumazet @ 2016-12-02 18:16 UTC (permalink / raw)
To: Tom Herbert
Cc: Jesper Dangaard Brouer, Willem de Bruijn, Rick Jones,
Linux Kernel Network Developers, Saeed Mahameed, Tariq Toukan,
Achiad Shochat
In-Reply-To: <1480560655.18162.255.camel@edumazet-glaptop3.roam.corp.google.com>
On Wed, 2016-11-30 at 18:50 -0800, Eric Dumazet wrote:
> On Wed, 2016-11-30 at 18:32 -0800, Eric Dumazet wrote:
>
> > I simply suggest we try to queue the qdisc for further servicing as we
> > do today, from net_tx_action(), but we might use a different bit, so
> > that we leave the opportunity for another cpu to get __QDISC_STATE_SCHED
> > before we grab it from net_tx_action(), maybe 100 usec later (time to
> > flush all skbs queued in napi_consume_skb() and maybe RX processing,
> > since most NIC handle TX completion before doing RX processing from thei
> > napi poll handler.
> >
> > Should be doable with few changes in __netif_schedule() and
> > net_tx_action(), plus some control paths that will need to take care of
> > the new bit at dismantle time, right ?
>
> Hmm... this is silly. Code already implements a different bit.
>
> qdisc_run() seems to run more often from net_tx_action(), I have to find
> out why.
After more analysis I believe TSQ was one of the bottlenecks.
I prepared a patch series that helped my use cases.
^ permalink raw reply
* Re: [PATCH net-next 1/2] samples, bpf: Refactor test_current_task_under_cgroup - separate out helpers
From: Alexei Starovoitov @ 2016-12-02 18:17 UTC (permalink / raw)
To: Sargun Dhillon; +Cc: netdev, daniel, ast
In-Reply-To: <20161202104217.GA9231@ircssh.c.rugged-nimbus-611.internal>
On Fri, Dec 02, 2016 at 02:42:18AM -0800, Sargun Dhillon wrote:
> This patch modifies test_current_task_under_cgroup_user. The test has
> several helpers around creating a temporary environment for cgroup
> testing, and moving the current task around cgroups. This set of
> helpers can then be used in other tests.
>
> Signed-off-by: Sargun Dhillon <sargun@sargun.me>
lgtm
Acked-by: Alexei Starovoitov <ast@kernel.org>
^ permalink raw reply
* Re: [PATCH net-next 2/2] samples, bpf: Add automated test for cgroup filter attachments
From: Alexei Starovoitov @ 2016-12-02 18:18 UTC (permalink / raw)
To: Sargun Dhillon; +Cc: netdev, daniel, ast
In-Reply-To: <20161202104230.GA9237@ircssh.c.rugged-nimbus-611.internal>
On Fri, Dec 02, 2016 at 02:42:32AM -0800, Sargun Dhillon wrote:
> This patch adds the sample program test_cgrp2_attach2. This program is
> similar to test_cgrp2_attach, but it performs automated testing of the
> cgroupv2 BPF attached filters. It runs the following checks:
> * Simple filter attachment
> * Application of filters to child cgroups
> * Overriding filters on child cgroups
> * Checking that this still works when the parent filter is removed
>
> The filters that are used here are simply allow all / deny all filters, so
> it isn't checking the actual functionality of the filters, but rather
> the behaviour around detachment / attachment. If net_cls is enabled,
> this test will fail.
>
> Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Nice. Thanks for the test!
Acked-by: Alexei Starovoitov <ast@kernel.org>
^ permalink raw reply
* [PATCH iproute2/net-next 2/3] tc: flower: introduce enum flower_endpoint
From: Simon Horman @ 2016-12-02 18:24 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, Jamal Hadi Salim, Jiri Pirko, Simon Horman
In-Reply-To: <1480703079-25422-1-git-send-email-simon.horman@netronome.com>
Introduce enum flower_endpoint and use it instead of a bool
as the type for paramatising source and destination.
This is intended to improve read-ability and provide some type
checking of endpoint parameters.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
v2
* Rename enums FLOWER_ENDPOINT_SRC/DST
---
tc/f_flower.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/tc/f_flower.c b/tc/f_flower.c
index 615e8f27bed2..22d95305acb4 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -23,6 +23,11 @@
#include "tc_util.h"
#include "rt_names.h"
+enum flower_endpoint {
+ FLOWER_ENDPOINT_SRC,
+ FLOWER_ENDPOINT_DST
+};
+
static void explain(void)
{
fprintf(stderr,
@@ -160,29 +165,33 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type,
return 0;
}
-static int flower_port_attr_type(__u8 ip_proto, bool is_src)
+static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
{
if (ip_proto == IPPROTO_TCP)
- return is_src ? TCA_FLOWER_KEY_TCP_SRC :
+ return endpoint == FLOWER_ENDPOINT_SRC ?
+ TCA_FLOWER_KEY_TCP_SRC :
TCA_FLOWER_KEY_TCP_DST;
else if (ip_proto == IPPROTO_UDP)
- return is_src ? TCA_FLOWER_KEY_UDP_SRC :
+ return endpoint == FLOWER_ENDPOINT_SRC ?
+ TCA_FLOWER_KEY_UDP_SRC :
TCA_FLOWER_KEY_UDP_DST;
else if (ip_proto == IPPROTO_SCTP)
- return is_src ? TCA_FLOWER_KEY_SCTP_SRC :
+ return endpoint == FLOWER_ENDPOINT_SRC ?
+ TCA_FLOWER_KEY_SCTP_SRC :
TCA_FLOWER_KEY_SCTP_DST;
else
return -1;
}
-static int flower_parse_port(char *str, __u8 ip_proto, bool is_src,
+static int flower_parse_port(char *str, __u8 ip_proto,
+ enum flower_endpoint endpoint,
struct nlmsghdr *n)
{
int ret;
int type;
__be16 port;
- type = flower_port_attr_type(ip_proto, is_src);
+ type = flower_port_attr_type(ip_proto, endpoint);
if (type < 0)
return -1;
@@ -340,14 +349,16 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
}
} else if (matches(*argv, "dst_port") == 0) {
NEXT_ARG();
- ret = flower_parse_port(*argv, ip_proto, false, n);
+ ret = flower_parse_port(*argv, ip_proto,
+ FLOWER_ENDPOINT_DST, n);
if (ret < 0) {
fprintf(stderr, "Illegal \"dst_port\"\n");
return -1;
}
} else if (matches(*argv, "src_port") == 0) {
NEXT_ARG();
- ret = flower_parse_port(*argv, ip_proto, true, n);
+ ret = flower_parse_port(*argv, ip_proto,
+ FLOWER_ENDPOINT_SRC, n);
if (ret < 0) {
fprintf(stderr, "Illegal \"src_port\"\n");
return -1;
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH iproute2/net-next 1/3] tc: flower: update headers for TCA_FLOWER_KEY_ICMP*
From: Simon Horman @ 2016-12-02 18:24 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, Jamal Hadi Salim, Jiri Pirko, Simon Horman
In-Reply-To: <1480703079-25422-1-git-send-email-simon.horman@netronome.com>
These are proposed changes for net-next.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
include/linux/pkt_cls.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index a3d8a4f17d8e..fa435ea8ad21 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -403,6 +403,16 @@ enum {
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT, /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_ICMPV4_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,/* u8 */
+
__TCA_FLOWER_MAX,
};
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH iproute2/net-next 3/3] tc: flower: support matching on ICMP type and code
From: Simon Horman @ 2016-12-02 18:24 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, Jamal Hadi Salim, Jiri Pirko, Simon Horman
In-Reply-To: <1480703079-25422-1-git-send-email-simon.horman@netronome.com>
Support matching on ICMP type and code.
Example usage:
tc qdisc add dev eth0 ingress
tc filter add dev eth0 protocol ip parent ffff: flower \
indev eth0 ip_proto icmp type 8 code 0 action drop
tc filter add dev eth0 protocol ipv6 parent ffff: flower \
indev eth0 ip_proto icmpv6 type 128 code 0 action drop
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
v2
* Rename enums FLOWER_ICMP_FIELD_TYPE/CODE
* Use above enums (oversight in v1)
---
man/man8/tc-flower.8 | 20 ++++++++---
tc/f_flower.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 107 insertions(+), 11 deletions(-)
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
index a401293fed50..c01ace6249dd 100644
--- a/man/man8/tc-flower.8
+++ b/man/man8/tc-flower.8
@@ -29,7 +29,7 @@ flower \- flow based traffic control filter
.IR PRIORITY " | "
.BR vlan_eth_type " { " ipv4 " | " ipv6 " | "
.IR ETH_TYPE " } | "
-.BR ip_proto " { " tcp " | " udp " | " sctp " | "
+.BR ip_proto " { " tcp " | " udp " | " sctp " | " icmp " | " icmpv6 " | "
.IR IP_PROTO " } | { "
.BR dst_ip " | " src_ip " } { "
.IR ipv4_address " | " ipv6_address " } | { "
@@ -94,7 +94,7 @@ or an unsigned 16bit value in hexadecimal format.
Match on layer four protocol.
.I IP_PROTO
may be
-.BR tcp ", " udp ", " sctp
+.BR tcp ", " udp ", " sctp ", " icmp ", " icmpv6
or an unsigned 8bit value in hexadecimal format.
.TP
.BI dst_ip " ADDRESS"
@@ -112,6 +112,13 @@ option of tc filter.
Match on layer 4 protocol source or destination port number. Only available for
.BR ip_proto " values " udp ", " tcp " and " sctp
which have to be specified in beforehand.
+.TP
+.BI type " NUMBER"
+.TQ
+.BI code " NUMBER"
+Match on ICMP type or code. Only available for
+.BR ip_proto " values " icmp " and " icmpv6
+which have to be specified in beforehand.
.SH NOTES
As stated above where applicable, matches of a certain layer implicitly depend
on the matches of the next lower layer. Precisely, layer one and two matches
@@ -120,13 +127,16 @@ have no dependency, layer three matches
(\fBip_proto\fR, \fBdst_ip\fR and \fBsrc_ip\fR)
depend on the
.B protocol
-option of tc filter
-and finally layer four matches
+option of tc filter, layer four port matches
(\fBdst_port\fR and \fBsrc_port\fR)
depend on
.B ip_proto
being set to
-.BR tcp ", " udp " or " sctp.
+.BR tcp ", " udp " or " sctp,
+and finally ICMP matches (\fBcode\fR and \fBtype\fR) depend on
+.B ip_proto
+being set to
+.BR icmp " or " icmpv6.
.P
There can be only used one mask per one prio. If user needs to specify different
mask, he has to use different prio.
diff --git a/tc/f_flower.c b/tc/f_flower.c
index 22d95305acb4..6cac344683e6 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -28,6 +28,11 @@ enum flower_endpoint {
FLOWER_ENDPOINT_DST
};
+enum flower_icmp_field {
+ FLOWER_ICMP_FIELD_TYPE,
+ FLOWER_ICMP_FIELD_CODE
+};
+
static void explain(void)
{
fprintf(stderr,
@@ -42,11 +47,13 @@ static void explain(void)
" vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
" dst_mac MAC-ADDR |\n"
" src_mac MAC-ADDR |\n"
- " ip_proto [tcp | udp | sctp | IP-PROTO ] |\n"
+ " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
" dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
" src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
" dst_port PORT-NUMBER |\n"
- " src_port PORT-NUMBER }\n"
+ " src_port PORT-NUMBER |\n"
+ " type ICMP-TYPE |\n"
+ " code ICMP-CODE }\n"
" FILTERID := X:Y:Z\n"
" ACTION-SPEC := ... look at individual actions\n"
"\n"
@@ -95,16 +102,23 @@ static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
int ret;
__u8 ip_proto;
- if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6)) {
- fprintf(stderr, "Illegal \"eth_type\" for ip proto\n");
- return -1;
- }
+ if (eth_type != htons(ETH_P_IP) && eth_type != htons(ETH_P_IPV6))
+ goto err;
+
if (matches(str, "tcp") == 0) {
ip_proto = IPPROTO_TCP;
} else if (matches(str, "udp") == 0) {
ip_proto = IPPROTO_UDP;
} else if (matches(str, "sctp") == 0) {
ip_proto = IPPROTO_SCTP;
+ } else if (matches(str, "icmp") == 0) {
+ if (eth_type != htons(ETH_P_IP))
+ goto err;
+ ip_proto = IPPROTO_ICMP;
+ } else if (matches(str, "icmpv6") == 0) {
+ if (eth_type != htons(ETH_P_IPV6))
+ goto err;
+ ip_proto = IPPROTO_ICMPV6;
} else {
ret = get_u8(&ip_proto, str, 16);
if (ret)
@@ -113,6 +127,10 @@ static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
addattr8(n, MAX_MSG, type, ip_proto);
*p_ip_proto = ip_proto;
return 0;
+
+err:
+ fprintf(stderr, "Illegal \"eth_type\" for ip proto\n");
+ return -1;
}
static int flower_parse_ip_addr(char *str, __be16 eth_type,
@@ -165,6 +183,41 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type,
return 0;
}
+static int flower_icmp_attr_type(__be16 eth_type, __u8 ip_proto,
+ enum flower_icmp_field field)
+{
+ if (eth_type == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP)
+ return field == FLOWER_ICMP_FIELD_CODE ?
+ TCA_FLOWER_KEY_ICMPV4_CODE :
+ TCA_FLOWER_KEY_ICMPV4_TYPE;
+ else if (eth_type == htons(ETH_P_IPV6) &&ip_proto == IPPROTO_ICMPV6)
+ return field == FLOWER_ICMP_FIELD_CODE ?
+ TCA_FLOWER_KEY_ICMPV6_CODE :
+ TCA_FLOWER_KEY_ICMPV6_TYPE;
+
+ return -1;
+}
+
+static int flower_parse_icmp(char *str, __u16 eth_type, __u8 ip_proto,
+ enum flower_icmp_field field, struct nlmsghdr *n)
+{
+ int ret;
+ int type;
+ uint8_t value;
+
+ type = flower_icmp_attr_type(eth_type, ip_proto, field);
+ if (type < 0)
+ return -1;
+
+ ret = get_u8(&value, str, 10);
+ if (ret)
+ return -1;
+
+ addattr8(n, MAX_MSG, type, value);
+
+ return 0;
+}
+
static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
{
if (ip_proto == IPPROTO_TCP)
@@ -363,6 +416,22 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
fprintf(stderr, "Illegal \"src_port\"\n");
return -1;
}
+ } else if (matches(*argv, "type") == 0) {
+ NEXT_ARG();
+ ret = flower_parse_icmp(*argv, eth_type, ip_proto,
+ FLOWER_ICMP_FIELD_TYPE, n);
+ if (ret < 0) {
+ fprintf(stderr, "Illegal \"icmp type\"\n");
+ return -1;
+ }
+ } else if (matches(*argv, "code") == 0) {
+ NEXT_ARG();
+ ret = flower_parse_icmp(*argv, eth_type, ip_proto,
+ FLOWER_ICMP_FIELD_CODE, n);
+ if (ret < 0) {
+ fprintf(stderr, "Illegal \"icmp code\"\n");
+ return -1;
+ }
} else if (matches(*argv, "action") == 0) {
NEXT_ARG();
ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
@@ -476,6 +545,10 @@ static void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto,
fprintf(f, "udp");
else if (ip_proto == IPPROTO_SCTP)
fprintf(f, "sctp");
+ else if (ip_proto == IPPROTO_ICMP)
+ fprintf(f, "icmp");
+ else if (ip_proto == IPPROTO_ICMPV6)
+ fprintf(f, "icmpv6");
else
fprintf(f, "%02x", ip_proto);
*p_ip_proto = ip_proto;
@@ -524,6 +597,12 @@ static void flower_print_port(FILE *f, char *name, struct rtattr *attr)
fprintf(f, "\n %s %d", name, ntohs(rta_getattr_u16(attr)));
}
+static void flower_print_icmp(FILE *f, char *name, struct rtattr *attr)
+{
+ if (attr)
+ fprintf(f, "\n %s %d", name, ntohs(rta_getattr_u8(attr)));
+}
+
static int flower_print_opt(struct filter_util *qu, FILE *f,
struct rtattr *opt, __u32 handle)
{
@@ -592,6 +671,13 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
if (nl_type >= 0)
flower_print_port(f, "src_port", tb[nl_type]);
+ nl_type = flower_icmp_attr_type(eth_type, ip_proto, false);
+ if (nl_type >= 0)
+ flower_print_icmp(f, "icmp_type", tb[nl_type]);
+ nl_type = flower_icmp_attr_type(eth_type, ip_proto, true);
+ if (nl_type >= 0)
+ flower_print_icmp(f, "icmp_code", tb[nl_type]);
+
if (tb[TCA_FLOWER_FLAGS]) {
__u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* [PATCH net-next 1/4] tcp: tsq: add tsq_flags / tsq_enum
From: Eric Dumazet @ 2016-12-02 18:25 UTC (permalink / raw)
To: David S . Miller; +Cc: netdev, Eric Dumazet, Eric Dumazet
In-Reply-To: <1480703159-2327-1-git-send-email-edumazet@google.com>
This is a cleanup, to ease code review of following patches.
Old 'enum tsq_flags' is renamed, and a new enumeration is added
with the flags used in cmpxchg() operations as opposed to
single bit operations.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/linux/tcp.h | 11 ++++++++++-
net/ipv4/tcp_output.c | 16 ++++++++--------
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 00e0ee8f001f..c79ee070c56f 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -363,7 +363,7 @@ struct tcp_sock {
u32 *saved_syn;
};
-enum tsq_flags {
+enum tsq_enum {
TSQ_THROTTLED,
TSQ_QUEUED,
TCP_TSQ_DEFERRED, /* tcp_tasklet_func() found socket was owned */
@@ -374,6 +374,15 @@ enum tsq_flags {
*/
};
+enum tsq_flags {
+ TSQF_THROTTLED = (1UL << TSQ_THROTTLED),
+ TSQF_QUEUED = (1UL << TSQ_QUEUED),
+ TCPF_TSQ_DEFERRED = (1UL << TCP_TSQ_DEFERRED),
+ TCPF_WRITE_TIMER_DEFERRED = (1UL << TCP_WRITE_TIMER_DEFERRED),
+ TCPF_DELACK_TIMER_DEFERRED = (1UL << TCP_DELACK_TIMER_DEFERRED),
+ TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED),
+};
+
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
{
return (struct tcp_sock *)sk;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index d3545d0cff75..ac55aefc881d 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -784,10 +784,10 @@ static void tcp_tasklet_func(unsigned long data)
}
}
-#define TCP_DEFERRED_ALL ((1UL << TCP_TSQ_DEFERRED) | \
- (1UL << TCP_WRITE_TIMER_DEFERRED) | \
- (1UL << TCP_DELACK_TIMER_DEFERRED) | \
- (1UL << TCP_MTU_REDUCED_DEFERRED))
+#define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED | \
+ TCPF_WRITE_TIMER_DEFERRED | \
+ TCPF_DELACK_TIMER_DEFERRED | \
+ TCPF_MTU_REDUCED_DEFERRED)
/**
* tcp_release_cb - tcp release_sock() callback
* @sk: socket
@@ -808,7 +808,7 @@ void tcp_release_cb(struct sock *sk)
nflags = flags & ~TCP_DEFERRED_ALL;
} while (cmpxchg(&tp->tsq_flags, flags, nflags) != flags);
- if (flags & (1UL << TCP_TSQ_DEFERRED))
+ if (flags & TCPF_TSQ_DEFERRED)
tcp_tsq_handler(sk);
/* Here begins the tricky part :
@@ -822,15 +822,15 @@ void tcp_release_cb(struct sock *sk)
*/
sock_release_ownership(sk);
- if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
+ if (flags & TCPF_WRITE_TIMER_DEFERRED) {
tcp_write_timer_handler(sk);
__sock_put(sk);
}
- if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED)) {
+ if (flags & TCPF_DELACK_TIMER_DEFERRED) {
tcp_delack_timer_handler(sk);
__sock_put(sk);
}
- if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) {
+ if (flags & TCPF_MTU_REDUCED_DEFERRED) {
inet_csk(sk)->icsk_af_ops->mtu_reduced(sk);
__sock_put(sk);
}
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH net-next 0/4] tcp: tsq: performance series
From: Eric Dumazet @ 2016-12-02 18:25 UTC (permalink / raw)
To: David S . Miller; +Cc: netdev, Eric Dumazet, Eric Dumazet
Under very high TX stress, CPU handling NIC TX completions can spend
considerable amount of cycles handling TSQ (TCP Small Queues) logic.
This patch series avoids some atomic operations, but more important
patch is the 3rd one, allowing other cpus processing ACK packets and
calling tcp_write_xmit() to grab TCP_TSQ_DEFERRED so that
tcp_tasklet_func() can skip already processed sockets.
This avoid lots of lock acquisitions and cache lines accesses,
particularly under load.
Eric Dumazet (4):
tcp: tsq: add tsq_flags / tsq_enum
tcp: tsq: remove one locked operation in tcp_wfree()
tcp: tsq: add shortcut in tcp_tasklet_func()
tcp: tsq: avoid one atomic in tcp_wfree()
include/linux/tcp.h | 11 ++++++++++-
net/ipv4/tcp_output.c | 54 +++++++++++++++++++++++++++++++--------------------
2 files changed, 43 insertions(+), 22 deletions(-)
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply
* [PATCH net-next 2/4] tcp: tsq: remove one locked operation in tcp_wfree()
From: Eric Dumazet @ 2016-12-02 18:25 UTC (permalink / raw)
To: David S . Miller; +Cc: netdev, Eric Dumazet, Eric Dumazet
In-Reply-To: <1480703159-2327-1-git-send-email-edumazet@google.com>
Instead of atomically clear TSQ_THROTTLED and atomically set TSQ_QUEUED
bits, use one cmpxchg() to perform a single locked operation.
Since the following patch will also set TCP_TSQ_DEFERRED here,
this cmpxchg() will make this addition free.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp_output.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ac55aefc881d..76be79437595 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -860,6 +860,7 @@ void tcp_wfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct tcp_sock *tp = tcp_sk(sk);
+ unsigned long flags, nval, oval;
int wmem;
/* Keep one reference on sk_wmem_alloc.
@@ -877,11 +878,17 @@ void tcp_wfree(struct sk_buff *skb)
if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current)
goto out;
- if (test_and_clear_bit(TSQ_THROTTLED, &tp->tsq_flags) &&
- !test_and_set_bit(TSQ_QUEUED, &tp->tsq_flags)) {
- unsigned long flags;
+ for (oval = READ_ONCE(tp->tsq_flags);; oval = nval) {
struct tsq_tasklet *tsq;
+ if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED))
+ goto out;
+
+ nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED;
+ nval = cmpxchg(&tp->tsq_flags, oval, nval);
+ if (nval != oval)
+ continue;
+
/* queue this socket to tasklet queue */
local_irq_save(flags);
tsq = this_cpu_ptr(&tsq_tasklet);
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH net-next 3/4] tcp: tsq: add shortcut in tcp_tasklet_func()
From: Eric Dumazet @ 2016-12-02 18:25 UTC (permalink / raw)
To: David S . Miller; +Cc: netdev, Eric Dumazet, Eric Dumazet
In-Reply-To: <1480703159-2327-1-git-send-email-edumazet@google.com>
Under high stress, I've seen tcp_tasklet_func() consuming
~700 usec, handling ~150 tcp sockets.
By setting TCP_TSQ_DEFERRED in tcp_wfree(), we give a chance
for other cpus/threads entering tcp_write_xmit() to grab it,
allowing tcp_tasklet_func() to skip sockets that already did
an xmit cycle.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp_output.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 76be79437595..9143c52b3105 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -767,19 +767,19 @@ static void tcp_tasklet_func(unsigned long data)
list_for_each_safe(q, n, &list) {
tp = list_entry(q, struct tcp_sock, tsq_node);
list_del(&tp->tsq_node);
+ clear_bit(TSQ_QUEUED, &tp->tsq_flags);
sk = (struct sock *)tp;
- bh_lock_sock(sk);
-
- if (!sock_owned_by_user(sk)) {
- tcp_tsq_handler(sk);
- } else {
- /* defer the work to tcp_release_cb() */
- set_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
+ if (!sk->sk_lock.owned &&
+ test_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags)) {
+ bh_lock_sock(sk);
+ if (!sock_owned_by_user(sk)) {
+ clear_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
+ tcp_tsq_handler(sk);
+ }
+ bh_unlock_sock(sk);
}
- bh_unlock_sock(sk);
- clear_bit(TSQ_QUEUED, &tp->tsq_flags);
sk_free(sk);
}
}
@@ -884,7 +884,7 @@ void tcp_wfree(struct sk_buff *skb)
if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED))
goto out;
- nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED;
+ nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED | TCP_TSQ_DEFERRED;
nval = cmpxchg(&tp->tsq_flags, oval, nval);
if (nval != oval)
continue;
@@ -2229,6 +2229,8 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
break;
+ if (test_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags))
+ clear_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags);
if (tcp_small_queue_check(sk, skb, 0))
break;
--
2.8.0.rc3.226.g39d4020
^ 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