* Re: [PATCH v3 00/27] kill devm_ioremap_nocache
From: Yisheng Xie @ 2017-12-25 1:34 UTC (permalink / raw)
To: christophe leroy, Greg KH
Cc: linux-mips, ulf.hansson, jakub.kicinski, platform-driver-x86,
airlied, linux-wireless, linus.walleij, alsa-devel, dri-devel,
linux-kernel, linux-ide, linux-mtd, daniel.vetter, dan.j.williams,
jason, linux-rtc, boris.brezillon, mchehab, dmaengine, vinod.koul,
richard, marek.vasut, industrypack-devel, linux-pci, dvhart,
linux, linux-media, seanpaul, devel, linux-watchdog, arnd,
b.zolnierkie, marc.zyngier, jslaby
In-Reply-To: <b8ff7f17-7f2c-f220-9833-7ae5bd7343d5@c-s.fr>
On 2017/12/24 17:05, christophe leroy wrote:
>
>
> Le 23/12/2017 à 14:48, Greg KH a écrit :
>> On Sat, Dec 23, 2017 at 06:55:25PM +0800, Yisheng Xie wrote:
>>> Hi all,
>>>
>>> When I tried to use devm_ioremap function and review related code, I found
>>> devm_ioremap and devm_ioremap_nocache is almost the same with each other,
>>> except one use ioremap while the other use ioremap_nocache.
>>
>> For all arches? Really? Look at MIPS, and x86, they have different
>> functions.
>>
>>> While ioremap's
>>> default function is ioremap_nocache, so devm_ioremap_nocache also have the
>>> same function with devm_ioremap, which can just be killed to reduce the size
>>> of devres.o(from 20304 bytes to 18992 bytes in my compile environment).
>>>
>>> I have posted two versions, which use macro instead of function for
>>> devm_ioremap_nocache[1] or devm_ioremap[2]. And Greg suggest me to kill
>>> devm_ioremap_nocache for no need to keep a macro around for the duplicate
>>> thing. So here comes v3 and please help to review.
>>
>> I don't think this can be done, what am I missing? These functions are
>> not identical, sorry for missing that before.
>
> devm_ioremap() and devm_ioremap_nocache() are quite similar, both use devm_ioremap_release() for the release, why not just defining:
>
> static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
> resource_size_t size, bool nocache)
> {
> [...]
> if (nocache)
> addr = ioremap_nocache(offset, size);
> else
> addr = ioremap(offset, size);
> [...]
> }
>
> then in include/linux/io.h
>
> static inline void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
> resource_size_t size)
> {return __devm_ioremap(dev, offset, size, false);}
>
> static inline void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
> resource_size_t size);
> {return __devm_ioremap(dev, offset, size, true);}
Yeah, this seems good to me, right now we have devm_ioremap, devm_ioremap_wc, devm_ioremap_nocache
May be we can use an enum like:
typedef enum {
DEVM_IOREMAP = 0,
DEVM_IOREMAP_NOCACHE,
DEVM_IOREMAP_WC,
} devm_ioremap_type;
static inline void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
resource_size_t size)
{return __devm_ioremap(dev, offset, size, DEVM_IOREMAP);}
static inline void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
resource_size_t size);
{return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NOCACHE);}
static inline void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
resource_size_t size);
{return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_WC);}
static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
resource_size_t size, devm_ioremap_type type)
{
void __iomem **ptr, *addr = NULL;
[...]
switch (type){
case DEVM_IOREMAP:
addr = ioremap(offset, size);
break;
case DEVM_IOREMAP_NOCACHE:
addr = ioremap_nocache(offset, size);
break;
case DEVM_IOREMAP_WC:
addr = ioremap_wc(offset, size);
break;
}
[...]
}
Thanks
Yisheng
>
> Christophe
>
>>
>> thanks,
>>
>> greg k-h
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> ---
> L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
> https://www.avast.com/antivirus
>
>
> .
>
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
^ permalink raw reply
* Re: [PATCH v3 27/27] devres: kill devm_ioremap_nocache
From: Yisheng Xie @ 2017-12-25 1:43 UTC (permalink / raw)
To: Greg KH
Cc: linux-mips, ulf.hansson, jakub.kicinski, lgirdwood, airlied,
linux-pci, linus.walleij, alsa-devel, dri-devel,
platform-driver-x86, linux-ide, linux-mtd, daniel.vetter, tglx,
linux-watchdog, linux-rtc, boris.brezillon, andriy.shevchenko,
vinod.koul, richard, alexandre.belloni, marek.vasut,
industrypack-devel, jslaby, dvhart, linux, linux-media, devel,
jason, arnd, b.zolnierkie, marc.zyngier, linux-mmc, jani.niku
In-Reply-To: <20171223134532.GA10103@kroah.com>
On 2017/12/23 21:45, Greg KH wrote:
> On Sat, Dec 23, 2017 at 07:02:59PM +0800, Yisheng Xie wrote:
>> --- a/lib/devres.c
>> +++ b/lib/devres.c
>> @@ -44,35 +44,6 @@ void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
>> EXPORT_SYMBOL(devm_ioremap);
>>
>> /**
>> - * devm_ioremap_nocache - Managed ioremap_nocache()
>> - * @dev: Generic device to remap IO address for
>> - * @offset: Resource address to map
>> - * @size: Size of map
>> - *
>> - * Managed ioremap_nocache(). Map is automatically unmapped on driver
>> - * detach.
>> - */
>> -void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
>> - resource_size_t size)
>> -{
>> - void __iomem **ptr, *addr;
>> -
>> - ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
>> - if (!ptr)
>> - return NULL;
>> -
>> - addr = ioremap_nocache(offset, size);
>
> Wait, devm_ioremap() calls ioremap(), not ioremap_nocache(), are you
> _SURE_ that these are all identical? For all arches? If so, then
> ioremap_nocache() can also be removed, right?
Yeah, As Christophe pointed out, that 4 archs do not have the same function.
But I do not why they do not want do the same thing. Driver may no know about
this? right?
>
> In my quick glance, I don't think you can do this series at all :(
Yes, maybe should take Christophe suggestion and use a bool or enum to distinguish them?
Thanks
Yisheng
>
> greg k-h
>
> .
>
^ permalink raw reply
* [PATCH] ip6_tunnel: disable dst caching if tunnel is dual-stack
From: Eli Cooper @ 2017-12-25 2:43 UTC (permalink / raw)
To: netdev; +Cc: David S . Miller
When an ip6_tunnel is in mode 'any', where the transport layer
protocol can be either 4 or 41, dst_cache must be disabled.
This is because xfrm policies might apply to only one of the two
protocols. Caching dst would cause xfrm policies for one protocol
incorrectly used for the other.
Cc: stable@vger.kernel.org
Signed-off-by: Eli Cooper <elicooper@gmx.com>
---
net/ipv6/ip6_tunnel.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 931c38f6ff4a..8aea23d15ddd 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1074,10 +1074,10 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
neigh_release(neigh);
}
- } else if (!(t->parms.flags &
+ } else if (t->parms.proto != 0 && !(t->parms.flags &
(IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
- /* enable the cache only only if the routing decision does
- * not depend on the current inner header value
+ /* enable the cache only if neither the outer protocol nor the
+ * routing decision depends on the current inner header value
*/
use_cache = true;
}
--
2.15.1
^ permalink raw reply related
* [PATCH] net: sched: fix skb leak in dev_requeue_skb()
From: Wei Yongjun @ 2017-12-25 3:39 UTC (permalink / raw)
To: John Fastabend, Jamal Hadi Salim, Cong Wang, Jiri Pirko
Cc: Wei Yongjun, netdev
When dev_requeue_skb() is called with bluked skb list, only the
first skb of the list will be requeued to qdisc layer, and leak
the others without free them.
TCP is broken due to skb leak since no free skb will be considered
as still in the host queue and never be retransmitted. This happend
when dev_requeue_skb() called from qdisc_restart().
qdisc_restart
|-- dequeue_skb
|-- sch_direct_xmit()
|-- dev_requeue_skb() <-- skb may bluked
Fix dev_requeue_skb() to requeue the full bluked list.
Fixes: a53851e2c321 ("net: sched: explicit locking in gso_cpu fallback")
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 981c08f..0df2dbf 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -111,10 +111,16 @@ static inline void qdisc_enqueue_skb_bad_txq(struct Qdisc *q,
static inline int __dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
{
- __skb_queue_head(&q->gso_skb, skb);
- q->qstats.requeues++;
- qdisc_qstats_backlog_inc(q, skb);
- q->q.qlen++; /* it's still part of the queue */
+ while (skb) {
+ struct sk_buff *next = skb->next;
+
+ __skb_queue_tail(&q->gso_skb, skb);
+ q->qstats.requeues++;
+ qdisc_qstats_backlog_inc(q, skb);
+ q->q.qlen++; /* it's still part of the queue */
+
+ skb = next;
+ }
__netif_schedule(q);
return 0;
@@ -124,13 +130,20 @@ static inline int dev_requeue_skb_locked(struct sk_buff *skb, struct Qdisc *q)
{
spinlock_t *lock = qdisc_lock(q);
- spin_lock(lock);
- __skb_queue_tail(&q->gso_skb, skb);
- spin_unlock(lock);
+ while (skb) {
+ struct sk_buff *next = skb->next;
+
+ spin_lock(lock);
+ __skb_queue_tail(&q->gso_skb, skb);
+ spin_unlock(lock);
+
+ qdisc_qstats_cpu_requeues_inc(q);
+ qdisc_qstats_cpu_backlog_inc(q, skb);
+ qdisc_qstats_cpu_qlen_inc(q);
+
+ skb = next;
+ }
- qdisc_qstats_cpu_requeues_inc(q);
- qdisc_qstats_cpu_backlog_inc(q, skb);
- qdisc_qstats_cpu_qlen_inc(q);
__netif_schedule(q);
return 0;
--
1.8.3.1
^ permalink raw reply related
* RE: [PATCH] net: sched: fix skb leak in dev_requeue_skb()
From: weiyongjun (A) @ 2017-12-25 3:38 UTC (permalink / raw)
To: John Fastabend, Jamal Hadi Salim, Cong Wang, Jiri Pirko
Cc: netdev@vger.kernel.org
In-Reply-To: <1514173173-164916-1-git-send-email-weiyongjun1@huawei.com>
> When dev_requeue_skb() is called with bluked skb list, only the
> first skb of the list will be requeued to qdisc layer, and leak
> the others without free them.
>
> TCP is broken due to skb leak since no free skb will be considered
> as still in the host queue and never be retransmitted. This happend
> when dev_requeue_skb() called from qdisc_restart().
> qdisc_restart
> |-- dequeue_skb
> |-- sch_direct_xmit()
> |-- dev_requeue_skb() <-- skb may bluked
>
> Fix dev_requeue_skb() to requeue the full bluked list.
>
> Fixes: a53851e2c321 ("net: sched: explicit locking in gso_cpu fallback")
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Sorry, I forgot the 'net-next' prefix, please ignore this one, I will resend it.
^ permalink raw reply
* [PATCH net-next v2] net: sched: fix skb leak in dev_requeue_skb()
From: Wei Yongjun @ 2017-12-25 3:49 UTC (permalink / raw)
To: John Fastabend, Jamal Hadi Salim, Cong Wang, Jiri Pirko
Cc: Wei Yongjun, netdev
When dev_requeue_skb() is called with bluked skb list, only the
first skb of the list will be requeued to qdisc layer, and leak
the others without free them.
TCP is broken due to skb leak since no free skb will be considered
as still in the host queue and never be retransmitted. This happend
when dev_requeue_skb() called from qdisc_restart().
qdisc_restart
|-- dequeue_skb
|-- sch_direct_xmit()
|-- dev_requeue_skb() <-- skb may bluked
Fix dev_requeue_skb() to requeue the full bluked list.
Fixes: a53851e2c321 ("net: sched: explicit locking in gso_cpu fallback")
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
v1 -> v2: add net-next prefix
---
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 981c08f..0df2dbf 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -111,10 +111,16 @@ static inline void qdisc_enqueue_skb_bad_txq(struct Qdisc *q,
static inline int __dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
{
- __skb_queue_head(&q->gso_skb, skb);
- q->qstats.requeues++;
- qdisc_qstats_backlog_inc(q, skb);
- q->q.qlen++; /* it's still part of the queue */
+ while (skb) {
+ struct sk_buff *next = skb->next;
+
+ __skb_queue_tail(&q->gso_skb, skb);
+ q->qstats.requeues++;
+ qdisc_qstats_backlog_inc(q, skb);
+ q->q.qlen++; /* it's still part of the queue */
+
+ skb = next;
+ }
__netif_schedule(q);
return 0;
@@ -124,13 +130,20 @@ static inline int dev_requeue_skb_locked(struct sk_buff *skb, struct Qdisc *q)
{
spinlock_t *lock = qdisc_lock(q);
- spin_lock(lock);
- __skb_queue_tail(&q->gso_skb, skb);
- spin_unlock(lock);
+ while (skb) {
+ struct sk_buff *next = skb->next;
+
+ spin_lock(lock);
+ __skb_queue_tail(&q->gso_skb, skb);
+ spin_unlock(lock);
+
+ qdisc_qstats_cpu_requeues_inc(q);
+ qdisc_qstats_cpu_backlog_inc(q, skb);
+ qdisc_qstats_cpu_qlen_inc(q);
+
+ skb = next;
+ }
- qdisc_qstats_cpu_requeues_inc(q);
- qdisc_qstats_cpu_backlog_inc(q, skb);
- qdisc_qstats_cpu_qlen_inc(q);
__netif_schedule(q);
return 0;
--
1.8.3.1
^ permalink raw reply related
* [PATCH net] geneve: update skb dst pmtu on tx path
From: Xin Long @ 2017-12-25 6:43 UTC (permalink / raw)
To: network dev; +Cc: davem
Commit a93bf0ff4490 ("vxlan: update skb dst pmtu on tx path") has fixed
a performance issue caused by the change of lower dev's mtu for vxlan.
The same thing needs to be done for geneve as well.
Note that geneve cannot adjust it's mtu according to lower dev's mtu
when creating it. The performance is very low later when netperfing
over it without fixing the mtu manually. This patch could also avoid
this issue.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
drivers/net/geneve.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index b718a02..0a48b30 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -825,6 +825,13 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(rt))
return PTR_ERR(rt);
+ if (skb_dst(skb)) {
+ int mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr) -
+ GENEVE_BASE_HLEN - info->options_len - 14;
+
+ skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
+ }
+
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
if (geneve->collect_md) {
tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
@@ -864,6 +871,13 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(dst))
return PTR_ERR(dst);
+ if (skb_dst(skb)) {
+ int mtu = dst_mtu(dst) - sizeof(struct ipv6hdr) -
+ GENEVE_BASE_HLEN - info->options_len - 14;
+
+ skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
+ }
+
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
if (geneve->collect_md) {
prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
--
2.1.0
^ permalink raw reply related
* [PATCH net] ip6_tunnel: allow ip6gre dev mtu to be set below 1280
From: Xin Long @ 2017-12-25 6:45 UTC (permalink / raw)
To: network dev; +Cc: davem
Commit 582442d6d5bc ("ipv6: Allow the MTU of ipip6 tunnel to be set
below 1280") fixed a mtu setting issue. It works for ipip6 tunnel.
But ip6gre dev updates the mtu also with ip6_tnl_change_mtu. Since
the inner packet over ip6gre can be ipv4 and it's mtu should also
be allowed to set below 1280, the same issue also exists on ip6gre.
This patch is to fix it by simply changing to check if parms.proto
is IPPROTO_IPV6 in ip6_tnl_change_mtu instead, to make ip6gre to
go to 'else' branch.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
net/ipv6/ip6_tunnel.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 931c38f..1b30777c 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1676,11 +1676,11 @@ int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
{
struct ip6_tnl *tnl = netdev_priv(dev);
- if (tnl->parms.proto == IPPROTO_IPIP) {
- if (new_mtu < ETH_MIN_MTU)
+ if (tnl->parms.proto == IPPROTO_IPV6) {
+ if (new_mtu < IPV6_MIN_MTU)
return -EINVAL;
} else {
- if (new_mtu < IPV6_MIN_MTU)
+ if (new_mtu < ETH_MIN_MTU)
return -EINVAL;
}
if (new_mtu > 0xFFF8 - dev->hard_header_len)
--
2.1.0
^ permalink raw reply related
* [patch net] mlxsw: spectrum_router: Fix NULL pointer deref
From: Jiri Pirko @ 2017-12-25 7:57 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
From: Ido Schimmel <idosch@mellanox.com>
When we remove the neighbour associated with a nexthop we should always
refuse to write the nexthop to the adjacency table. Regardless if it is
already present in the table or not.
Otherwise, we risk dereferencing the NULL pointer that was set instead
of the neighbour.
Fixes: a7ff87acd995 ("mlxsw: spectrum_router: Implement next-hop routing")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reported-by: Alexander Petrovskiy <alexpe@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index be657b8..434b392 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3228,7 +3228,7 @@ static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
{
if (!removing)
nh->should_offload = 1;
- else if (nh->offloaded)
+ else
nh->should_offload = 0;
nh->update = 1;
}
--
2.9.5
^ permalink raw reply related
* Re: [patch net] mlxsw: spectrum_router: Fix NULL pointer deref
From: Jiri Pirko @ 2017-12-25 8:02 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
In-Reply-To: <20171225075735.2058-1-jiri@resnulli.us>
Mon, Dec 25, 2017 at 08:57:35AM CET, jiri@resnulli.us wrote:
>From: Ido Schimmel <idosch@mellanox.com>
>
>When we remove the neighbour associated with a nexthop we should always
>refuse to write the nexthop to the adjacency table. Regardless if it is
>already present in the table or not.
>
>Otherwise, we risk dereferencing the NULL pointer that was set instead
>of the neighbour.
>
>Fixes: a7ff87acd995 ("mlxsw: spectrum_router: Implement next-hop routing")
>Signed-off-by: Ido Schimmel <idosch@mellanox.com>
>Reported-by: Alexander Petrovskiy <alexpe@mellanox.com>
>Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Dave, could you please queue this up for 4.14.y together
with "mlxsw: spectrum: Relax sanity checks during enslavement".
Thanks!
^ permalink raw reply
* [patch net] mlxsw: spectrum: Relax sanity checks during enslavement
From: Jiri Pirko @ 2017-12-25 8:05 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, alexpe, mlxsw
From: Ido Schimmel <idosch@mellanox.com>
Since commit 25cc72a33835 ("mlxsw: spectrum: Forbid linking to devices that
have uppers") the driver forbids enslavement to netdevs that already
have uppers of their own, as this can result in various ordering
problems.
This requirement proved to be too strict for some users who need to be
able to enslave ports to a bridge that already has uppers. In this case,
we can allow the enslavement if the bridge is already known to us, as
any configuration performed on top of the bridge was already reflected
to the device.
Fixes: 25cc72a33835 ("mlxsw: spectrum: Forbid linking to devices that have uppers")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reported-by: Alexander Petrovskiy <alexpe@mellanox.com>
Tested-by: Alexander Petrovskiy <alexpe@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 11 +++++++++--
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 6 ++++++
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 9bd8d28..c3837ca 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -4376,7 +4376,10 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
}
if (!info->linking)
break;
- if (netdev_has_any_upper_dev(upper_dev)) {
+ if (netdev_has_any_upper_dev(upper_dev) &&
+ (!netif_is_bridge_master(upper_dev) ||
+ !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
+ upper_dev))) {
NL_SET_ERR_MSG(extack,
"spectrum: Enslaving a port to a device that already has an upper device is not supported");
return -EINVAL;
@@ -4504,6 +4507,7 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
u16 vid)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct netdev_notifier_changeupper_info *info = ptr;
struct netlink_ext_ack *extack;
struct net_device *upper_dev;
@@ -4520,7 +4524,10 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
}
if (!info->linking)
break;
- if (netdev_has_any_upper_dev(upper_dev)) {
+ if (netdev_has_any_upper_dev(upper_dev) &&
+ (!netif_is_bridge_master(upper_dev) ||
+ !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
+ upper_dev))) {
NL_SET_ERR_MSG(extack, "spectrum: Enslaving a port to a device that already has an upper device is not supported");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 432ab9b..05ce1be 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -365,6 +365,8 @@ int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *brport_dev,
struct net_device *br_dev);
+bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *br_dev);
/* spectrum.c */
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 7b8548e..593ad31 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -152,6 +152,12 @@ mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge,
return NULL;
}
+bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *br_dev)
+{
+ return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
+}
+
static struct mlxsw_sp_bridge_device *
mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
struct net_device *br_dev)
--
2.9.5
^ permalink raw reply related
* [patch iproute2 v3 0/4] tc: Add -bs option to batch mode
From: Chris Mi @ 2017-12-25 8:46 UTC (permalink / raw)
To: netdev; +Cc: gerlitz.or, stephen, dsahern
Currently in tc batch mode, only one command is read from the batch
file and sent to kernel to process. With this patchset, we can accumulate
several commands before sending to kernel. The batch size is specified
using option -bs or -batchsize.
To accumulate the commands in tc, client should allocate an array of
struct iovec. If batchsize is bigger than 1, only after the client
has accumulated enough commands, can the client call rtnl_talk_msg
to send the message that includes the iov array. One exception is
that there is no more command in the batch file.
But please note that kernel still processes the requests one by one.
To process the requests in parallel in kernel is another effort.
The time we're saving in this patchset is the user mode and kernel mode
context switch. So this patchset works on top of the current kernel.
Using the following script in kernel, we can generate 1,000,000 rules.
tools/testing/selftests/tc-testing/tdc_batch.py
Without this patchset, 'tc -b $file' exection time is:
real 0m15.125s
user 0m6.982s
sys 0m8.080s
With this patchset, 'tc -b $file -bs 10' exection time is:
real 0m12.772s
user 0m5.984s
sys 0m6.723s
The insertion rate is improved more than 10%.
In this patchset, we still ack for every rule. If we don't ack at all,
'tc -b $file' exection time is:
real 0m14.484s
user 0m6.919s
sys 0m7.498s
'tc -b $file -bs 10' exection time is:
real 0m11.664s
user 0m6.017s
sys 0m5.578s
We can see that the performance win is to send multiple messages instead
of no acking. I think that's because in tc, we don't spend too much time
processing the ack message.
v3
==
1. Instead of hacking function rtnl_talk directly, add a new function
rtnl_talk_msg.
2. remove most of global variables to use parameter passing
3. divide the previous patch into 4 patches.
Chris Mi (4):
lib/libnetlink: Add a function rtnl_talk_msg
utils: Add a function setcmdlinetotal
tc: Add -bs option to batch mode
man: Add -bs option to tc manpage
include/libnetlink.h | 3 ++
include/utils.h | 4 ++
lib/libnetlink.c | 92 ++++++++++++++++++++++++++++++---------
lib/utils.c | 20 +++++++++
man/man8/tc.8 | 5 +++
tc/m_action.c | 91 +++++++++++++++++++++++++++++---------
tc/tc.c | 47 ++++++++++++++++----
tc/tc_common.h | 8 +++-
tc/tc_filter.c | 121 +++++++++++++++++++++++++++++++++++++--------------
9 files changed, 307 insertions(+), 84 deletions(-)
--
2.14.3
^ permalink raw reply
* [patch iproute2 v3 3/4] tc: Add -bs option to batch mode
From: Chris Mi @ 2017-12-25 8:46 UTC (permalink / raw)
To: netdev; +Cc: gerlitz.or, stephen, dsahern
In-Reply-To: <20171225084658.24076-1-chrism@mellanox.com>
Signed-off-by: Chris Mi <chrism@mellanox.com>
---
tc/m_action.c | 91 +++++++++++++++++++++++++++++++++----------
tc/tc.c | 47 ++++++++++++++++++----
tc/tc_common.h | 8 +++-
tc/tc_filter.c | 121 +++++++++++++++++++++++++++++++++++++++++----------------
4 files changed, 204 insertions(+), 63 deletions(-)
diff --git a/tc/m_action.c b/tc/m_action.c
index fc422364..c4c3b862 100644
--- a/tc/m_action.c
+++ b/tc/m_action.c
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
#include <string.h>
#include <dlfcn.h>
+#include <errno.h>
#include "utils.h"
#include "tc_common.h"
@@ -546,40 +547,88 @@ bad_val:
return ret;
}
+typedef struct {
+ struct nlmsghdr n;
+ struct tcamsg t;
+ char buf[MAX_MSG];
+} tc_action_req;
+
+static tc_action_req *action_reqs;
+static struct iovec msg_iov[MSG_IOV_MAX];
+
+void free_action_reqs(void)
+{
+ free(action_reqs);
+}
+
+static tc_action_req *get_action_req(int batch_size, int index)
+{
+ tc_action_req *req;
+
+ if (action_reqs == NULL) {
+ action_reqs = malloc(batch_size * sizeof (tc_action_req));
+ if (action_reqs == NULL)
+ return NULL;
+ }
+ req = &action_reqs[index];
+ memset(req, 0, sizeof (*req));
+
+ return req;
+}
+
static int tc_action_modify(int cmd, unsigned int flags,
- int *argc_p, char ***argv_p)
+ int *argc_p, char ***argv_p,
+ int batch_size, int index, bool send)
{
int argc = *argc_p;
char **argv = *argv_p;
int ret = 0;
- struct {
- struct nlmsghdr n;
- struct tcamsg t;
- char buf[MAX_MSG];
- } req = {
- .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
- .n.nlmsg_flags = NLM_F_REQUEST | flags,
- .n.nlmsg_type = cmd,
- .t.tca_family = AF_UNSPEC,
+ tc_action_req *req;
+ struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
+ struct iovec *iov = &msg_iov[index];
+
+ req = get_action_req(batch_size, index);
+ if (req == NULL) {
+ fprintf(stderr, "get_action_req error: not enough buffer\n");
+ return -ENOMEM;
+ }
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST | flags;
+ req->n.nlmsg_type = cmd;
+ req->t.tca_family = AF_UNSPEC;
+ struct rtattr *tail = NLMSG_TAIL(&req->n);
+
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = msg_iov,
+ .msg_iovlen = index + 1,
};
- struct rtattr *tail = NLMSG_TAIL(&req.n);
argc -= 1;
argv += 1;
- if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
+ if (parse_action(&argc, &argv, TCA_ACT_TAB, &req->n)) {
fprintf(stderr, "Illegal \"action\"\n");
return -1;
}
- tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
+ tail->rta_len = (void *) NLMSG_TAIL(&req->n) - (void *) tail;
+
+ *argc_p = argc;
+ *argv_p = argv;
+
+ iov->iov_base = &req->n;
+ iov->iov_len = req->n.nlmsg_len;
+
+ if (!send)
+ return 0;
- if (rtnl_talk(&rth, &req.n, NULL) < 0) {
+ ret = rtnl_talk_msg(&rth, &msg, NULL);
+ if (ret < 0) {
fprintf(stderr, "We have an error talking to the kernel\n");
ret = -1;
}
- *argc_p = argc;
- *argv_p = argv;
-
return ret;
}
@@ -679,7 +728,7 @@ bad_val:
return ret;
}
-int do_action(int argc, char **argv)
+int do_action(int argc, char **argv, int batch_size, int index, bool send)
{
int ret = 0;
@@ -689,12 +738,14 @@ int do_action(int argc, char **argv)
if (matches(*argv, "add") == 0) {
ret = tc_action_modify(RTM_NEWACTION,
NLM_F_EXCL | NLM_F_CREATE,
- &argc, &argv);
+ &argc, &argv, batch_size,
+ index, send);
} else if (matches(*argv, "change") == 0 ||
matches(*argv, "replace") == 0) {
ret = tc_action_modify(RTM_NEWACTION,
NLM_F_CREATE | NLM_F_REPLACE,
- &argc, &argv);
+ &argc, &argv, batch_size,
+ index, send);
} else if (matches(*argv, "delete") == 0) {
argc -= 1;
argv += 1;
diff --git a/tc/tc.c b/tc/tc.c
index ad9f07e9..7ea2fc89 100644
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -189,20 +189,20 @@ static void usage(void)
fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
" tc [-force] -batch filename\n"
"where OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
- " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -n[etns] name |\n"
+ " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -bs | -batchsize [size] | -n[etns] name |\n"
" -nm | -nam[es] | { -cf | -conf } path } | -j[son]\n");
}
-static int do_cmd(int argc, char **argv)
+static int do_cmd(int argc, char **argv, int batch_size, int index, bool send)
{
if (matches(*argv, "qdisc") == 0)
return do_qdisc(argc-1, argv+1);
if (matches(*argv, "class") == 0)
return do_class(argc-1, argv+1);
if (matches(*argv, "filter") == 0)
- return do_filter(argc-1, argv+1);
+ return do_filter(argc-1, argv+1, batch_size, index, send);
if (matches(*argv, "actions") == 0)
- return do_action(argc-1, argv+1);
+ return do_action(argc-1, argv+1, batch_size, index, send);
if (matches(*argv, "monitor") == 0)
return do_tcmonitor(argc-1, argv+1);
if (matches(*argv, "exec") == 0)
@@ -217,11 +217,16 @@ static int do_cmd(int argc, char **argv)
return -1;
}
-static int batch(const char *name)
+static int batch(const char *name, int batch_size)
{
+ int msg_iov_index = 0;
char *line = NULL;
size_t len = 0;
int ret = 0;
+ bool send;
+
+ if (batch_size > 1)
+ setcmdlinetotal(name);
batch_mode = 1;
if (name && strcmp(name, "-") != 0) {
@@ -248,15 +253,30 @@ static int batch(const char *name)
if (largc == 0)
continue; /* blank line */
- if (do_cmd(largc, largv)) {
+ /*
+ * In batch mode, if we haven't accumulated enough commands
+ * and this is not the last command, don't send the message
+ * immediately.
+ */
+ if (batch_size > 1 && msg_iov_index + 1 != batch_size
+ && cmdlineno != cmdlinetotal)
+ send = false;
+ else
+ send = true;
+
+ ret = do_cmd(largc, largv, batch_size, msg_iov_index++, send);
+ if (ret < 0) {
fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno);
ret = 1;
if (!force)
break;
}
+ msg_iov_index %= batch_size;
}
if (line)
free(line);
+ free_filter_reqs();
+ free_action_reqs();
rtnl_close(&rth);
return ret;
@@ -267,6 +287,7 @@ int main(int argc, char **argv)
{
int ret;
char *batch_file = NULL;
+ int batch_size = 1;
while (argc > 1) {
if (argv[1][0] != '-')
@@ -297,6 +318,14 @@ int main(int argc, char **argv)
if (argc <= 1)
usage();
batch_file = argv[1];
+ } else if (matches(argv[1], "-batchsize") == 0 ||
+ matches(argv[1], "-bs") == 0) {
+ argc--; argv++;
+ if (argc <= 1)
+ usage();
+ batch_size = atoi(argv[1]);
+ if (batch_size > MSG_IOV_MAX)
+ batch_size = MSG_IOV_MAX;
} else if (matches(argv[1], "-netns") == 0) {
NEXT_ARG();
if (netns_switch(argv[1]))
@@ -323,7 +352,7 @@ int main(int argc, char **argv)
}
if (batch_file)
- return batch(batch_file);
+ return batch(batch_file, batch_size);
if (argc <= 1) {
usage();
@@ -341,7 +370,9 @@ int main(int argc, char **argv)
goto Exit;
}
- ret = do_cmd(argc-1, argv+1);
+ ret = do_cmd(argc-1, argv+1, 1, 0, true);
+ free_filter_reqs();
+ free_action_reqs();
Exit:
rtnl_close(&rth);
diff --git a/tc/tc_common.h b/tc/tc_common.h
index 264fbdac..8a82439f 100644
--- a/tc/tc_common.h
+++ b/tc/tc_common.h
@@ -1,13 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define TCA_BUF_MAX (64*1024)
+#define MSG_IOV_MAX 256
extern struct rtnl_handle rth;
extern int do_qdisc(int argc, char **argv);
extern int do_class(int argc, char **argv);
-extern int do_filter(int argc, char **argv);
-extern int do_action(int argc, char **argv);
+extern int do_filter(int argc, char **argv, int batch_size, int index, bool send);
+extern int do_action(int argc, char **argv, int batch_size, int index, bool send);
extern int do_tcmonitor(int argc, char **argv);
extern int do_exec(int argc, char **argv);
@@ -24,5 +25,8 @@ struct tc_sizespec;
extern int parse_size_table(int *p_argc, char ***p_argv, struct tc_sizespec *s);
extern int check_size_table_opts(struct tc_sizespec *s);
+extern void free_filter_reqs(void);
+extern void free_action_reqs(void);
+
extern int show_graph;
extern bool use_names;
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
index 545cc3a1..6fecbb45 100644
--- a/tc/tc_filter.c
+++ b/tc/tc_filter.c
@@ -19,6 +19,7 @@
#include <arpa/inet.h>
#include <string.h>
#include <linux/if_ether.h>
+#include <errno.h>
#include "rt_names.h"
#include "utils.h"
@@ -42,18 +43,44 @@ static void usage(void)
"OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n");
}
-static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
+typedef struct {
+ struct nlmsghdr n;
+ struct tcmsg t;
+ char buf[MAX_MSG];
+} tc_filter_req;
+
+static tc_filter_req *filter_reqs;
+static struct iovec msg_iov[MSG_IOV_MAX];
+
+void free_filter_reqs(void)
{
- struct {
- struct nlmsghdr n;
- struct tcmsg t;
- char buf[MAX_MSG];
- } req = {
- .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
- .n.nlmsg_flags = NLM_F_REQUEST | flags,
- .n.nlmsg_type = cmd,
- .t.tcm_family = AF_UNSPEC,
- };
+ free(filter_reqs);
+}
+
+static tc_filter_req *get_filter_req(int batch_size, int index)
+{
+ tc_filter_req *req;
+
+ if (filter_reqs == NULL) {
+ filter_reqs = malloc(batch_size * sizeof (tc_filter_req));
+ if (filter_reqs == NULL)
+ return NULL;
+ }
+ req = &filter_reqs[index];
+ memset(req, 0, sizeof (*req));
+
+ return req;
+}
+
+static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
+ int batch_size, int index, bool send)
+{
+ tc_filter_req *req;
+ int ret;
+
+ struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
+ struct iovec *iov = &msg_iov[index];
+
struct filter_util *q = NULL;
__u32 prio = 0;
__u32 protocol = 0;
@@ -65,6 +92,24 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
char k[FILTER_NAMESZ] = {};
struct tc_estimator est = {};
+ req = get_filter_req(batch_size, index);
+ if (req == NULL) {
+ fprintf(stderr, "get_filter_req error: not enough buffer\n");
+ return -ENOMEM;
+ }
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST | flags;
+ req->n.nlmsg_type = cmd;
+ req->t.tcm_family = AF_UNSPEC;
+
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = msg_iov,
+ .msg_iovlen = index + 1,
+ };
+
if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
protocol = htons(ETH_P_ALL);
@@ -75,37 +120,37 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
duparg("dev", *argv);
strncpy(d, *argv, sizeof(d)-1);
} else if (strcmp(*argv, "root") == 0) {
- if (req.t.tcm_parent) {
+ if (req->t.tcm_parent) {
fprintf(stderr,
"Error: \"root\" is duplicate parent ID\n");
return -1;
}
- req.t.tcm_parent = TC_H_ROOT;
+ req->t.tcm_parent = TC_H_ROOT;
} else if (strcmp(*argv, "ingress") == 0) {
- if (req.t.tcm_parent) {
+ if (req->t.tcm_parent) {
fprintf(stderr,
"Error: \"ingress\" is duplicate parent ID\n");
return -1;
}
- req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
+ req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
TC_H_MIN_INGRESS);
} else if (strcmp(*argv, "egress") == 0) {
- if (req.t.tcm_parent) {
+ if (req->t.tcm_parent) {
fprintf(stderr,
"Error: \"egress\" is duplicate parent ID\n");
return -1;
}
- req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
+ req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
TC_H_MIN_EGRESS);
} else if (strcmp(*argv, "parent") == 0) {
__u32 handle;
NEXT_ARG();
- if (req.t.tcm_parent)
+ if (req->t.tcm_parent)
duparg("parent", *argv);
if (get_tc_classid(&handle, *argv))
invarg("Invalid parent ID", *argv);
- req.t.tcm_parent = handle;
+ req->t.tcm_parent = handle;
} else if (strcmp(*argv, "handle") == 0) {
NEXT_ARG();
if (fhandle)
@@ -152,26 +197,26 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
argc--; argv++;
}
- req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
+ req->t.tcm_info = TC_H_MAKE(prio<<16, protocol);
if (chain_index_set)
- addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
+ addattr32(&req->n, sizeof(*req), TCA_CHAIN, chain_index);
if (k[0])
- addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
+ addattr_l(&req->n, sizeof(*req), TCA_KIND, k, strlen(k)+1);
if (d[0]) {
ll_init_map(&rth);
- req.t.tcm_ifindex = ll_name_to_index(d);
- if (req.t.tcm_ifindex == 0) {
+ req->t.tcm_ifindex = ll_name_to_index(d);
+ if (req->t.tcm_ifindex == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return 1;
}
}
if (q) {
- if (q->parse_fopt(q, fhandle, argc, argv, &req.n))
+ if (q->parse_fopt(q, fhandle, argc, argv, &req->n))
return 1;
} else {
if (fhandle) {
@@ -190,10 +235,17 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
}
if (est.ewma_log)
- addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
+ addattr_l(&req->n, sizeof(*req), TCA_RATE, &est, sizeof(est));
- if (rtnl_talk(&rth, &req.n, NULL) < 0) {
- fprintf(stderr, "We have an error talking to the kernel\n");
+ iov->iov_base = &req->n;
+ iov->iov_len = req->n.nlmsg_len;
+
+ if (!send)
+ return 0;
+
+ ret = rtnl_talk_msg(&rth, &msg, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "We have an error talking to the kernel, %d\n", ret);
return 2;
}
@@ -636,20 +688,23 @@ static int tc_filter_list(int argc, char **argv)
return 0;
}
-int do_filter(int argc, char **argv)
+int do_filter(int argc, char **argv, int batch_size, int index, bool send)
{
if (argc < 1)
return tc_filter_list(0, NULL);
if (matches(*argv, "add") == 0)
return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE,
- argc-1, argv+1);
+ argc-1, argv+1,
+ batch_size, index, send);
if (matches(*argv, "change") == 0)
- return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1);
+ return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1,
+ batch_size, index, send);
if (matches(*argv, "replace") == 0)
return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1,
- argv+1);
+ argv+1, batch_size, index, send);
if (matches(*argv, "delete") == 0)
- return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1);
+ return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1,
+ batch_size, index, send);
if (matches(*argv, "get") == 0)
return tc_filter_get(RTM_GETTFILTER, 0, argc-1, argv+1);
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
--
2.14.3
^ permalink raw reply related
* [patch iproute2 v3 1/4] lib/libnetlink: Add a function rtnl_talk_msg
From: Chris Mi @ 2017-12-25 8:46 UTC (permalink / raw)
To: netdev; +Cc: gerlitz.or, stephen, dsahern
In-Reply-To: <20171225084658.24076-1-chrism@mellanox.com>
rtnl_talk can only send a single message to kernel. Add a new function
rtnl_talk_msg that can send multiple messages to kernel.
Signed-off-by: Chris Mi <chrism@mellanox.com>
---
include/libnetlink.h | 3 ++
lib/libnetlink.c | 92 ++++++++++++++++++++++++++++++++++++++++------------
2 files changed, 74 insertions(+), 21 deletions(-)
diff --git a/include/libnetlink.h b/include/libnetlink.h
index a4d83b9e..e95fad75 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -96,6 +96,9 @@ int rtnl_dump_filter_nc(struct rtnl_handle *rth,
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer)
__attribute__((warn_unused_result));
+int rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+ struct nlmsghdr **answer)
+ __attribute__((warn_unused_result));
int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer, nl_ext_ack_fn_t errfn)
__attribute__((warn_unused_result));
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 00e6ce0c..f5f675cf 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -581,36 +581,21 @@ static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
strerror(-err->error));
}
-static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
- struct nlmsghdr **answer,
- bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+static int __rtnl_check_ack(struct rtnl_handle *rtnl, struct nlmsghdr **answer,
+ bool show_rtnl_err, nl_ext_ack_fn_t errfn,
+ unsigned int seq)
{
int status;
- unsigned int seq;
- struct nlmsghdr *h;
+ char *buf;
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
- struct iovec iov = {
- .iov_base = n,
- .iov_len = n->nlmsg_len
- };
+ struct nlmsghdr *h;
+ struct iovec iov;
struct msghdr msg = {
.msg_name = &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1,
};
- char *buf;
-
- n->nlmsg_seq = seq = ++rtnl->seq;
-
- if (answer == NULL)
- n->nlmsg_flags |= NLM_F_ACK;
-
- status = sendmsg(rtnl->fd, &msg, 0);
- if (status < 0) {
- perror("Cannot talk to rtnetlink");
- return -1;
- }
while (1) {
status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
@@ -698,12 +683,77 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
}
}
+static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
+ struct nlmsghdr **answer,
+ bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+{
+ unsigned int seq;
+ int status;
+ struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
+ struct iovec iov = {
+ .iov_base = n,
+ .iov_len = n->nlmsg_len
+ };
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ n->nlmsg_seq = seq = ++rtnl->seq;
+
+ if (answer == NULL)
+ n->nlmsg_flags |= NLM_F_ACK;
+
+ status = sendmsg(rtnl->fd, &msg, 0);
+ if (status < 0) {
+ perror("Cannot talk to rtnetlink");
+ return -1;
+ }
+
+ return __rtnl_check_ack(rtnl, answer, show_rtnl_err, errfn, seq);
+}
+
+static int __rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+ struct nlmsghdr **answer,
+ bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+{
+ int iovlen = m->msg_iovlen;
+ unsigned int seq = 0;
+ struct nlmsghdr *n;
+ struct iovec *v;
+ int i, status;
+
+ for (i = 0; i < iovlen; i++) {
+ v = &m->msg_iov[i];
+ n = v->iov_base;
+ n->nlmsg_seq = seq = ++rtnl->seq;
+ if (answer == NULL)
+ n->nlmsg_flags |= NLM_F_ACK;
+ }
+
+ status = sendmsg(rtnl->fd, m, 0);
+ if (status < 0) {
+ perror("Cannot talk to rtnetlink");
+ return -1;
+ }
+
+ return __rtnl_check_ack(rtnl, answer, show_rtnl_err, errfn, seq);
+}
+
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer)
{
return __rtnl_talk(rtnl, n, answer, true, NULL);
}
+int rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+ struct nlmsghdr **answer)
+{
+ return __rtnl_talk_msg(rtnl, m, answer, true, NULL);
+}
+
int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
struct nlmsghdr **answer,
nl_ext_ack_fn_t errfn)
--
2.14.3
^ permalink raw reply related
* [patch iproute2 v3 2/4] utils: Add a function setcmdlinetotal
From: Chris Mi @ 2017-12-25 8:46 UTC (permalink / raw)
To: netdev; +Cc: gerlitz.or, stephen, dsahern
In-Reply-To: <20171225084658.24076-1-chrism@mellanox.com>
This function calculates how many commands a batch file has and
set it to global variable cmdlinetotal.
Signed-off-by: Chris Mi <chrism@mellanox.com>
---
include/utils.h | 4 ++++
lib/utils.c | 20 ++++++++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/include/utils.h b/include/utils.h
index d3895d56..113a8c31 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -235,6 +235,10 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
extern int cmdlineno;
ssize_t getcmdline(char **line, size_t *len, FILE *in);
+
+extern int cmdlinetotal;
+void setcmdlinetotal(const char *name);
+
int makeargs(char *line, char *argv[], int maxargs);
int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6);
diff --git a/lib/utils.c b/lib/utils.c
index 7ced8c06..53ca389f 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1202,6 +1202,26 @@ ssize_t getcmdline(char **linep, size_t *lenp, FILE *in)
return cc;
}
+int cmdlinetotal;
+
+void setcmdlinetotal(const char *name)
+{
+ char *line = NULL;
+ size_t len = 0;
+
+ if (name && strcmp(name, "-") != 0) {
+ if (freopen(name, "r", stdin) == NULL) {
+ fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n",
+ name, strerror(errno));
+ return;
+ }
+ }
+
+ cmdlinetotal = 0;
+ while (getcmdline(&line, &len, stdin) != -1)
+ cmdlinetotal++;
+}
+
/* split command line into argument vector */
int makeargs(char *line, char *argv[], int maxargs)
{
--
2.14.3
^ permalink raw reply related
* [patch iproute2 v3 4/4] man: Add -bs option to tc manpage
From: Chris Mi @ 2017-12-25 8:46 UTC (permalink / raw)
To: netdev; +Cc: gerlitz.or, stephen, dsahern
In-Reply-To: <20171225084658.24076-1-chrism@mellanox.com>
Signed-off-by: Chris Mi <chrism@mellanox.com>
---
man/man8/tc.8 | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/man/man8/tc.8 b/man/man8/tc.8
index ff071b33..de137e16 100644
--- a/man/man8/tc.8
+++ b/man/man8/tc.8
@@ -601,6 +601,11 @@ must exist already.
read commands from provided file or standard input and invoke them.
First failure will cause termination of tc.
+.TP
+.BR "\-bs", " \-bs size", " \-batchsize", " \-batchsize size"
+How many commands are accumulated before sending to kernel.
+By default, it is 1. It only takes effect in batch mode.
+
.TP
.BR "\-force"
don't terminate tc on errors in batch mode.
--
2.14.3
^ permalink raw reply related
* [patch net-next 1/2] net_sch: red: Fix the new offload indication
From: Nogah Frankel @ 2017-12-25 8:51 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, xiyou.wangcong, jiri, mlxsw, Nogah Frankel
In-Reply-To: <1514191902-53752-1-git-send-email-nogahf@mellanox.com>
Update the offload flag, TCQ_F_OFFLOADED, in each dump call (and ignore
the offloading function return value in relation to this flag).
This is done because a qdisc is being initialized, and therefore offloaded
before being grafted. Since the ability of the driver to offload the qdisc
depends on its location, a qdisc can be offloaded and un-offloaded by graft
calls, that doesn't effect the qdisc itself.
Fixes: 428a68af3a7c ("net: sched: Move to new offload indication in RED"
Signed-off-by: Nogah Frankel <nogahf@mellanox.com>
Reviewed-by: Yuval Mintz <yuvalm@mellanox.com>
---
net/sched/sch_red.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index ec0bd36..a392eaa 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -157,7 +157,6 @@ static int red_offload(struct Qdisc *sch, bool enable)
.handle = sch->handle,
.parent = sch->parent,
};
- int err;
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return -EOPNOTSUPP;
@@ -172,14 +171,7 @@ static int red_offload(struct Qdisc *sch, bool enable)
opt.command = TC_RED_DESTROY;
}
- err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, &opt);
-
- if (!err && enable)
- sch->flags |= TCQ_F_OFFLOADED;
- else
- sch->flags &= ~TCQ_F_OFFLOADED;
-
- return err;
+ return dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, &opt);
}
static void red_destroy(struct Qdisc *sch)
@@ -297,12 +289,22 @@ static int red_dump_offload_stats(struct Qdisc *sch, struct tc_red_qopt *opt)
.stats.qstats = &sch->qstats,
},
};
+ int err;
+
+ sch->flags &= ~TCQ_F_OFFLOADED;
- if (!(sch->flags & TCQ_F_OFFLOADED))
+ if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
+ return 0;
+
+ err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED,
+ &hw_stats);
+ if (err == -EOPNOTSUPP)
return 0;
- return dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED,
- &hw_stats);
+ if (!err)
+ sch->flags |= TCQ_F_OFFLOADED;
+
+ return err;
}
static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
--
2.4.3
^ permalink raw reply related
* [patch net-next 2/2] net: sched: Move offload check till after dump call
From: Nogah Frankel @ 2017-12-25 8:51 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, xiyou.wangcong, jiri, mlxsw, Nogah Frankel
In-Reply-To: <1514191902-53752-1-git-send-email-nogahf@mellanox.com>
Move the check of the offload state to after the qdisc dump action was
called, so the qdisc could update it if it was changed.
Fixes: 7a4fa29106d9 ("net: sched: Add TCA_HW_OFFLOAD")
Signed-off-by: Nogah Frankel <nogahf@mellanox.com>
Reviewed-by: Yuval Mintz <yuvalm@mellanox.com>
---
net/sched/sch_api.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 3a3a1da..758f132 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -807,11 +807,10 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
tcm->tcm_info = refcount_read(&q->refcnt);
if (nla_put_string(skb, TCA_KIND, q->ops->id))
goto nla_put_failure;
- if (nla_put_u8(skb, TCA_HW_OFFLOAD, !!(q->flags & TCQ_F_OFFLOADED)))
- goto nla_put_failure;
if (q->ops->dump && q->ops->dump(q, skb) < 0)
goto nla_put_failure;
-
+ if (nla_put_u8(skb, TCA_HW_OFFLOAD, !!(q->flags & TCQ_F_OFFLOADED)))
+ goto nla_put_failure;
qlen = qdisc_qlen_sum(q);
stab = rtnl_dereference(q->stab);
--
2.4.3
^ permalink raw reply related
* [patch net-next 0/2] net: sched: Fix RED qdisc offload flag
From: Nogah Frankel @ 2017-12-25 8:51 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, xiyou.wangcong, jiri, mlxsw, Nogah Frankel
Replacing the RED offload flag (TC_RED_OFFLOADED) with the generic one
(TCQ_F_OFFLOADED) deleted some of the logic behind it. This patchset fixes
this problem.
Nogah Frankel (2):
net_sch: red: Fix the new offload indication
net: sched: Move offload check till after dump call
net/sched/sch_api.c | 5 ++---
net/sched/sch_red.c | 26 ++++++++++++++------------
2 files changed, 16 insertions(+), 15 deletions(-)
--
2.4.3
^ permalink raw reply
* Re: [QUESTION] Doubt about NAPI_GRO_CB(skb)->is_atomic in tcpv4 gro process
From: Yunsheng Lin @ 2017-12-25 9:32 UTC (permalink / raw)
To: Alexander Duyck
Cc: netdev@vger.kernel.org, davem@davemloft.net, linuxarm@huawei.com,
yuxiaowu, wzhen.wang, Xuehuahu
In-Reply-To: <CAKgT0Uczi6icYfQnuYYzA3_keXVTjJ2GEKfBabPbwFtcd=nddg@mail.gmail.com>
Hi, Alexander
On 2017/12/23 0:32, Alexander Duyck wrote:
> On Fri, Dec 22, 2017 at 12:49 AM, Yunsheng Lin <linyunsheng@huawei.com> wrote:
>> Hi, Alexander
>>
>> On 2017/12/22 0:29, Alexander Duyck wrote:
>>> On Thu, Dec 21, 2017 at 1:16 AM, Yunsheng Lin <linyunsheng@huawei.com> wrote:
>>>> Hi, Alexander
>>>>
>>>> On 2017/12/21 0:24, Alexander Duyck wrote:
>>>>> On Wed, Dec 20, 2017 at 1:09 AM, Yunsheng Lin <linyunsheng@huawei.com> wrote:
>>>>>> Hi, all
>>>>>> I have some doubt about NAPI_GRO_CB(skb)->is_atomic when
>>>>>> analyzing the tcpv4 gro process:
>>>>>>
>>>>>> Firstly we set NAPI_GRO_CB(skb)->is_atomic to 1 in dev_gro_receive:
>>>>>> https://elixir.free-electrons.com/linux/v4.15-rc4/source/net/core/dev.c#L4838
>>>>>>
>>>>>> And then in inet_gro_receive, we check the NAPI_GRO_CB(skb)->is_atomic
>>>>>> before setting NAPI_GRO_CB(skb)->is_atomic according to IP_DF bit in the ip header:
>>>>>> https://elixir.free-electrons.com/linux/v4.15-rc4/source/net/ipv4/af_inet.c#L1319
>>>>>>
>>>>>> struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff *skb)
>>>>>> {
>>>>>> .....................
>>>>>> for (p = *head; p; p = p->next) {
>>>>>> ........................
>>>>>>
>>>>>> /* If the previous IP ID value was based on an atomic
>>>>>> * datagram we can overwrite the value and ignore it.
>>>>>> */
>>>>>> if (NAPI_GRO_CB(skb)->is_atomic) //we check it here
>>>>>> NAPI_GRO_CB(p)->flush_id = flush_id;
>>>>>> else
>>>>>> NAPI_GRO_CB(p)->flush_id |= flush_id;
>>>>>> }
>>>>>>
>>>>>> NAPI_GRO_CB(skb)->is_atomic = !!(iph->frag_off & htons(IP_DF)); //we set it here
>>>>>> NAPI_GRO_CB(skb)->flush |= flush;
>>>>>> skb_set_network_header(skb, off);
>>>>>> ................................
>>>>>> }
>>>>>>
>>>>>> My question is whether we should check the NAPI_GRO_CB(skb)->is_atomic or NAPI_GRO_CB(p)->is_atomic?
>>>>>> If we should check NAPI_GRO_CB(skb)->is_atomic, then maybe it is unnecessary because it is alway true.
>>>>>> If we should check NAPI_GRO_CB(p)->is_atomic, maybe there is a bug here.
>>>>>>
>>>>>> So what is the logic here? I am just start analyzing the gro, maybe I miss something obvious here.
>>>>>
>>>>> The logic there is to address the multiple IP header case where there
>>>>> are 2 or more IP headers due to things like VXLAN or GRE tunnels. So
>>>>> what will happen is that an outer IP header will end up being sent
>>>>> with DF not set and will clear the is_atomic value then we want to OR
>>>>> in the next header that is applied. It defaults to assignment on
>>>>> is_atomic because the first IP header will encounter flush_id with no
>>>>> previous configuration occupying it.
>>>>
>>>> I see your point now.
>>>>
>>>> But for the same flow of tunnels packet, the outer and inner ip header must
>>>> have the same fixed id or increment id?
>>>>
>>>> For example, if we have a flow of tunnels packet which has fixed id in outer
>>>> header and increment id in inner header(the inner header does have DF flag set):
>>
>> Sorry, a typo error here. I meant the inner header does *not* have DF flag set here.
>>
>>>>
>>>> 1. For the first packet, NAPI_GRO_CB(skb)->is_atomic will be set to zero when
>>>> inet_gro_receive is processing the inner ip header.
>>>>
>>>> 2. For the second packet, when inet_gro_receive is processing the outer ip header
>>>> which has a fixed id, NAPI_GRO_CB(p)->is_atomic is zero according to [1], so
>>>> NAPI_GRO_CB(p)->flush_id will be set to 0xFFFF, then the second packet will not
>>>> be merged to first packet in tcp_gro_receive.
>>>
>>> I'm not sure how valid your case here is. The is_atomic is only really
>>> meant to apply to the inner-most header.
>>
>> For the new skb, NAPI_GRO_CB(skb)->is_atomic is indeed applied to the
>> inner-most header.
>>
>> What about the NAPI_GRO_CB(p)->is_atomic, p is the same skb flow already
>> merged by gro.
>>
>> Let me try if I understand it correctly:
>> when there is only one skb merged in p, then NAPI_GRO_CB(p)->is_atomic
>> is set according to the first skb' inner-most ip DF flags.
>>
>> When the second skb comes, and inet_gro_receive is processing the
>> outer-most ip, for the below code, NAPI_GRO_CB(p)->is_atomic
>> is for first skb's inner-most ip DF flags, and "iph->frag_off & htons(IP_DF)"
>> is for second skb' outer-most ip DF flags.
>> Why don't we use the first skb's outer-most ip DF flags here? I think it is
>> more logical to use first skb's outer-most ip DF flags here. But the first
>> skb's outer-most ip DF flags is lost when we get here, right?
>>
>> if (!NAPI_GRO_CB(p)->is_atomic ||
>> !(iph->frag_off & htons(IP_DF))) {
>> flush_id ^= NAPI_GRO_CB(p)->count;
>> flush_id = flush_id ? 0xFFFF : 0;
>> }
>
> We already did in a way. If you look earlier up we will set flush if
> the DF bit of this packet and the next don't match. So if the DF bit
> changes we are flushing anyway.
Hmm, sorry for missing that.
What puzzle me most is the differentiation between NAPI_GRO_CB(p)->is_atomic
and NAPI_GRO_CB(skb)->is_atomic. So I spent some time on reading the code
related to them. Here is what I found:
Suppose there are only two ip headers and focus on the DF flag and ID field
in ip header(assume other conditions are meet). Because when the same flow
of second skb is being processed, the NAPI_GRO_CB(p)->is_atomic set to 0 or 1
accoding to the first skb' inner-most ip DF flag, So I analyze it based on
the first skb' inner-most ip DF flag.
When the first skb' inner-most ip DF flag is not set, then
NAPI_GRO_CB(p)->is_atomic is always zero. When the skb's DF flags and ID field
meet the follow condition, it will be merged:
outer-DF outer-ID inner-DF inner-ID
1 any 0 increment
0 increment 0 increment
When the first skb' inner-most ip DF flag is set, NAPI_GRO_CB(p)->is_atomic is 1
at first and will be changed accordingly when processing the second skb.
When the skb's DF flags and ID field meet the follow condition, it will be merged
and NAPI_GRO_CB(p)->is_atomic is changed accordingly:
outer-DF outer-ID inner-DF inner-ID
1 any 1 fixed
1 any 1 increment [NAPI_GRO_CB(p)->is_atomic changes to zero]
0 increment 1 increment [NAPI_GRO_CB(p)->is_atomic changes to zero]
0 increment 1 fixed
Is my above analysis correct? I have tried my best to understand it. :)
According to the analysis above, If the DF flags in outer-most ip header is set,
then ID can be any value. But not the same as the ID in the inner-most ip header,
it can only be fixed or increment. According to rcf6864 originating sources MAY
set the IPv4 ID field of atomic datagrams to any value if DF is set.
I wonder what is the different here?
Also I wonder if gro support more than two ip header now.
Refer:
https://tools.ietf.org/html/rfc6864#section-4.1
>
>>
>>
>> In the case of TCP the
>>> inner-most header should almost always have the DF bit set which means
>>> the inner-most is almost always atomic.
>>>
>>>> I thought outer ip header could have a fixed id while inner ip header could
>>>> have a increment id. Do I miss something here?
>>>
>>> You have it backwards. The innermost will have DF bit set so it can be
>>> fixed, the outer-most will in many cases not since it is usually UDP
>>> and as such it will likely need to increment.
>>
>> Actually I got it backwards because that is what intel do when TSOing.
>>
>> Below is quoted from 710 datasheet in page 1052:
>> The Identification field (in the IP header in non tunneled packets or the inner IP header in
>> tunneled packets) is taken from the TSO header in the first segment and then it is increased by
>> one for each transmitted segment.
>> The Identification field (in the external IP header) is taken from the TSO header in the first
>> segment and then it is either increased by one for each transmitted segment or remains
>> constant depending on the EIP_NOINC setting in the transmit context descriptor.
>>
>> If I understand it correctly, intel is doing oppositely as pointed out by you.
>> Am I miss something here?
>>
>> Refer:
>> https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xl710-10-40-controller-datasheet.pdf
>
> The only form of IP ID mangling supported by i40e is to increment
> everything always for outer and inner header. This code was meant more
> to handle the setup generated by igb or ixgbe when we are doing
> GSO_PARTIAL. We don't support fixed outer IDs in that driver if I
> recall correctly. The hardware might support it but the stack doesn't.
> Basically if DF is not set then we must increment and if DF is set we
> could either increment or be fixed and we would be within spec for how
> IP IDs are supposed to be handled.>
>>>
>>>>>
>>>>> The part I am not sure about is if we should be using assignment for
>>>>> is_atomic or using an "&=" to clear the bit and leave it cleared.
>>>>
>>>> I am not sure I understood you here. is_atomic is a bit field, why do you
>>>> want to use "&="?
>>>
>>> Actually that was my mind kind of wandering. It has been a while since
>>> I looked at this code and the use of &= wouldn't be appropriate since
>>> is_atomic should only apply to the innermost header.
>>>
>>> Basically the only acceptable combinations for is_atomic and flush_id
>>> are false with 0, or true with 1. We can't have a fixed outer header
>>> value if DF is not set.
>>>
>>> Hope that helps to clarify things.
>>
>> Yes, Your reqly has helped a lot. But I still have some doubt above,
>> please help me understand it.
>> I hope this does not take much of your time.
>> Thanks very much.
>>
>> Yunsheng Lin
>>
>
> You are free to doubt, but I suggest you actually walk through the
> protocol and thoroughly read the code. Arguing hypothetical bugs is
> rather tedious when I can easily point out the flaws and why something
> isn't a bug.
I will try my best to do as you suggested.
Thanks very much for your time.
Best Regards
Yunsheng Lin
>
> - Alex
>
> .
>
^ permalink raw reply
* Re: [patch net-next v4 00/10] net: sched: allow qdiscs to share filter block instances
From: Jiri Pirko @ 2017-12-25 10:23 UTC (permalink / raw)
To: David Ahern
Cc: netdev, davem, jhs, xiyou.wangcong, mlxsw, andrew, vivien.didelot,
f.fainelli, michael.chan, ganeshgr, saeedm, matanb, leonro,
idosch, jakub.kicinski, simon.horman, pieter.jansenvanvuuren,
john.hurley, alexander.h.duyck, ogerlitz, john.fastabend, daniel
In-Reply-To: <780a80d0-9384-ae34-4cab-3070b004b64e@gmail.com>
Sun, Dec 24, 2017 at 05:25:41PM CET, dsahern@gmail.com wrote:
>On 12/24/17 1:19 AM, Jiri Pirko wrote:
>> Sun, Dec 24, 2017 at 02:54:47AM CET, dsahern@gmail.com wrote:
>>> On 12/23/17 9:54 AM, Jiri Pirko wrote:
>>>> So back to the example. First, we create 2 qdiscs. Both will share
>>>> block number 22. "22" is just an identification. If we don't pass any
>>>> block number, a new one will be generated by kernel:
>>>>
>>>> $ tc qdisc add dev ens7 ingress block 22
>>>> ^^^^^^^^
>>>> $ tc qdisc add dev ens8 ingress block 22
>>>> ^^^^^^^^
>>>>
>>>> Now if we list the qdiscs, we will see the block index in the output:
>>>>
>>>> $ tc qdisc
>>>> qdisc ingress ffff: dev ens7 parent ffff:fff1 block 22
>>>> qdisc ingress ffff: dev ens8 parent ffff:fff1 block 22
>>>>
>>>> To make is more visual, the situation looks like this:
>>>>
>>>> ens7 ingress qdisc ens7 ingress qdisc
>>>> | |
>>>> | |
>>>> +----------> block 22 <----------+
>>>>
>>>> Unlimited number of qdiscs may share the same block.
>>>>
>>>> Now we can add filter to any of qdiscs sharing the same block:
>>>>
>>>> $ tc filter add dev ens7 ingress protocol ip pref 25 flower dst_ip 192.168.0.0/16 action drop
>>>
>>>
>>> Allowing config of a shared block through any qdisc that references it
>>> is akin to me allowing nexthop objects to be manipulated by any route
>>> that references it -- sure, it could be done but causes a lot surprises
>>> to the user.
>>>
>>> You are adding a new tc object -- a shared block. Why the resistance to
>>> creating a proper API for managing it?
>>
>> Again, no resistance, I said many times it would be done as a follow-up.
>> But as an api already exists, it has to continue to work. Or do you
>> suggest it should stop working? That, I don't agree with.
>>
>
>That is exactly what I am saying - principle of least surprise. The new
>object brings its own API and can only be modified using the new API.
>The scheme above can and will surprise users. You are thinking like a tc
>developer, someone intimately familiar with the code, and not like an
>ordinary user of this new feature.
Breaking exising tools is newer good. Note that not only about filter
add/del iface but also dump and notifications. I agree to extend the api
for the "block handle", sure, but the existing api should continue to
work.
^ permalink raw reply
* Re: [patch net-next 02/10] devlink: Add support for resource abstraction
From: Arkadi Sharshevsky @ 2017-12-25 11:12 UTC (permalink / raw)
To: David Miller, jiri
Cc: netdev, mlxsw, andrew, vivien.didelot, f.fainelli, michael.chan,
ganeshgr, saeedm, matanb, leonro, idosch, jakub.kicinski, ast,
daniel, simon.horman, pieter.jansenvanvuuren, john.hurley,
alexander.h.duyck, linville, gospo, steven.lin1, yuvalm, ogerlitz,
dsa, roopa
In-Reply-To: <20171220.144358.1892414104907740492.davem@davemloft.net>
On 12/20/2017 09:43 PM, David Miller wrote:
> From: Jiri Pirko <jiri@resnulli.us>
> Date: Wed, 20 Dec 2017 12:58:13 +0100
>
>> From: Arkadi Sharshevsky <arkadis@mellanox.com>
>>
>> Add support for hardware resource abstraction over devlink. Each resource
>> is identified via id, furthermore it contains information regarding its
>> size and its related sub resources. Each resource can also provide its
>> current occupancy.
>>
>> In some cases the sizes of some resources can be changed, yet for those
>> changes to take place a hot driver reload may be needed. The reload
>> capability will be introduced in the next patch.
>>
>> Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com>
>> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
>
> In what units are these sizes? If it depends upon the resource, it would
> be great to have a way to introspect the units given a resource.
>
This is problematic. Currently the units are actually double words
(single entry is 64 bit) because this resource is a actually a memory.
So my first thought was adding an enum in UAPI of resource_units
enum resource_units {
DEVLINK_RESOURCE_UNITS_WORD,
DEVLINK_RESOURCE_UNITS_DOUBLE_WORD,
DEVLINK_RESOURCE_UNITS_ITEM, /* this is in order to define some
driver specific stuff*/
...
};
But the 'item' is too vague, because for example, we will have the
RIF bank as resource. What unit will it have? rifs? items?
Any inputs on this?
>> + struct devlink_resource_ops *resource_ops;
>
> Const?
>
>> +static inline int
>> +devlink_resource_register(struct devlink *devlink,
>> + const char *resource_name,
>> + bool top_hierarchy,
>> + u64 resource_size,
>> + u64 resource_id,
>> + u64 parent_resource_id,
>> + struct devlink_resource_ops *resource_ops)
>
> Const for resource_ops?
>
>> +int devlink_resource_register(struct devlink *devlink,
>> + const char *resource_name,
>> + bool top_hierarchy,
>> + u64 resource_size,
>> + u64 resource_id,
>> + u64 parent_resource_id,
>> + struct devlink_resource_ops *resource_ops)
>
> Likewise.
>
^ permalink raw reply
* Re: [PATCH] flex_can: Fix checking can_dlc
From: Oliver Hartkopp @ 2017-12-25 11:38 UTC (permalink / raw)
To: Luu An Phu, wg, mkl; +Cc: linux-can, netdev, stefan-gabriel.mirea
In-Reply-To: <1513672833-28402-1-git-send-email-phu.luuan@nxp.com>
This patch looks wrong to me.
On 12/19/2017 09:40 AM, Luu An Phu wrote:
> From: "phu.luuan" <phu.luuan@nxp.com>
>
> flexcan_start_xmit should write data to register when can_dlc > 4.
> Because can_dlc is data length and it has value from 1 to 8.
No. can_dlc can contain values from 0 to 8. Even 0 is a valid DLC.
> But CAN data
> index has value from 0 to 7. So in case we have data in cf->data[4],
> the can_dlc has value is more than 4.
>
> Signed-off-by: Luu An Phu <phu.luuan@nxp.com>
> ---
> drivers/net/can/flexcan.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
> index 0626dcf..0e3ff13 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -5,6 +5,7 @@
> * Copyright (c) 2009 Sascha Hauer, Pengutronix
> * Copyright (c) 2010-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
> * Copyright (c) 2014 David Jander, Protonic Holland
> + * Copyright 2017 NXP
> *
> * Based on code originally by Andrey Volkov <avolkov@varma-el.com>
> *
> @@ -526,7 +527,7 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
> data = be32_to_cpup((__be32 *)&cf->data[0]);
> flexcan_write(data, &priv->tx_mb->data[0]);
> }
> - if (cf->can_dlc > 3) {
This is correct as data[0 .. 3] are filled from the code above. And if
can_dlc is greater than 3 (== 4 .. 8) the following 4 bytes are copied
into the registers.
So everything is correct with the current code.
> + if (cf->can_dlc > 4) {
> data = be32_to_cpup((__be32 *)&cf->data[4]);
> flexcan_write(data, &priv->tx_mb->data[1]);
> }
>
Regards,
Oliver
^ permalink raw reply
* Re: [PATCH net-next] virtio_net: Add ethtool stats
From: Toshiaki Makita @ 2017-12-25 11:45 UTC (permalink / raw)
To: Stephen Hemminger
Cc: netdev, virtualization, David S . Miller, Michael S . Tsirkin
In-Reply-To: <20171224101640.4b14002f@xeon-e3>
On 2017/12/25 3:16, Stephen Hemminger wrote:
> On Wed, 20 Dec 2017 13:40:37 +0900
> Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> wrote:
>
>> +
>> +static const struct virtnet_gstats virtnet_gstrings_stats[] = {
>> + { "rx_packets", VIRTNET_NETDEV_STAT(rx_packets) },
>> + { "tx_packets", VIRTNET_NETDEV_STAT(tx_packets) },
>> + { "rx_bytes", VIRTNET_NETDEV_STAT(rx_bytes) },
>> + { "tx_bytes", VIRTNET_NETDEV_STAT(tx_bytes) },
>> + { "rx_dropped", VIRTNET_NETDEV_STAT(rx_dropped) },
>> + { "rx_length_errors", VIRTNET_NETDEV_STAT(rx_length_errors) },
>> + { "rx_frame_errors", VIRTNET_NETDEV_STAT(rx_frame_errors) },
>> + { "tx_dropped", VIRTNET_NETDEV_STAT(tx_dropped) },
>> + { "tx_fifo_errors", VIRTNET_NETDEV_STAT(tx_fifo_errors) },
>> +};
>> +
>
> Please do not merge pre-existing global stats into ethtool.
> It just duplicates existing functionality.
Thanks for the feedback.
I thought it's handy to be able to check stats like this in ethtool as
well. Some drivers like ixgbe and mlx5 do similar thing.
I can remove these duplicate stats (unless anyone has objection).
--
Toshiaki Makita
^ permalink raw reply
* [RFC PATCH v11 0/5] PCI: rockchip: Move PCIe WAKE# handling into pci core
From: Jeffy Chen @ 2017-12-25 11:47 UTC (permalink / raw)
To: linux-kernel, bhelgaas
Cc: Mark Rutland, linux-wireless, Heiko Stuebner, tony, linux-pci,
shawn.lin, Will Deacon, Amitkumar Karwar, Frank Rowand,
briannorris, linux-rockchip, Matthias Kaehlcke, linux-arm-kernel,
Catalin Marinas, Caesar Wang, devicetree, Xinming Hu, linux-pm,
Jeffy Chen, Nishant Sarmukadam, Rob Herring, Kalle Valo,
Ganapathi Bhat, netdev, rjw, dianders, Enric Balletbo i Serra
Currently we are handling wake irq in mrvl wifi driver. Move it into
pci core.
Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).
Changes in v11:
Only add irq definitions for PCI devices and rewrite the commit message.
Address Brian's comments.
Only support 1-per-device PCIe WAKE# pin as suggested.
Move to pcie port as Brian suggested.
Changes in v10:
Use device_set_wakeup_capable() instead of device_set_wakeup_enable(),
since dedicated wakeirq will be lost in device_set_wakeup_enable(false).
Changes in v9:
Add section for PCI devices and rewrite the commit message.
Fix check error in .cleanup().
Move dedicated wakeirq setup to setup() callback and use
device_set_wakeup_enable() to enable/disable.
Rewrite the commit message.
Changes in v8:
Add optional "pci", and rewrite commit message.
Add pci-of.c and use platform_pm_ops to handle the PCIe WAKE# signal.
Rewrite the commit message.
Changes in v7:
Move PCIE_WAKE handling into pci core.
Changes in v6:
Fix device_init_wake error handling, and add some comments.
Changes in v5:
Move to pci.txt
Rebase.
Use "wakeup" instead of "wake"
Changes in v3:
Fix error handling.
Changes in v2:
Use dev_pm_set_dedicated_wake_irq.
Jeffy Chen (5):
dt-bindings: PCI: Add definition of PCIe WAKE# irq and PCI irq
of/irq: Adjust of_pci_irq parsing for multiple interrupts
mwifiex: Disable wakeup irq handling for pcie
PCI / PM: Add support for the PCIe WAKE# signal for OF
arm64: dts: rockchip: Move PCIe WAKE# irq to pcie port for Gru
Documentation/devicetree/bindings/pci/pci.txt | 10 ++++
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 11 +++--
drivers/net/wireless/marvell/mwifiex/main.c | 4 ++
drivers/of/of_pci_irq.c | 71 +++++++++++++++++++++++++--
drivers/pci/pci-driver.c | 10 ++++
include/linux/of_pci.h | 9 ++++
6 files changed, 107 insertions(+), 8 deletions(-)
--
2.11.0
^ permalink raw reply
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