* [patch net-next v4 10/11] act_police: improved accuracy at high rates
From: Jiri Pirko @ 2013-02-10 10:52 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, jhs, kuznet, j.vimal
In-Reply-To: <1360493539-14868-1-git-send-email-jiri@resnulli.us>
Current act_police uses rate table computed by the "tc" userspace program,
which has the following issue:
The rate table has 256 entries to map packet lengths to
token (time units). With TSO sized packets, the 256 entry granularity
leads to loss/gain of rate, making the token bucket inaccurate.
Thus, instead of relying on rate table, this patch explicitly computes
the time and accounts for packet transmission times with nanosecond
granularity.
This is a followup to 56b765b79e9a78dc7d3f8850ba5e5567205a3ecd
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
net/sched/act_police.c | 95 +++++++++++++++++++++++++++-----------------------
1 file changed, 51 insertions(+), 44 deletions(-)
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 378a649..71bf4f5 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -26,20 +26,20 @@ struct tcf_police {
struct tcf_common common;
int tcfp_result;
u32 tcfp_ewma_rate;
- u32 tcfp_burst;
+ s64 tcfp_burst;
u32 tcfp_mtu;
- u32 tcfp_toks;
- u32 tcfp_ptoks;
+ s64 tcfp_toks;
+ s64 tcfp_ptoks;
+ s64 tcfp_mtu_ptoks;
psched_time_t tcfp_t_c;
- struct qdisc_rate_table *tcfp_R_tab;
- struct qdisc_rate_table *tcfp_P_tab;
+ struct psched_ratecfg rate;
+ bool rate_present;
+ struct psched_ratecfg peak;
+ bool peak_present;
};
#define to_police(pc) \
container_of(pc, struct tcf_police, common)
-#define L2T(p, L) qdisc_l2t((p)->tcfp_R_tab, L)
-#define L2T_P(p, L) qdisc_l2t((p)->tcfp_P_tab, L)
-
#define POL_TAB_MASK 15
static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1];
static u32 police_idx_gen;
@@ -123,10 +123,6 @@ static void tcf_police_destroy(struct tcf_police *p)
write_unlock_bh(&police_lock);
gen_kill_estimator(&p->tcf_bstats,
&p->tcf_rate_est);
- if (p->tcfp_R_tab)
- qdisc_put_rtab(p->tcfp_R_tab);
- if (p->tcfp_P_tab)
- qdisc_put_rtab(p->tcfp_P_tab);
/*
* gen_estimator est_timer() might access p->tcf_lock
* or bstats, wait a RCU grace period before freeing p
@@ -227,26 +223,36 @@ override:
}
/* No failure allowed after this point */
- if (R_tab != NULL) {
- qdisc_put_rtab(police->tcfp_R_tab);
- police->tcfp_R_tab = R_tab;
+ police->tcfp_mtu = parm->mtu;
+ if (police->tcfp_mtu == 0) {
+ police->tcfp_mtu = ~0;
+ if (R_tab)
+ police->tcfp_mtu = 255 << R_tab->rate.cell_log;
+ }
+ if (R_tab) {
+ police->rate_present = true;
+ psched_ratecfg_precompute(&police->rate, R_tab->rate.rate);
+ qdisc_put_rtab(R_tab);
+ } else {
+ police->rate_present = false;
}
- if (P_tab != NULL) {
- qdisc_put_rtab(police->tcfp_P_tab);
- police->tcfp_P_tab = P_tab;
+ if (P_tab) {
+ police->peak_present = true;
+ psched_ratecfg_precompute(&police->peak, P_tab->rate.rate);
+ qdisc_put_rtab(P_tab);
+ } else {
+ police->peak_present = false;
}
if (tb[TCA_POLICE_RESULT])
police->tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]);
- police->tcfp_toks = police->tcfp_burst = parm->burst;
- police->tcfp_mtu = parm->mtu;
- if (police->tcfp_mtu == 0) {
- police->tcfp_mtu = ~0;
- if (police->tcfp_R_tab)
- police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
+ police->tcfp_burst = PSCHED_TICKS2NS(parm->burst);
+ police->tcfp_toks = police->tcfp_burst;
+ if (police->peak_present) {
+ police->tcfp_mtu_ptoks = (s64) psched_l2t_ns(&police->peak,
+ police->tcfp_mtu);
+ police->tcfp_ptoks = police->tcfp_mtu_ptoks;
}
- if (police->tcfp_P_tab)
- police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
police->tcf_action = parm->action;
if (tb[TCA_POLICE_AVRATE])
@@ -256,7 +262,7 @@ override:
if (ret != ACT_P_CREATED)
return ret;
- police->tcfp_t_c = psched_get_time();
+ police->tcfp_t_c = ktime_to_ns(ktime_get());
police->tcf_index = parm->index ? parm->index :
tcf_hash_new_index(&police_idx_gen, &police_hash_info);
h = tcf_hash(police->tcf_index, POL_TAB_MASK);
@@ -303,8 +309,8 @@ static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a,
{
struct tcf_police *police = a->priv;
psched_time_t now;
- long toks;
- long ptoks = 0;
+ s64 toks;
+ s64 ptoks = 0;
spin_lock(&police->tcf_lock);
@@ -320,24 +326,25 @@ static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a,
}
if (qdisc_pkt_len(skb) <= police->tcfp_mtu) {
- if (police->tcfp_R_tab == NULL) {
+ if (!police->rate_present) {
spin_unlock(&police->tcf_lock);
return police->tcfp_result;
}
- now = psched_get_time();
- toks = psched_tdiff_bounded(now, police->tcfp_t_c,
- police->tcfp_burst);
- if (police->tcfp_P_tab) {
+ now = ktime_to_ns(ktime_get());
+ toks = min_t(s64, now - police->tcfp_t_c,
+ police->tcfp_burst);
+ if (police->peak_present) {
ptoks = toks + police->tcfp_ptoks;
- if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
- ptoks = (long)L2T_P(police, police->tcfp_mtu);
- ptoks -= L2T_P(police, qdisc_pkt_len(skb));
+ if (ptoks > police->tcfp_mtu_ptoks)
+ ptoks = police->tcfp_mtu_ptoks;
+ ptoks -= (s64) psched_l2t_ns(&police->peak,
+ qdisc_pkt_len(skb));
}
toks += police->tcfp_toks;
- if (toks > (long)police->tcfp_burst)
+ if (toks > police->tcfp_burst)
toks = police->tcfp_burst;
- toks -= L2T(police, qdisc_pkt_len(skb));
+ toks -= (s64) psched_l2t_ns(&police->rate, qdisc_pkt_len(skb));
if ((toks|ptoks) >= 0) {
police->tcfp_t_c = now;
police->tcfp_toks = toks;
@@ -363,15 +370,15 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
.index = police->tcf_index,
.action = police->tcf_action,
.mtu = police->tcfp_mtu,
- .burst = police->tcfp_burst,
+ .burst = PSCHED_NS2TICKS(police->tcfp_burst),
.refcnt = police->tcf_refcnt - ref,
.bindcnt = police->tcf_bindcnt - bind,
};
- if (police->tcfp_R_tab)
- opt.rate = police->tcfp_R_tab->rate;
- if (police->tcfp_P_tab)
- opt.peakrate = police->tcfp_P_tab->rate;
+ if (police->rate_present)
+ opt.rate.rate = psched_ratecfg_getrate(&police->rate);
+ if (police->peak_present)
+ opt.peakrate.rate = psched_ratecfg_getrate(&police->peak);
if (nla_put(skb, TCA_POLICE_TBF, sizeof(opt), &opt))
goto nla_put_failure;
if (police->tcfp_result &&
--
1.8.1.2
^ permalink raw reply related
* [patch net-next v4 11/11] act_police: remove <=mtu check for gso skbs
From: Jiri Pirko @ 2013-02-10 10:52 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, jhs, kuznet, j.vimal
In-Reply-To: <1360493539-14868-1-git-send-email-jiri@resnulli.us>
This check made bigger packets incorrectly dropped. Remove this
limitation for gso skbs.
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
net/sched/act_police.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 71bf4f5..e11eca9 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -325,7 +325,7 @@ static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a,
return police->tcf_action;
}
- if (qdisc_pkt_len(skb) <= police->tcfp_mtu) {
+ if (qdisc_pkt_len(skb) <= police->tcfp_mtu || skb_is_gso(skb)) {
if (!police->rate_present) {
spin_unlock(&police->tcf_lock);
return police->tcfp_result;
--
1.8.1.2
^ permalink raw reply related
* Re: [IPv6] interface-local multicast escapes the local node
From: YOSHIFUJI Hideaki @ 2013-02-10 10:57 UTC (permalink / raw)
To: Erik Hugne, netdev, YOSHIFUJI Hideaki, YOSHIFUJI Hideaki
In-Reply-To: <20130210095954.GA23548@order.stressinduktion.org>
Hannes Frederic Sowa wrote:
> On Sat, Feb 09, 2013 at 11:12:46PM +0900, YOSHIFUJI Hideaki wrote:
>> It seems applications will join ff01::/16%eth0 instead of ff01::/16%lo.
>> If so, your original patch seems better. My bad, sorry.
>>
>> Would you update original one, with minor modification that defers
>> kfree_skb() after incrementing MIB, please?
>
> I would add another constraint to the if "&& !(dev->flags & IFF_LOOPBACK)", so
> it becomes:
>
> if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
> IPV6_ADDR_SCOPE_NODELOCAL &&
> !(dev->flags & IFF_LOOPBACK))
> kfree_skb(skb);
> return 0;
> }
>
>
> Otherwise ff01::/16%lo would not work because the multicast mirroring through
> dev_loopback_xmit won't be taken and the packet would be dropped after that.
>
> Can you confirm? Thanks.
Ack.
--yoshfuji
^ permalink raw reply
* [PATCH vringh 0/2] Introduce CAIF Virtio driver
From: sjur.brandeland @ 2013-02-10 11:04 UTC (permalink / raw)
To: Rusty Russell, David S. Miller, Ohad Ben-Cohen
Cc: Dmitry Tarnyagin, sjur, Linus Walleij, linux-kernel, Erwan Yvin,
virtualization, netdev, Ido Yariv, Sjur Brændeland
From: Sjur Brændeland <sjur.brandeland@stericsson.com>
This patch-set introduces the CAIF Virtio Link layer driver.
This driver depends on Rusty's new host virtio ring implementation,
so this patch-set is based on the vringh branch in Rusty's git.
Regards,
Sjur
cc: Rusty Russell <rusty@rustcorp.com.au>
cc: Ohad Ben-Cohen <ohad@wizery.com>
cc: David S. Miller <davem@davemloft.net>
cc: Ido Yariv <ido@wizery.com>
cc: Erwan Yvin <erwan.yvin@stericsson.com>
Sjur Brændeland (1):
remoteproc: Add support for vringh (Host vrings)
Vikram ARV (1):
caif_virtio: Introduce caif over virtio
drivers/net/caif/Kconfig | 8 +
drivers/net/caif/Makefile | 3 +
drivers/net/caif/caif_virtio.c | 568 ++++++++++++++++++++++++++++++++
drivers/remoteproc/Kconfig | 3 +
drivers/remoteproc/remoteproc_virtio.c | 127 +++++++-
include/linux/remoteproc.h | 14 +
include/linux/virtio_caif.h | 24 ++
include/uapi/linux/virtio_ids.h | 1 +
8 files changed, 741 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/caif/caif_virtio.c
create mode 100644 include/linux/virtio_caif.h
--
1.7.5.4
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* [PATCH vringh 1/2] remoteproc: Add support for vringh (Host vrings)
From: sjur.brandeland @ 2013-02-10 11:04 UTC (permalink / raw)
To: Rusty Russell, David S. Miller, Ohad Ben-Cohen
Cc: Dmitry Tarnyagin, sjur, Linus Walleij, linux-kernel, Erwan Yvin,
virtualization, netdev, Ido Yariv, Sjur Brændeland
In-Reply-To: <1360494273-27889-1-git-send-email-sjur.brandeland@stericsson.com>
From: Sjur Brændeland <sjur.brandeland@stericsson.com>
Add functions for creating, deleting and kicking host-side virtio rings.
The host ring is not integrated with virtiqueues and cannot be managed
through virtio-config. Remoteproc must export functions for handling the
host-side virtio rings.
The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(),
rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The
existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs()
are updated to handle the new vhost rings.
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
cc: Ohad Ben-Cohen <ohad@wizery.com>
cc: Rusty Russell <rusty@rustcorp.com.au>
cc: Ido Yariv <ido@wizery.com>
cc: Erwan Yvin <erwan.yvin@stericsson.com>
---
Hi Ohad,
I would really appreciate if you could find time to
review this patch. It will go via Rusty's vringh tree.
Feedback and review comments are welcomed.
Thanks,
Sjur
drivers/remoteproc/Kconfig | 3 +
drivers/remoteproc/remoteproc_virtio.c | 127 ++++++++++++++++++++++++++++++--
include/linux/remoteproc.h | 14 ++++
3 files changed, 137 insertions(+), 7 deletions(-)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 96ce101..c7d1d36 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -7,6 +7,9 @@ config REMOTEPROC
depends on HAS_DMA
select FW_CONFIG
select VIRTIO
+ select VHOST_RING
+
+source drivers/vhost/Kconfig
config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..fa7bf7b 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -23,6 +23,7 @@
#include <linux/virtio_config.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_ring.h>
+#include <linux/vringh.h>
#include <linux/err.h>
#include <linux/kref.h>
#include <linux/slab.h>
@@ -60,10 +61,15 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
rvring = idr_find(&rproc->notifyids, notifyid);
- if (!rvring || !rvring->vq)
+ if (!rvring)
return IRQ_NONE;
- return vring_interrupt(0, rvring->vq);
+ if (rvring->vringh && rvring->vringh_cb)
+ return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh);
+ else if (rvring->vq)
+ return vring_interrupt(0, rvring->vq);
+ else
+ return IRQ_NONE;
}
EXPORT_SYMBOL(rproc_vq_interrupt);
@@ -149,14 +155,21 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
const char *names[])
{
struct rproc *rproc = vdev_to_rproc(vdev);
- int i, ret;
+ struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+ int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring);
+
+ for (id = 0, rng = 0; rng < nrings; ++rng) {
+ struct rproc_vring *rvring = &rvdev->vring[rng];
+ /* Skip the host side rings */
+ if (rvring->vringh)
+ continue;
- for (i = 0; i < nvqs; ++i) {
- vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
- if (IS_ERR(vqs[i])) {
- ret = PTR_ERR(vqs[i]);
+ vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]);
+ if (IS_ERR(vqs[id])) {
+ ret = PTR_ERR(vqs[id]);
goto error;
}
+ ++id;
}
/* now that the vqs are all set, boot the remote processor */
@@ -173,6 +186,106 @@ error:
return ret;
}
+/**
+ * rproc_virtio_new_vringh() - create a reversed virtio ring.
+ * @vdev: the virtio device
+ * @index: the virtio ring index
+ * @cb: callback for the reversed virtio ring
+ *
+ * This function should be called by the virtio-driver
+ * before calling find_vqs(). It returns a struct vringh for
+ * accessing the virtio ring.
+ *
+ * Return: struct vhost, or NULL upon error.
+ */
+struct vringh *
+rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index,
+ irqreturn_t (*cb)(struct virtio_device *vdev,
+ struct vringh *vring))
+{
+ struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+ struct rproc_vring *rvring;
+ struct vringh *vrh;
+ int err;
+
+ if (index > ARRAY_SIZE(rvdev->vring)) {
+ dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index);
+ return NULL;
+ }
+
+ vrh = kzalloc(sizeof(*vrh), GFP_KERNEL);
+ if (!vrh)
+ return NULL;
+
+ err = rproc_alloc_vring(rvdev, index);
+ if (err)
+ goto free_vring;
+
+
+ rvring = &rvdev->vring[index];
+ /* zero vring */
+ memset(rvring->va, 0, vring_size(rvring->len, rvring->align));
+ vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align);
+
+ rvring->vringh_cb = cb;
+ rvring->vringh = vrh;
+
+ err = vringh_init_kern(vrh,
+ rvdev->dfeatures,
+ rvring->len,
+ false,
+ vrh->vring.desc,
+ vrh->vring.avail,
+ vrh->vring.used);
+ if (!err)
+ return vrh;
+
+ dev_err(&vdev->dev, "failed to create vhost: %d\n", err);
+ rproc_free_vring(rvring);
+free_vring:
+ kfree(vrh);
+ return NULL;
+}
+EXPORT_SYMBOL(rproc_virtio_new_vringh);
+
+/**
+ * rproc_virtio_del_vringh() - release a reversed virtio ring.
+ * @vdev: the virtio device
+ * @index: the virtio ring index
+ *
+ * This function release the reversed virtio ring.
+ */
+void rproc_virtio_del_vringh(struct virtio_device *vdev, unsigned index)
+{
+ struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+ struct rproc_vring *rvring = &rvdev->vring[index];
+ kfree(rvring->vringh);
+ rproc_free_vring(rvring);
+ rvring->vringh_cb = NULL;
+ rvring->vringh = NULL;
+}
+EXPORT_SYMBOL(rproc_virtio_del_vringh);
+
+/**
+ * rproc_virtio_kick_vringh() - kick the remote processor.
+ * @vdev: the virtio device
+ * @index: the virtio ring index
+ *
+ * kick the remote processor, and let it know which vring to poke at
+ */
+void rproc_virtio_kick_vringh(struct virtio_device *vdev, unsigned index)
+{
+ struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+ struct rproc_vring *rvring = &rvdev->vring[index];
+ struct rproc *rproc = rvring->rvdev->rproc;
+ int notifyid = rvring->notifyid;
+
+ dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid);
+
+ rproc->ops->kick(rproc, notifyid);
+}
+EXPORT_SYMBOL(rproc_virtio_kick_vringh);
+
/*
* We don't support yet real virtio status semantics.
*
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index faf3332..414a1fd 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -39,7 +39,9 @@
#include <linux/klist.h>
#include <linux/mutex.h>
#include <linux/virtio.h>
+#include <linux/vringh.h>
#include <linux/completion.h>
+#include <linux/interrupt.h>
#include <linux/idr.h>
/**
@@ -444,6 +446,8 @@ struct rproc {
* @notifyid: rproc-specific unique vring index
* @rvdev: remote vdev
* @vq: the virtqueue of this vring
+ * @vringh_cb: callback used when device has kicked
+ * @vringh: the reversed host-side vring
*/
struct rproc_vring {
void *va;
@@ -454,6 +458,9 @@ struct rproc_vring {
int notifyid;
struct rproc_vdev *rvdev;
struct virtqueue *vq;
+ irqreturn_t (*vringh_cb)(struct virtio_device *vdev,
+ struct vringh *vring);
+ struct vringh *vringh;
};
/**
@@ -485,6 +492,13 @@ int rproc_boot(struct rproc *rproc);
void rproc_shutdown(struct rproc *rproc);
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
+struct vringh *
+rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index,
+ irqreturn_t (*cb)(struct virtio_device *vdev,
+ struct vringh *vring));
+void rproc_virtio_del_vringh(struct virtio_device *vdev, unsigned index);
+void rproc_virtio_kick_vringh(struct virtio_device *vdev, unsigned index);
+
static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
{
return container_of(vdev, struct rproc_vdev, vdev);
--
1.7.5.4
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply related
* [PATCH vringh 2/2] caif_virtio: Introduce caif over virtio
From: sjur.brandeland @ 2013-02-10 11:04 UTC (permalink / raw)
To: Rusty Russell, David S. Miller, Ohad Ben-Cohen
Cc: Vikram ARV, Dmitry Tarnyagin, sjur, Linus Walleij, linux-kernel,
Erwan Yvin, virtualization, netdev, Ido Yariv,
Sjur Brændeland
In-Reply-To: <1360494273-27889-1-git-send-email-sjur.brandeland@stericsson.com>
From: Vikram ARV <vikram.arv@stericsson.com>
Add the the Virtio shared memory driver for STE Modems.
caif_virtio is implemented utilizing the virtio framework
for data transport and is managed with the remoteproc frameworks.
The Virtio queue is used for transmitting data to the modem, and
the new vringh implementation is receiving data over the vring.
Signed-off-by: Vikram ARV <vikram.arv@stericsson.com>
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
to: David S. Miller <davem@davemloft.net>
cc: Rusty Russell <rusty@rustcorp.com.au>
cc: Ohad Ben-Cohen <ohad@wizery.com>
cc: Ido Yariv <ido@wizery.com>
cc: Erwan Yvin <erwan.yvin@stericsson.com>
---
Hi Dave,
Rusty has accepted to take this patch via his tree.
Feedback and review comments are appreciated.
Thanks,
Sjur
drivers/net/caif/Kconfig | 8 +
drivers/net/caif/Makefile | 3 +
drivers/net/caif/caif_virtio.c | 568 +++++++++++++++++++++++++++++++++++++++
include/linux/virtio_caif.h | 24 ++
include/uapi/linux/virtio_ids.h | 1 +
5 files changed, 604 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/caif/caif_virtio.c
create mode 100644 include/linux/virtio_caif.h
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index abf4d7a..a8b67e9 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -47,3 +47,11 @@ config CAIF_HSI
The caif low level driver for CAIF over HSI.
Be aware that if you enable this then you also need to
enable a low-level HSI driver.
+
+config CAIF_VIRTIO
+ tristate "CAIF virtio transport driver"
+ depends on CAIF
+ depends on REMOTEPROC
+ default n
+ ---help---
+ The caif driver for CAIF over Virtio.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 91dff86..d9ee26a 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -13,3 +13,6 @@ obj-$(CONFIG_CAIF_SHM) += caif_shm.o
# HSI interface
obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
+
+# Virtio interface
+obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o
diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c
new file mode 100644
index 0000000..e8ea114
--- /dev/null
+++ b/drivers/net/caif/caif_virtio.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Authors: Vicram Arv / vikram.arv@stericsson.com,
+ * Dmitry Tarnyagin / dmitry.tarnyagin@stericsson.com
+ * Sjur Brendeland / sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/spinlock.h>
+#include <linux/virtio_caif.h>
+#include <linux/virtio_ring.h>
+#include <linux/vringh.h>
+#include <linux/remoteproc.h>
+#include <net/caif/caif_dev.h>
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Vicram Arv <vikram.arv@stericsson.com>");
+MODULE_AUTHOR("Sjur Brendeland <sjur.brandeland@stericsson.com");
+MODULE_DESCRIPTION("Virtio CAIF Driver");
+
+/* Virtio Ring used in receive direction */
+#define RX_RING_INDEX 0
+
+#define CFV_DEFAULT_QUOTA 32
+
+/* struct cfv_napi_contxt - NAPI context info
+ * @riov: IOV holding data read from the ring. Note that riov may
+ * still hold data when cfv_rx_poll() returns.
+ * @head: Last descriptor ID we received from vringh_getdesc_kern.
+ * We use this to put descriptor back on the used ring. USHRT_MAX is
+ * used to indicate invalid head-id.
+ */
+struct cfv_napi_context {
+ struct vringh_kiov riov;
+ unsigned short head;
+};
+
+/* struct cfv_info - Caif Virtio control structure
+ * @cfdev: caif common header
+ * @vdev: Associated virtio device
+ * @vq_rx: rx/downlink virtqueue
+ * @vq_tx: tx/uplink virtqueue
+ * @ndev: associated netdevice
+ * @queued_tx: number of buffers queued in the tx virtqueue
+ * @watermark_tx: indicates number of buffers the tx queue
+ * should shrink to to unblock datapath
+ * @tx_lock: protects vq_tx to allow concurrent senders
+ * @tx_hr: transmit headroom
+ * @rx_hr: receive headroom
+ * @tx_tr: transmit tailroom
+ * @rx_tr: receive tailroom
+ * @mtu: transmit max size
+ * @mru: receive max size
+ */
+struct cfv_info {
+ struct caif_dev_common cfdev;
+ struct virtio_device *vdev;
+ struct vringh *vr_rx;
+ struct virtqueue *vq_tx;
+ struct net_device *ndev;
+ unsigned int queued_tx;
+ unsigned int watermark_tx;
+ /* Protect access to vq_tx */
+ spinlock_t tx_lock;
+ struct tasklet_struct tx_release_tasklet;
+ struct napi_struct napi;
+ struct cfv_napi_context ctx;
+ /* Copied from Virtio config space */
+ u16 tx_hr;
+ u16 rx_hr;
+ u16 tx_tr;
+ u16 rx_tr;
+ u32 mtu;
+ u32 mru;
+};
+
+/* struct token_info - maintains Transmit buffer data handle
+ * @size: size of transmit buffer
+ * @dma_handle: handle to allocated dma device memory area
+ * @vaddr: virtual address mapping to allocated memory area
+ */
+struct token_info {
+ size_t size;
+ u8 *vaddr;
+ dma_addr_t dma_handle;
+};
+
+/* Default if virtio config space is unavailable */
+#define CFV_DEF_MTU_SIZE 4096
+#define CFV_DEF_HEADROOM 32
+#define CFV_DEF_TAILROOM 32
+
+/* Require IP header to be 4-byte aligned. */
+#define IP_HDR_ALIGN 4
+
+static inline void ctx_prep_iov(struct cfv_napi_context *ctx)
+{
+ if (ctx->riov.allocated) {
+ kfree(ctx->riov.iov);
+ ctx->riov.iov = NULL;
+ ctx->riov.allocated = false;
+ }
+ ctx->riov.iov = NULL;
+ ctx->riov.i = 0;
+ ctx->riov.max = 0;
+}
+
+static void cfv_release_cb(struct virtqueue *vq_tx)
+{
+ struct cfv_info *cfv = vq_tx->vdev->priv;
+ tasklet_schedule(&cfv->tx_release_tasklet);
+}
+
+/* This is invoked whenever the remote processor completed processing
+ * a TX msg we just sent it, and the buffer is put back to the used ring.
+ */
+static void cfv_release_used_buf(struct virtqueue *vq_tx)
+{
+ struct cfv_info *cfv = vq_tx->vdev->priv;
+ unsigned long flags;
+
+ BUG_ON(vq_tx != cfv->vq_tx);
+ WARN_ON_ONCE(irqs_disabled());
+
+ for (;;) {
+ unsigned int len;
+ struct token_info *buf_info;
+
+ /* Get used buffer from used ring to recycle used descriptors */
+ spin_lock_irqsave(&cfv->tx_lock, flags);
+ buf_info = virtqueue_get_buf(vq_tx, &len);
+
+ if (!buf_info)
+ goto out;
+
+ BUG_ON(!cfv->queued_tx);
+ if (--cfv->queued_tx <= cfv->watermark_tx) {
+ cfv->watermark_tx = 0;
+ netif_tx_wake_all_queues(cfv->ndev);
+ }
+ spin_unlock_irqrestore(&cfv->tx_lock, flags);
+
+ dma_free_coherent(vq_tx->vdev->dev.parent->parent,
+ buf_info->size, buf_info->vaddr,
+ buf_info->dma_handle);
+ kfree(buf_info);
+ }
+ return;
+out:
+ spin_unlock_irqrestore(&cfv->tx_lock, flags);
+}
+
+static struct sk_buff *cfv_alloc_and_copy_skb(int *err,
+ struct cfv_info *cfv,
+ u8 *frm, u32 frm_len)
+{
+ struct sk_buff *skb;
+ u32 cfpkt_len, pad_len;
+
+ *err = 0;
+ /* Verify that packet size with down-link header and mtu size */
+ if (frm_len > cfv->mru || frm_len <= cfv->rx_hr + cfv->rx_tr) {
+ netdev_err(cfv->ndev,
+ "Invalid frmlen:%u mtu:%u hr:%d tr:%d\n",
+ frm_len, cfv->mru, cfv->rx_hr,
+ cfv->rx_tr);
+ *err = -EPROTO;
+ return NULL;
+ }
+
+ cfpkt_len = frm_len - (cfv->rx_hr + cfv->rx_tr);
+
+ pad_len = (unsigned long)(frm + cfv->rx_hr) & (IP_HDR_ALIGN - 1);
+
+ skb = netdev_alloc_skb(cfv->ndev, frm_len + pad_len);
+ if (!skb) {
+ *err = -ENOMEM;
+ return NULL;
+ }
+ /* Reserve space for headers. */
+ skb_reserve(skb, cfv->rx_hr + pad_len);
+
+ memcpy(skb_put(skb, cfpkt_len), frm + cfv->rx_hr, cfpkt_len);
+ return skb;
+}
+
+static int cfv_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct cfv_info *cfv = container_of(napi, struct cfv_info, napi);
+ int rxcnt = 0;
+ int err = 0;
+ struct vringh_kiov wiov;
+ void *buf;
+ struct sk_buff *skb;
+ struct vringh_kiov *riov = &cfv->ctx.riov;
+
+ memset(&wiov, 0, sizeof(wiov));
+
+ do {
+ skb = NULL;
+ if (riov->i == riov->max) {
+ if (cfv->ctx.head != USHRT_MAX) {
+ vringh_complete_kern(cfv->vr_rx,
+ cfv->ctx.head,
+ 0);
+ cfv->ctx.head = USHRT_MAX;
+ }
+
+ ctx_prep_iov(&cfv->ctx);
+ err = vringh_getdesc_kern(
+ cfv->vr_rx,
+ riov,
+ &wiov,
+ &cfv->ctx.head,
+ GFP_ATOMIC);
+
+ if (err <= 0)
+ goto out;
+
+ if (wiov.max != 0) {
+ /* CAIF does not use write descriptors */
+ err = -EPROTO;
+ goto out;
+ }
+ }
+
+ buf = phys_to_virt((unsigned long) riov->iov[riov->i].iov_base);
+ /* TODO: Add check on valid buffer address */
+
+ skb = cfv_alloc_and_copy_skb(&err, cfv, buf,
+ riov->iov[riov->i].iov_len);
+ if (unlikely(err))
+ goto out;
+
+ /* Push received packet up the stack. */
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = cfv->ndev;
+ err = netif_receive_skb(skb);
+ if (unlikely(err)) {
+ ++cfv->ndev->stats.rx_dropped;
+ } else {
+ ++cfv->ndev->stats.rx_packets;
+ cfv->ndev->stats.rx_bytes += skb->len;
+ }
+
+ ++riov->i;
+ ++rxcnt;
+ } while (rxcnt < quota);
+
+ return rxcnt;
+
+out:
+ switch (err) {
+ case 0:
+ /* Empty ring, enable notifications and stop NAPI polling */
+ if (!vringh_notify_enable_kern(cfv->vr_rx)) {
+ napi_complete(napi);
+ ctx_prep_iov(&cfv->ctx);
+ }
+ return rxcnt;
+ break;
+
+ case -ENOMEM:
+ dev_kfree_skb(skb);
+ /* Stop NAPI poll on OOM, we hope to be polled later */
+ napi_complete(napi);
+ vringh_notify_enable_kern(cfv->vr_rx);
+ break;
+
+ default:
+ /* We're doomed */
+ netdev_warn(cfv->ndev, "Bad ring, disable device\n");
+ cfv->ndev->stats.rx_dropped = riov->max - riov->i;
+ ctx_prep_iov(&cfv->ctx);
+ napi_complete(napi);
+ vringh_notify_disable_kern(cfv->vr_rx);
+ netif_carrier_off(cfv->ndev);
+ break;
+ }
+
+ return rxcnt;
+}
+
+static irqreturn_t cfv_recv(struct virtio_device *vdev, struct vringh *vr_rx)
+{
+ struct cfv_info *cfv = vdev->priv;
+
+ vringh_notify_disable_kern(cfv->vr_rx);
+ napi_schedule(&cfv->napi);
+ return IRQ_HANDLED;
+}
+
+static int cfv_netdev_open(struct net_device *netdev)
+{
+ struct cfv_info *cfv = netdev_priv(netdev);
+
+ netif_carrier_on(netdev);
+ napi_enable(&cfv->napi);
+ return 0;
+}
+
+static int cfv_netdev_close(struct net_device *netdev)
+{
+ struct cfv_info *cfv = netdev_priv(netdev);
+
+ netif_carrier_off(netdev);
+ napi_disable(&cfv->napi);
+ return 0;
+}
+
+static struct token_info *cfv_alloc_and_copy_to_dmabuf(struct cfv_info *cfv,
+ struct sk_buff *skb,
+ struct scatterlist *sg)
+{
+ struct caif_payload_info *info = (void *)&skb->cb;
+ struct token_info *buf_info = NULL;
+ u8 pad_len, hdr_ofs;
+
+ if (unlikely(cfv->tx_hr + skb->len + cfv->tx_tr > cfv->mtu)) {
+ netdev_warn(cfv->ndev, "Invalid packet len (%d > %d)\n",
+ cfv->tx_hr + skb->len + cfv->tx_tr, cfv->mtu);
+ goto err;
+ }
+
+ buf_info = kmalloc(sizeof(struct token_info), GFP_ATOMIC);
+ if (unlikely(!buf_info))
+ goto err;
+
+ /* Make the IP header aligned in tbe buffer */
+ hdr_ofs = cfv->tx_hr + info->hdr_len;
+ pad_len = hdr_ofs & (IP_HDR_ALIGN - 1);
+ buf_info->size = cfv->tx_hr + skb->len + cfv->tx_tr + pad_len;
+
+ if (WARN_ON_ONCE(!cfv->vdev->dev.parent))
+ goto err;
+
+ /* allocate coherent memory for the buffers */
+ buf_info->vaddr =
+ dma_alloc_coherent(cfv->vdev->dev.parent->parent,
+ buf_info->size, &buf_info->dma_handle,
+ GFP_ATOMIC);
+ if (unlikely(!buf_info->vaddr)) {
+ netdev_warn(cfv->ndev,
+ "Out of DMA memory (alloc %zu bytes)\n",
+ buf_info->size);
+ goto err;
+ }
+
+ /* copy skbuf contents to send buffer */
+ skb_copy_bits(skb, 0, buf_info->vaddr + cfv->tx_hr + pad_len, skb->len);
+ sg_init_one(sg, buf_info->vaddr + pad_len,
+ skb->len + cfv->tx_hr + cfv->rx_hr);
+
+ return buf_info;
+err:
+ kfree(buf_info);
+ return NULL;
+}
+
+/* This is invoked whenever the host processor application has sent
+ * up-link data. Send it in the TX VQ avail ring.
+ *
+ * CAIF Virtio sends does not use linked descriptors in the tx direction.
+ */
+static int cfv_netdev_tx(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct cfv_info *cfv = netdev_priv(netdev);
+ struct token_info *buf_info;
+ struct scatterlist sg;
+ unsigned long flags;
+ int ret;
+
+ buf_info = cfv_alloc_and_copy_to_dmabuf(cfv, skb, &sg);
+
+ spin_lock_irqsave(&cfv->tx_lock, flags);
+ if (unlikely(!buf_info))
+ goto flow_off;
+
+ /* Add buffer to avail ring. Flow control below should ensure
+ * that this always succeedes
+ */
+ ret = virtqueue_add_buf(cfv->vq_tx, &sg, 1, 0,
+ buf_info, GFP_ATOMIC);
+
+ if (unlikely(WARN_ON(ret < 0))) {
+ kfree(buf_info);
+ goto flow_off;
+ }
+
+
+ /* update netdev statistics */
+ cfv->queued_tx++;
+ cfv->ndev->stats.tx_packets++;
+ cfv->ndev->stats.tx_bytes += skb->len;
+
+ /* tell the remote processor it has a pending message to read */
+ virtqueue_kick(cfv->vq_tx);
+
+ /* Flow-off check takes into account number of cpus to make sure
+ * virtqueue will not be overfilled in any possible smp conditions.
+ *
+ * Flow-on is triggered when sufficient buffers are freed
+ */
+ if (ret <= num_present_cpus()) {
+flow_off:
+ cfv->watermark_tx = cfv->queued_tx >> 1;
+ netif_tx_stop_all_queues(netdev);
+ }
+
+ spin_unlock_irqrestore(&cfv->tx_lock, flags);
+
+ dev_kfree_skb(skb);
+ tasklet_schedule(&cfv->tx_release_tasklet);
+ return NETDEV_TX_OK;
+}
+
+static void cfv_tx_release_tasklet(unsigned long drv)
+{
+ struct cfv_info *cfv = (struct cfv_info *)drv;
+ cfv_release_used_buf(cfv->vq_tx);
+}
+
+static const struct net_device_ops cfv_netdev_ops = {
+ .ndo_open = cfv_netdev_open,
+ .ndo_stop = cfv_netdev_close,
+ .ndo_start_xmit = cfv_netdev_tx,
+};
+
+static void cfv_netdev_setup(struct net_device *netdev)
+{
+ netdev->netdev_ops = &cfv_netdev_ops;
+ netdev->type = ARPHRD_CAIF;
+ netdev->tx_queue_len = 100;
+ netdev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ netdev->mtu = CFV_DEF_MTU_SIZE;
+ netdev->destructor = free_netdev;
+}
+
+static int cfv_probe(struct virtio_device *vdev)
+{
+ vq_callback_t *vq_cbs = cfv_release_cb;
+ const char *names = "output";
+ const char *cfv_netdev_name = "cfvrt";
+ struct net_device *netdev;
+ struct virtqueue *vqs;
+
+ struct cfv_info *cfv;
+ int err = 0;
+
+ netdev = alloc_netdev(sizeof(struct cfv_info), cfv_netdev_name,
+ cfv_netdev_setup);
+ if (!netdev)
+ return -ENOMEM;
+
+ cfv = netdev_priv(netdev);
+ cfv->vdev = vdev;
+ cfv->ndev = netdev;
+
+ spin_lock_init(&cfv->tx_lock);
+
+ cfv->vr_rx = rproc_virtio_new_vringh(vdev, RX_RING_INDEX, cfv_recv);
+ if (!cfv->vr_rx)
+ goto free_cfv;
+
+ /* Get the TX (uplink) virtque */
+ err = vdev->config->find_vqs(vdev, 1, &vqs, &vq_cbs, &names);
+ if (err)
+ goto free_cfv;
+
+ cfv->vq_tx = vqs;
+
+#define GET_VIRTIO_CONFIG_OPS(_v, _var, _f) \
+ ((_v)->config->get(_v, offsetof(struct virtio_caif_transf_config, _f), \
+ &_var, \
+ FIELD_SIZEOF(struct virtio_caif_transf_config, _f)))
+
+ if (vdev->config->get) {
+ GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_hr, headroom);
+ GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_hr, headroom);
+ GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_tr, tailroom);
+ GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_tr, tailroom);
+ GET_VIRTIO_CONFIG_OPS(vdev, cfv->mtu, mtu);
+ GET_VIRTIO_CONFIG_OPS(vdev, cfv->mru, mtu);
+ } else {
+ cfv->tx_hr = CFV_DEF_HEADROOM;
+ cfv->rx_hr = CFV_DEF_HEADROOM;
+ cfv->tx_tr = CFV_DEF_TAILROOM;
+ cfv->rx_tr = CFV_DEF_TAILROOM;
+ cfv->mtu = CFV_DEF_MTU_SIZE;
+ cfv->mru = CFV_DEF_MTU_SIZE;
+ }
+
+ netdev->needed_headroom = cfv->tx_hr;
+ netdev->needed_tailroom = cfv->tx_tr;
+
+ /* Subtract needed tailroom from MTU to ensure enough room */
+ netdev->mtu = cfv->mtu - cfv->tx_tr;
+
+ vdev->priv = cfv;
+ memset(&cfv->ctx, 0, sizeof(cfv->ctx));
+ cfv->ctx.head = USHRT_MAX;
+
+ netif_napi_add(netdev, &cfv->napi, cfv_rx_poll, CFV_DEFAULT_QUOTA);
+ tasklet_init(&cfv->tx_release_tasklet,
+ cfv_tx_release_tasklet,
+ (unsigned long)cfv);
+
+ netif_carrier_off(netdev);
+
+ /* register Netdev */
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&vdev->dev, "Unable to register netdev (%d)\n", err);
+ goto vqs_del;
+ }
+
+ /* tell the remote processor it can start sending messages */
+ rproc_virtio_kick_vringh(vdev, RX_RING_INDEX);
+
+ return 0;
+
+vqs_del:
+ vdev->config->del_vqs(cfv->vdev);
+free_cfv:
+ free_netdev(netdev);
+ return err;
+}
+
+static void cfv_remove(struct virtio_device *vdev)
+{
+ struct cfv_info *cfv = vdev->priv;
+ vdev->config->reset(vdev);
+ rproc_virtio_del_vringh(vdev, RX_RING_INDEX);
+ cfv->vr_rx = NULL;
+ vdev->config->del_vqs(cfv->vdev);
+ unregister_netdev(cfv->ndev);
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_CAIF, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static unsigned int features[] = {
+};
+
+static struct virtio_driver caif_virtio_driver = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = cfv_probe,
+ .remove = cfv_remove,
+};
+
+module_driver(caif_virtio_driver, register_virtio_driver,
+ unregister_virtio_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
diff --git a/include/linux/virtio_caif.h b/include/linux/virtio_caif.h
new file mode 100644
index 0000000..5d2d312
--- /dev/null
+++ b/include/linux/virtio_caif.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brændeland <sjur.brandeland@stericsson.com>
+ *
+ * This header is BSD licensed so
+ * anyone can use the definitions to implement compatible remote processors
+ */
+
+#ifndef VIRTIO_CAIF_H
+#define VIRTIO_CAIF_H
+
+#include <linux/types.h>
+struct virtio_caif_transf_config {
+ u16 headroom;
+ u16 tailroom;
+ u32 mtu;
+ u8 reserved[4];
+};
+
+struct virtio_caif_config {
+ struct virtio_caif_transf_config uplink, downlink;
+ u8 reserved[8];
+};
+#endif
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index a7630d0..284fc3a 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -38,5 +38,6 @@
#define VIRTIO_ID_SCSI 8 /* virtio scsi */
#define VIRTIO_ID_9P 9 /* 9p virtio console */
#define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */
+#define VIRTIO_ID_CAIF 12 /* Virtio caif */
#endif /* _LINUX_VIRTIO_IDS_H */
--
1.7.5.4
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply related
* [PATCH] ipv6: don't let node/interface scoped multicast traffic escape on the wire
From: Hannes Frederic Sowa @ 2013-02-10 12:33 UTC (permalink / raw)
To: netdev; +Cc: yoshfuji, erik.hugne
Reported-by: Erik Hugne <erik.hugne@ericsson.com>
Cc: Erik Hugne <erik.hugne@ericsson.com>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
net/ipv6/ip6_output.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index c953825..155eccf 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -120,6 +120,13 @@ static int ip6_finish_output2(struct sk_buff *skb)
IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST,
skb->len);
+
+ if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
+ IPV6_ADDR_SCOPE_NODELOCAL &&
+ !(dev->flags & IFF_LOOPBACK)) {
+ kfree_skb(skb);
+ return 0;
+ }
}
rcu_read_lock_bh();
--
1.8.1.2
^ permalink raw reply related
* Re: [net-next (TAKE 2) 0/4] IPv6 over Firewire
From: Stephan Gatzka @ 2013-02-10 12:48 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: netdev, linux1394-devel, davem, stefanr
In-Reply-To: <51177B15.3030405@linux-ipv6.org>
> I have tested against MacOS X 10.5.8.
>
> ARP and ping works but unfortunately NDP does not seem to work.
>
> If I assign static NDP entry on Linux, ping6 ff02::1%fw0 from MacOS
> works well.
>
> I checked tcpdump on both side, and I guess this is because MacOS is
> broken; - tcpdump on Linux side complains that ICMP checksum is
> incorrect. - tcpdump on MacOS side says that length of Link-layer
> address option is 2 (16) instead of 3 (24).
Than I would assume that there is a bug in your new implementation.
RFC3146 section 8 states that the link layer option is of length 3. In
addition, my proof of concept implementation also worked with MacOS X
and I double checked the ndisc packets directly on the firewire line
using a firewire sniffing device (firespy).
Regards,
Stephan
^ permalink raw reply
* [PATCH] ipv6: don't accept multicast traffic with scop 0
From: Hannes Frederic Sowa @ 2013-02-10 12:48 UTC (permalink / raw)
To: netdev; +Cc: yoshfuji, erik.hugne
Cc: Erik Hugne <erik.hugne@ericsson.com>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
net/ipv6/ip6_input.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 4ac5bf3..34ddebd 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -126,6 +126,16 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (ipv6_addr_is_multicast(&hdr->saddr))
goto err;
+ /*
+ * RFC4291 2.7
+ * Nodes must not originate a packet to a multicast address whose scop
+ * field contains the reserved value 0; if such a packet is received, it
+ * must be silently dropped.
+ */
+ if (ipv6_addr_is_multicast(&hdr->daddr) &&
+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0)
+ goto err;
+
skb->transport_header = skb->network_header + sizeof(*hdr);
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH net-next] ipv6 mcast: Do not join device multicast for interface-local multicasts.
From: Hannes Frederic Sowa @ 2013-02-10 12:51 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: netdev, David Miller
In-Reply-To: <51165D66.5090200@linux-ipv6.org>
On Sat, Feb 09, 2013 at 11:29:58PM +0900, YOSHIFUJI Hideaki wrote:
> RFC4291 (IPv6 addressing architecture) says that interface-Local scope
> spans only a single interface on a node. We should not join L2 device
> multicast list for addresses in interface-local (or smaller) scope.
>
> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Had this patch in my tree while testing and it is definitely the right thing
to do:
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
^ permalink raw reply
* [PATCH] ipv6: by default join ff01::1 and in case of forwarding ff01::2 and ff05:2
From: Hannes Frederic Sowa @ 2013-02-10 13:34 UTC (permalink / raw)
To: netdev
Cc: Erik Hugne <erik.hugne@ericsson.com>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
include/linux/in6.h | 9 +++++++++
net/ipv6/addrconf.c | 15 +++++++++++++--
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/include/linux/in6.h b/include/linux/in6.h
index a16e193..34edf1f 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -36,4 +36,13 @@ extern const struct in6_addr in6addr_linklocal_allnodes;
extern const struct in6_addr in6addr_linklocal_allrouters;
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{ { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } }
+extern const struct in6_addr in6addr_interfacelocal_allnodes;
+#define IN6ADDR_INTERFACELOCAL_ALLNODES_INIT \
+ { { { 0xff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+extern const struct in6_addr in6addr_interfacelocal_allrouters;
+#define IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT \
+ { { { 0xff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } }
+extern const struct in6_addr in6addr_sitelocal_allrouters;
+#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \
+ { { { 0xff,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } }
#endif
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index bd9f936..b83cd75 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -244,6 +244,9 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
/* Check if a valid qdisc is available */
static inline bool addrconf_qdisc_ok(const struct net_device *dev)
@@ -428,6 +431,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
/* protected by rtnl_lock */
rcu_assign_pointer(dev->ip6_ptr, ndev);
+ /* Join interface-local all-node multicast group */
+ ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes);
+
/* Join all-node multicast group */
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
@@ -611,10 +617,15 @@ static void dev_forward_change(struct inet6_dev *idev)
if (idev->cnf.forwarding)
dev_disable_lro(dev);
if (dev->flags & IFF_MULTICAST) {
- if (idev->cnf.forwarding)
+ if (idev->cnf.forwarding) {
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
- else
+ ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters);
+ ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
+ } else {
ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
+ ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters);
+ ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
+ }
}
list_for_each_entry(ifa, &idev->addr_list, if_list) {
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH] ipv6: by default join ff01::1 and in case of forwarding ff01::2 and ff05:2
From: Hannes Frederic Sowa @ 2013-02-10 13:42 UTC (permalink / raw)
To: netdev
In-Reply-To: <20130210133431.GD18219@order.stressinduktion.org>
Patch is flawed, will resend, sorry.
On Sun, Feb 10, 2013 at 02:34:31PM +0100, Hannes Frederic Sowa wrote:
> Cc: Erik Hugne <erik.hugne@ericsson.com>
> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> ---
> include/linux/in6.h | 9 +++++++++
> net/ipv6/addrconf.c | 15 +++++++++++++--
> 2 files changed, 22 insertions(+), 2 deletions(-)
^ permalink raw reply
* [PATCH net-next v2] ipv6: by default join ff01::1 and in case of forwarding ff01::2 and ff05:2
From: Hannes Frederic Sowa @ 2013-02-10 13:50 UTC (permalink / raw)
To: netdev; +Cc: yoshfuji, erik.hugne
Cc: Erik Hugne <erik.hugne@ericsson.com>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
include/linux/in6.h | 9 +++++++++
net/ipv6/addrconf.c | 15 +++++++++++++--
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/include/linux/in6.h b/include/linux/in6.h
index a16e193..34edf1f 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -36,4 +36,13 @@ extern const struct in6_addr in6addr_linklocal_allnodes;
extern const struct in6_addr in6addr_linklocal_allrouters;
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{ { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } }
+extern const struct in6_addr in6addr_interfacelocal_allnodes;
+#define IN6ADDR_INTERFACELOCAL_ALLNODES_INIT \
+ { { { 0xff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+extern const struct in6_addr in6addr_interfacelocal_allrouters;
+#define IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT \
+ { { { 0xff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } }
+extern const struct in6_addr in6addr_sitelocal_allrouters;
+#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \
+ { { { 0xff,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } }
#endif
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index bd9f936..86c235d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -244,6 +244,9 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
/* Check if a valid qdisc is available */
static inline bool addrconf_qdisc_ok(const struct net_device *dev)
@@ -428,6 +431,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
/* protected by rtnl_lock */
rcu_assign_pointer(dev->ip6_ptr, ndev);
+ /* Join interface-local all-node multicast group */
+ ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes);
+
/* Join all-node multicast group */
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
@@ -611,10 +617,15 @@ static void dev_forward_change(struct inet6_dev *idev)
if (idev->cnf.forwarding)
dev_disable_lro(dev);
if (dev->flags & IFF_MULTICAST) {
- if (idev->cnf.forwarding)
+ if (idev->cnf.forwarding) {
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
- else
+ ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters);
+ ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
+ } else {
ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
+ ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters);
+ ipv6_dev_mc_dec(dev, &in6addr_sitelocal_allrouters);
+ }
}
list_for_each_entry(ifa, &idev->addr_list, if_list) {
--
1.8.1.2
^ permalink raw reply related
* Re: [net-next (TAKE 2) 3/4] firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.
From: Stefan Richter @ 2013-02-10 14:10 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: netdev, linux1394-devel, davem
In-Reply-To: <51176223.8090305@linux-ipv6.org>
On Feb 10 YOSHIFUJI Hideaki wrote:
> @@ -1140,18 +1051,6 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
> unsigned long offset;
> unsigned u;
>
> - if (dev->local_fifo == FWNET_NO_FIFO_ADDR) {
> - dev->handler.length = 4096;
> - dev->handler.address_callback = fwnet_receive_packet;
> - dev->handler.callback_data = dev;
> -
> - retval = fw_core_add_address_handler(&dev->handler,
> - &fw_high_memory_region);
> - if (retval < 0)
> - goto failed_initial;
> -
> - dev->local_fifo = dev->handler.offset;
> - }
>
> max_receive = 1U << (dev->card->max_receive + 1);
> num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive;
> @@ -1234,8 +1133,6 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
> dev->broadcast_rcv_context = NULL;
> failed_context_create:
> fw_core_remove_address_handler(&dev->handler);
> - failed_initial:
> - dev->local_fifo = FWNET_NO_FIFO_ADDR;
>
> return retval;
> }
[...]
> @@ -1546,12 +1421,21 @@ static int fwnet_probe(struct device *_dev)
> dev->broadcast_rcv_context = NULL;
> dev->broadcast_xmt_max_payload = 0;
> dev->broadcast_xmt_datagramlabel = 0;
> - dev->local_fifo = FWNET_NO_FIFO_ADDR;
> dev->queued_datagrams = 0;
> INIT_LIST_HEAD(&dev->peer_list);
> dev->card = card;
> dev->netdev = net;
>
> + dev->handler.length = 4096;
> + dev->handler.address_callback = fwnet_receive_packet;
> + dev->handler.callback_data = dev;
> +
> + ret = fw_core_add_address_handler(&dev->handler, &fw_high_memory_region);
> + if (ret < 0)
> + goto out;
> +
> + dev->local_fifo = dev->handler.offset;
> +
> /*
> * Use the RFC 2734 default 1500 octets or the maximum payload
> * as initial MTU
If at all possible, please put changes of this kind into a separate
patch.
I get a distinct feeling that the error handling paths in
fwnet_broadcast_start() and in fwnet_probe() respectively became buggy now.
This would be easier to verify if shifting this code was done in a separate
change.
On a loosely related note:
Current firewire-net should be changed to release the isochronous
reception context (the DMA context which is used for broadcast and unicast
reception) at ifdown. That would make it symmetrical to its allocation
(at ifup) and, importantly, would be the earliest opportunity to release
it. This is important because isochronous reception DMA contexts are a
scarce hardware resource.
--
Stefan Richter
-=====-===-= --=- -=-=-
http://arcgraph.de/sr/
^ permalink raw reply
* Re: [net-next (TAKE 2) 3/4] firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.
From: Stefan Richter @ 2013-02-10 14:31 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: netdev, linux1394-devel, davem
In-Reply-To: <51176223.8090305@linux-ipv6.org>
On Feb 10 YOSHIFUJI Hideaki wrote:
> @@ -1339,42 +1236,23 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
> ptask->dest_node = IEEE1394_ALL_NODES;
> ptask->speed = SCODE_100;
> } else {
> - __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
> + union fwnet_hwaddr *ha = (union fwnet_hwaddr *)hdr_buf.h_dest;
> + __be64 guid = get_unaligned(&ha->uc.uniq_id);
> u8 generation;
>
> peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
> - if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
> + if (!peer)
> goto fail;
>
> generation = peer->generation;
> dest_node = peer->node_id;
> - max_payload = peer->max_payload;
> + max_payload = fwnet_hwaddr_maxpayload(ha);
> datagram_label_ptr = &peer->datagram_label;
>
> - ptask->fifo_addr = peer->fifo;
> + ptask->fifo_addr = fwnet_hwaddr_fifo(ha);
> ptask->generation = generation;
> ptask->dest_node = dest_node;
> - ptask->speed = peer->speed;
> - }
> -
> - /* If this is an ARP packet, convert it */
> - if (proto == htons(ETH_P_ARP)) {
> - struct arphdr *arp = (struct arphdr *)skb->data;
> - unsigned char *arp_ptr = (unsigned char *)(arp + 1);
> - struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data;
> - __be32 ipaddr;
> -
> - ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN));
> -
> - arp1394->hw_addr_len = RFC2734_HW_ADDR_LEN;
> - arp1394->max_rec = dev->card->max_receive;
> - arp1394->sspd = dev->card->link_speed;
> -
> - put_unaligned_be16(dev->local_fifo >> 32,
> - &arp1394->fifo_hi);
> - put_unaligned_be32(dev->local_fifo & 0xffffffff,
> - &arp1394->fifo_lo);
> - put_unaligned(ipaddr, &arp1394->sip);
> + ptask->speed = fwnet_fixup_speed(ha->uc.sspd);
> }
>
> ptask->hdr.w0 = 0;
> @@ -1491,13 +1369,9 @@ static int fwnet_add_peer(struct fwnet_device *dev,
>
> peer->dev = dev;
> peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
> - peer->fifo = FWNET_NO_FIFO_ADDR;
> - peer->ip = 0;
> INIT_LIST_HEAD(&peer->pd_list);
> peer->pdg_size = 0;
> peer->datagram_label = 0;
> - peer->speed = device->max_speed;
> - peer->max_payload = fwnet_max_payload(device->max_rec, peer->speed);
>
> peer->generation = device->generation;
> smp_rmb();
As far as I can tell, it would be best to ignore max_rec and sspd from ARP
and NDP but keep using the respective information from firewire-core
instead (handed over by fwnet_probe()).
Why? As I noted earlier, RFC 2734:1999 and RFC 3146:2001 were apparently
written with a too simplistic notion of IEEE 1394 bus topology, resulting
in max_rec and sspd in ARP-1394 and NDP-1394 to be useless, IMO.
Consider a bus like this:
A ---- B ==== C
A, B, C are all IP-over-1394 capable nodes. ---- is an S400 cable hop,
and ==== is an S800 cable hop.
In case of unicasts or multicasts in which node A is involved as
transmitter or receiver, as well as in case of broadcasts, the speeds
S100, S200, S400 work and speed S400 is optimal.
In case of anything else, IOW in case of unicasts or multicasts in which
only nodes B and C are involved, the speeds S100, S200, S400, S800 work
and speed S800 is optimal.
Clearly, node A should indicate sspd = S400 in its ARP or NDP packets.
But which sspd should nodes B and C set there? Maybe they set S400, which
would work but would waste half of the available bandwidth in the second
case. Or maybe they set S800, which is OK in the second case but would
prohibit any communication with node A if blindly taken for correct.
On the other hand, firewire-core *always* gives us the correct and optimum
peer-to-peer speed and asynchronous packet payload, no matter how simple
or complex the bus topology is and no matter in which temporal order nodes
join the bus and are discovered.
--
Stefan Richter
-=====-===-= --=- -=-=-
http://arcgraph.de/sr/
------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
^ permalink raw reply
* Re: [PATCH] ipv6: by default join ff01::1 and in case of forwarding ff01::2 and ff05:2
From: YOSHIFUJI Hideaki @ 2013-02-10 14:47 UTC (permalink / raw)
To: hannes; +Cc: netdev, YOSHIFUJI Hideaki
In-Reply-To: <20130210133431.GD18219@order.stressinduktion.org>
> @@ -611,10 +617,15 @@ static void dev_forward_change(struct inet6_dev *idev)
> if (idev->cnf.forwarding)
> dev_disable_lro(dev);
> if (dev->flags & IFF_MULTICAST) {
> - if (idev->cnf.forwarding)
> + if (idev->cnf.forwarding) {
> ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
> - else
> + ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters);
> + ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
> + } else {
> ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
> + ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters);
> + ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
~~~dec?
> + }
> }
--yoshfuji
^ permalink raw reply
* Re: [PATCH] ipv6: don't accept multicast traffic with scop 0
From: YOSHIFUJI Hideaki @ 2013-02-10 14:56 UTC (permalink / raw)
To: netdev, erik.hugne, YOSHIFUJI Hideaki
In-Reply-To: <20130210124851.GB18219@order.stressinduktion.org>
Hannes Frederic Sowa wrote:
> Cc: Erik Hugne <erik.hugne@ericsson.com>
> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> ---
> net/ipv6/ip6_input.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
> index 4ac5bf3..34ddebd 100644
> --- a/net/ipv6/ip6_input.c
> +++ b/net/ipv6/ip6_input.c
> @@ -126,6 +126,16 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
> if (ipv6_addr_is_multicast(&hdr->saddr))
> goto err;
>
> + /*
> + * RFC4291 2.7
> + * Nodes must not originate a packet to a multicast address whose scop
> + * field contains the reserved value 0; if such a packet is received, it
> + * must be silently dropped.
> + */
> + if (ipv6_addr_is_multicast(&hdr->daddr) &&
> + IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0)
> + goto err;
> +
> skb->transport_header = skb->network_header + sizeof(*hdr);
> IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
>
>
Would you place this before saddr check, just after loopback check, please?
Otherwise,
Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
--yoshfuji
^ permalink raw reply
* Re: [PATCH] ipv6: by default join ff01::1 and in case of forwarding ff01::2 and ff05:2
From: Hannes Frederic Sowa @ 2013-02-10 14:59 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: netdev, YOSHIFUJI Hideaki
In-Reply-To: <5117B306.4070402@yoshifuji.org>
On Sun, Feb 10, 2013 at 11:47:34PM +0900, YOSHIFUJI Hideaki wrote:
> > @@ -611,10 +617,15 @@ static void dev_forward_change(struct inet6_dev *idev)
> > if (idev->cnf.forwarding)
> > dev_disable_lro(dev);
> > if (dev->flags & IFF_MULTICAST) {
> > - if (idev->cnf.forwarding)
> > + if (idev->cnf.forwarding) {
> > ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
> > - else
> > + ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters);
> > + ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
> > + } else {
> > ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
> > + ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters);
> > + ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters);
> ~~~dec?
> > + }
> > }
Yes, that was the broken part. I fixed it locally and then send out the old
patch file.
^ permalink raw reply
* Re: [net-next (TAKE 2) 0/4] IPv6 over Firewire
From: YOSHIFUJI Hideaki @ 2013-02-10 15:05 UTC (permalink / raw)
To: stephan.gatzka; +Cc: netdev, linux1394-devel, davem, stefanr, YOSHIFUJI Hideaki
In-Reply-To: <51179714.6010706@gmail.com>
Hi,
Stephan Gatzka wrote:
>
>> I have tested against MacOS X 10.5.8.
>>
>> ARP and ping works but unfortunately NDP does not seem to work.
>>
>> If I assign static NDP entry on Linux, ping6 ff02::1%fw0 from MacOS
>> works well.icmp
>>
>> I checked tcpdump on both side, and I guess this is because MacOS is
>> broken; - tcpdump on Linux side complains that ICMP checksum is
>> incorrect. - tcpdump on MacOS side says that length of Link-layer
>> address option is 2 (16) instead of 3 (24).
>
> Than I would assume that there is a bug in your new implementation.
> RFC3146 section 8 states that the link layer option is of length 3. In
> addition, my proof of concept implementation also worked with MacOS X
> and I double checked the ndisc packets directly on the firewire line
> using a firewire sniffing device (firespy).
Can I have you code?
I meant, on MacOS X, it reports its originating lladdr option of 16bytes.
Then Linux side receives lladdr option of 24bytes, in ICMPv6 with incorrect
checksum. I guess that lladdr option is 16byte long at bpf layer,
and then, it is mangled in the driver, but ICMPv6 checksum was not modified.
In reverse, on Linux side, it sends lladdr option of 24 bytes long
with correct checksum, but it is ignored by MacOS.
--yoshfuji
^ permalink raw reply
* Re: [PATCH] ipv6: don't let node/interface scoped multicast traffic escape on the wire
From: YOSHIFUJI Hideaki @ 2013-02-10 15:31 UTC (permalink / raw)
To: David Miller; +Cc: netdev, erik.hugne, YOSHIFUJI Hideaki
In-Reply-To: <20130210123335.GA18219@order.stressinduktion.org>
> Reported-by: Erik Hugne <erik.hugne@ericsson.com>
> Cc: Erik Hugne <erik.hugne@ericsson.com>
> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> ---
> net/ipv6/ip6_output.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index c953825..155eccf 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -120,6 +120,13 @@ static int ip6_finish_output2(struct sk_buff *skb)
>
> IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST,
> skb->len);
> +
> + if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
> + IPV6_ADDR_SCOPE_NODELOCAL &&
> + !(dev->flags & IFF_LOOPBACK)) {
> + kfree_skb(skb);
> + return 0;
> + }
> }
>
> rcu_read_lock_bh();
>
Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
--yoshfuji
^ permalink raw reply
* Re: [IPv6] interface-local multicast escapes the local node
From: Hannes Frederic Sowa @ 2013-02-10 15:32 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: Erik Hugne, netdev, YOSHIFUJI Hideaki
In-Reply-To: <5116595E.2080601@linux-ipv6.org>
On Sat, Feb 09, 2013 at 11:12:46PM +0900, YOSHIFUJI Hideaki wrote:
> Hi,
>
> Hannes Frederic Sowa wrote:
> > On Wed, Feb 06, 2013 at 05:54:15PM +0100, Hannes Frederic Sowa wrote:
> >> On Thu, Feb 07, 2013 at 12:24:14AM +0900, YOSHIFUJI Hideaki wrote:
> >>> NAK. I think we should select routes via loopback device here.
> >>
> >> Will try your idea, thanks.
> >
> > Does this patch look reasonable? Btw. i am pleased to see this kind of
> > things work out as expected most of the time (addrtype checking etc. all
> > in place). :)
> >
>
> Well, I rethink of what "interface-local" means.
>
> It seems applications will join ff01::/16%eth0 instead of ff01::/16%lo.
> If so, your original patch seems better. My bad, sorry.
I was looking at getpeername et. al. where we should report the scope
back to the user. A common pattern is:
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin->sin6_scope_id = IP6CB(skb)->iif;
I propose to introduce something like 'bool ipv6_addr_intf_scoped(in6_addr)'
and let it check for ll addresses and interface scoped addresses.
^ permalink raw reply
* [PATCH v2] ipv6: don't accept multicast traffic with scop 0
From: Hannes Frederic Sowa @ 2013-02-10 15:35 UTC (permalink / raw)
To: netdev
v2:
a) moved before multicast source address check
b) changed comment to netdev style
Cc: Erik Hugne <erik.hugne@ericsson.com>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
net/ipv6/ip6_input.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 4ac5bf3..521d9fd 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -118,6 +118,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
ipv6_addr_loopback(&hdr->daddr))
goto err;
+ /* RFC4291 2.7
+ * Nodes must not originate a packet to a multicast address whose scop
+ * field contains the reserved value 0; if such a packet is received, it
+ * must be silently dropped.
+ */
+ if (ipv6_addr_is_multicast(&hdr->daddr) &&
+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0)
+ goto err;
+
/*
* RFC4291 2.7
* Multicast addresses must not be used as source addresses in IPv6
--
1.8.1.2
^ permalink raw reply related
* calexda/xgmac bug fixes
From: Ben Dooks @ 2013-02-10 15:38 UTC (permalink / raw)
To: netdev; +Cc: linux-arm-kernel, David S. Miller, Rob Herring
The following are a couple of bugs that I ran in to trying to test the
highbank architecture in big endian mode.
Branch available at:
git://git.baserock.org/delta/linux baserock/bjdooks/calxeda-xgmac
^ permalink raw reply
* [PATCH 1/2] net: calexdaxgmac: fix printing of hardware version
From: Ben Dooks @ 2013-02-10 15:38 UTC (permalink / raw)
To: netdev; +Cc: linux-arm-kernel, Ben Dooks, David S. Miller, Rob Herring
In-Reply-To: <1360510721-17860-1-git-send-email-ben.dooks@codethink.co.uk>
The current driver attempts to print netdev_info() before registering the
network device and allowing the name to be set. Change this print to be
after the network deviec has been registered, and thus has been allocated
a network device name.
Fix the following issue:
calxedaxgmac fff50000.ethernet (unregistered net_device): h/w version is 0x1012
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/net/ethernet/calxeda/xgmac.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index f7f0290..f91d9b2 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1715,9 +1715,6 @@ static int xgmac_probe(struct platform_device *pdev)
goto err_io;
}
- uid = readl(priv->base + XGMAC_VERSION);
- netdev_info(ndev, "h/w version is 0x%x\n", uid);
-
writel(0, priv->base + XGMAC_DMA_INTR_ENA);
ndev->irq = platform_get_irq(pdev, 0);
if (ndev->irq == -ENXIO) {
@@ -1771,6 +1768,9 @@ static int xgmac_probe(struct platform_device *pdev)
if (ret)
goto err_reg;
+ uid = readl(priv->base + XGMAC_VERSION);
+ netdev_info(ndev, "h/w version is 0x%x\n", uid);
+
return 0;
err_reg:
--
1.7.10.4
^ permalink raw reply related
* [PATCH 2/2] net: calexdaxgmac: fixup endian issues after __raw IO function change
From: Ben Dooks @ 2013-02-10 15:38 UTC (permalink / raw)
To: netdev; +Cc: linux-arm-kernel, Ben Dooks, David S. Miller, Rob Herring
In-Reply-To: <1360510721-17860-1-git-send-email-ben.dooks@codethink.co.uk>
When changing to __raw acccessors in 0ec6d343f7bcf9e0944aa9ff65287b987ec00c0f
("net: calxedaxgmac: use raw i/o accessors in rx and tx paths"), the driver
is now broken on big endian systems as the readl/writel have an implict
endian swap in them.
Change all the places where the __raw calls are used to correctly convert
the constants in big endian format to the little endian data that the
peripheral expects to see.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/net/ethernet/calxeda/xgmac.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index f91d9b2..96fd538 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1202,7 +1202,8 @@ static int xgmac_poll(struct napi_struct *napi, int budget)
if (work_done < budget) {
napi_complete(napi);
- __raw_writel(DMA_INTR_DEFAULT_MASK, priv->base + XGMAC_DMA_INTR_ENA);
+ __raw_writel(le32_to_cpu((__force __le32)DMA_INTR_DEFAULT_MASK),
+ priv->base + XGMAC_DMA_INTR_ENA);
}
return work_done;
}
@@ -1348,7 +1349,7 @@ static irqreturn_t xgmac_pmt_interrupt(int irq, void *dev_id)
void __iomem *ioaddr = priv->base;
intr_status = __raw_readl(ioaddr + XGMAC_INT_STAT);
- if (intr_status & XGMAC_INT_STAT_PMT) {
+ if (intr_status & le32_to_cpu((__force __le32)XGMAC_INT_STAT_PMT)) {
netdev_dbg(priv->dev, "received Magic frame\n");
/* clear the PMT bits 5 and 6 by reading the PMT */
readl(ioaddr + XGMAC_PMT);
@@ -1369,6 +1370,8 @@ static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
intr_status &= __raw_readl(priv->base + XGMAC_DMA_INTR_ENA);
__raw_writel(intr_status, priv->base + XGMAC_DMA_STATUS);
+ intr_status = (__force u32)cpu_to_le32(intr_status);
+
/* It displays the DMA process states (CSR5 register) */
/* ABNORMAL interrupts */
if (unlikely(intr_status & DMA_STATUS_AIS)) {
@@ -1403,7 +1406,8 @@ static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
/* TX/RX NORMAL interrupts */
if (intr_status & (DMA_STATUS_RI | DMA_STATUS_TU | DMA_STATUS_TI)) {
- __raw_writel(DMA_INTR_ABNORMAL, priv->base + XGMAC_DMA_INTR_ENA);
+ __raw_writel(le32_to_cpu((__force __le32)DMA_INTR_ABNORMAL),
+ priv->base + XGMAC_DMA_INTR_ENA);
napi_schedule(&priv->napi);
}
--
1.7.10.4
^ 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