* [PATCHv3 net-next 08/14] net: sch: api: add extack support in qdisc_get_rtab
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the function qdisc_get_rtab which is
a common used function in the tc subsystem. Callers which are interested
in the receiving error can assign extack to get a more detailed
information why qdisc_get_rtab failed.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
include/net/pkt_sched.h | 3 ++-
net/sched/act_police.c | 4 ++--
net/sched/sch_api.c | 9 +++++++--
net/sched/sch_cbq.c | 7 ++++---
net/sched/sch_htb.c | 6 ++++--
net/sched/sch_tbf.c | 6 ++++--
6 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 240469228851..a4f21c0b4a43 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -101,7 +101,8 @@ void qdisc_hash_del(struct Qdisc *q);
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
- struct nlattr *tab);
+ struct nlattr *tab,
+ struct netlink_ext_ack *extack);
void qdisc_put_rtab(struct qdisc_rate_table *tab);
void qdisc_put_stab(struct qdisc_size_table *tab);
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc);
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index bf483db993a1..95d3c9097b25 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -118,13 +118,13 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
police = to_police(*a);
if (parm->rate.rate) {
err = -ENOMEM;
- R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
+ R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE], NULL);
if (R_tab == NULL)
goto failure;
if (parm->peakrate.rate) {
P_tab = qdisc_get_rtab(&parm->peakrate,
- tb[TCA_POLICE_PEAKRATE]);
+ tb[TCA_POLICE_PEAKRATE], NULL);
if (P_tab == NULL)
goto failure;
}
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 1bf6da80c6e7..a58459569f35 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -393,13 +393,16 @@ static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab)
static struct qdisc_rate_table *qdisc_rtab_list;
struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
- struct nlattr *tab)
+ struct nlattr *tab,
+ struct netlink_ext_ack *extack)
{
struct qdisc_rate_table *rtab;
if (tab == NULL || r->rate == 0 || r->cell_log == 0 ||
- nla_len(tab) != TC_RTAB_SIZE)
+ nla_len(tab) != TC_RTAB_SIZE) {
+ NL_SET_ERR_MSG(extack, "Invalid rate table parameters for searching");
return NULL;
+ }
for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) &&
@@ -418,6 +421,8 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
r->linklayer = __detect_linklayer(r, rtab->data);
rtab->next = qdisc_rtab_list;
qdisc_rtab_list = rtab;
+ } else {
+ NL_SET_ERR_MSG(extack, "Failed to allocate new qdisc rate table");
}
return rtab;
}
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index bb7e4ccd7caf..79f081eb6bb0 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1156,7 +1156,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt,
r = nla_data(tb[TCA_CBQ_RATE]);
- q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB]);
+ q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB], extack);
if (!q->link.R_tab)
return -EINVAL;
@@ -1484,7 +1484,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (tb[TCA_CBQ_RATE]) {
rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
- tb[TCA_CBQ_RTAB]);
+ tb[TCA_CBQ_RTAB], extack);
if (rtab == NULL)
return -EINVAL;
}
@@ -1537,7 +1537,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT])
return -EINVAL;
- rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]);
+ rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB],
+ extack);
if (rtab == NULL)
return -EINVAL;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 65762d57a70d..51be1b756e4e 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1357,10 +1357,12 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
/* Keeping backward compatible with rate_table based iproute2 tc */
if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE)
- qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]));
+ qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB],
+ NULL));
if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE)
- qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]));
+ qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB],
+ NULL));
if (!cl) { /* new class */
struct Qdisc *new_q;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index db6bd23530d4..1ab53ff80f46 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -327,11 +327,13 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
qopt = nla_data(tb[TCA_TBF_PARMS]);
if (qopt->rate.linklayer == TC_LINKLAYER_UNAWARE)
qdisc_put_rtab(qdisc_get_rtab(&qopt->rate,
- tb[TCA_TBF_RTAB]));
+ tb[TCA_TBF_RTAB],
+ NULL));
if (qopt->peakrate.linklayer == TC_LINKLAYER_UNAWARE)
qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate,
- tb[TCA_TBF_PTAB]));
+ tb[TCA_TBF_PTAB],
+ NULL));
buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U);
mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U);
--
2.11.0
^ permalink raw reply related
* [PATCHv3 net-next 09/14] net: sch: api: add extack support in tcf_block_get
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the function tcf_block_get which is
a common used function in the tc subsystem. Callers which are interested
in the receiving error can assign extack to get a more detailed
information why tcf_block_get failed.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
include/net/pkt_cls.h | 6 ++++--
net/sched/cls_api.c | 13 +++++++++----
net/sched/sch_atm.c | 6 ++++--
net/sched/sch_cbq.c | 4 ++--
net/sched/sch_drr.c | 2 +-
net/sched/sch_dsmark.c | 2 +-
net/sched/sch_fq_codel.c | 2 +-
net/sched/sch_hfsc.c | 4 ++--
net/sched/sch_htb.c | 4 ++--
net/sched/sch_ingress.c | 8 +++++---
net/sched/sch_multiq.c | 2 +-
net/sched/sch_prio.c | 2 +-
net/sched/sch_qfq.c | 2 +-
net/sched/sch_sfb.c | 2 +-
net/sched/sch_sfq.c | 2 +-
15 files changed, 36 insertions(+), 25 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 0105445cab83..58bba9c769ea 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -39,9 +39,11 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
bool create);
void tcf_chain_put(struct tcf_chain *chain);
int tcf_block_get(struct tcf_block **p_block,
- struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q);
+ struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
+ struct netlink_ext_ack *extack);
int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
- struct tcf_block_ext_info *ei);
+ struct tcf_block_ext_info *ei,
+ struct netlink_ext_ack *extack);
void tcf_block_put(struct tcf_block *block);
void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
struct tcf_block_ext_info *ei);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 446ef956a79c..11bcf95ac467 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -282,20 +282,24 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
}
int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
- struct tcf_block_ext_info *ei)
+ struct tcf_block_ext_info *ei,
+ struct netlink_ext_ack *extack)
{
struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
struct tcf_chain *chain;
int err;
- if (!block)
+ if (!block) {
+ NL_SET_ERR_MSG(extack, "Memory allocation for block failed");
return -ENOMEM;
+ }
INIT_LIST_HEAD(&block->chain_list);
INIT_LIST_HEAD(&block->cb_list);
/* Create chain 0 by default, it has to be always present. */
chain = tcf_chain_create(block, 0);
if (!chain) {
+ NL_SET_ERR_MSG(extack, "Failed to create new tcf chain");
err = -ENOMEM;
goto err_chain_create;
}
@@ -322,7 +326,8 @@ static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv)
}
int tcf_block_get(struct tcf_block **p_block,
- struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q)
+ struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
+ struct netlink_ext_ack *extack)
{
struct tcf_block_ext_info ei = {
.chain_head_change = tcf_chain_head_change_dflt,
@@ -330,7 +335,7 @@ int tcf_block_get(struct tcf_block **p_block,
};
WARN_ON(!p_filter_chain);
- return tcf_block_get_ext(p_block, q, &ei);
+ return tcf_block_get_ext(p_block, q, &ei, extack);
}
EXPORT_SYMBOL(tcf_block_get);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 8972ab72cda5..493d5c25d83a 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -283,7 +283,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
goto err_out;
}
- error = tcf_block_get(&flow->block, &flow->filter_list, sch);
+ error = tcf_block_get(&flow->block, &flow->filter_list, sch,
+ extack);
if (error) {
kfree(flow);
goto err_out;
@@ -550,7 +551,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt,
p->link.q = &noop_qdisc;
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
- err = tcf_block_get(&p->link.block, &p->link.filter_list, sch);
+ err = tcf_block_get(&p->link.block, &p->link.filter_list, sch,
+ extack);
if (err)
return err;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 79f081eb6bb0..248ea26997b9 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1160,7 +1160,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt,
if (!q->link.R_tab)
return -EINVAL;
- err = tcf_block_get(&q->link.block, &q->link.filter_list, sch);
+ err = tcf_block_get(&q->link.block, &q->link.filter_list, sch, extack);
if (err)
goto put_rtab;
@@ -1576,7 +1576,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (cl == NULL)
goto failure;
- err = tcf_block_get(&cl->block, &cl->filter_list, sch);
+ err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
if (err) {
kfree(cl);
return err;
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 30e9cba54ddb..9dfff065e27d 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -417,7 +417,7 @@ static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
struct drr_sched *q = qdisc_priv(sch);
int err;
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
err = qdisc_class_hash_init(&q->clhash);
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 92a36aa4c713..63f523b5e282 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -348,7 +348,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt,
if (!opt)
goto errout;
- err = tcf_block_get(&p->block, &p->filter_list, sch);
+ err = tcf_block_get(&p->block, &p->filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 06e5360c54d8..22fa13cf5d8b 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -484,7 +484,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt,
return err;
}
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 7f6a06ac4b9f..9ae288fcbed8 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1034,7 +1034,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (cl == NULL)
return -ENOBUFS;
- err = tcf_block_get(&cl->block, &cl->filter_list, sch);
+ err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
if (err) {
kfree(cl);
return err;
@@ -1409,7 +1409,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
return err;
q->eligible = RB_ROOT;
- err = tcf_block_get(&q->root.block, &q->root.filter_list, sch);
+ err = tcf_block_get(&q->root.block, &q->root.filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 51be1b756e4e..54e1f860f1e5 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1032,7 +1032,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt,
if (!opt)
return -EINVAL;
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
@@ -1397,7 +1397,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if (!cl)
goto failure;
- err = tcf_block_get(&cl->block, &cl->filter_list, sch);
+ err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
if (err) {
kfree(cl);
goto failure;
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index 17fa8969f7e7..0712fb3bcd5a 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -76,7 +76,7 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
q->block_info.chain_head_change = clsact_chain_head_change;
q->block_info.chain_head_change_priv = &q->miniqp;
- err = tcf_block_get_ext(&q->block, sch, &q->block_info);
+ err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
if (err)
return err;
@@ -182,7 +182,8 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
q->ingress_block_info.chain_head_change = clsact_chain_head_change;
q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
- err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info);
+ err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info,
+ extack);
if (err)
return err;
@@ -192,7 +193,8 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
q->egress_block_info.chain_head_change = clsact_chain_head_change;
q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
- err = tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info);
+ err = tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info,
+ extack);
if (err)
goto err_egress_block_get;
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 177d86de4b32..35cbaf8bd96a 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -248,7 +248,7 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt,
if (!opt)
return -EINVAL;
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 8fbd65661d77..502352762f03 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -215,7 +215,7 @@ static int prio_init(struct Qdisc *sch, struct nlattr *opt,
if (!opt)
return -EINVAL;
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index 7ec893f770d2..6ab58509cf49 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -1424,7 +1424,7 @@ static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
int i, j, err;
u32 max_cl_shift, maxbudg_shift, max_classes;
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index 1a33d6c3ac42..a1a11ded8e4f 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -556,7 +556,7 @@ static int sfb_init(struct Qdisc *sch, struct nlattr *opt,
struct sfb_sched_data *q = qdisc_priv(sch);
int err;
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 7a217be39f2a..2f2678197760 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -731,7 +731,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt,
q->sch = sch;
timer_setup(&q->perturb_timer, sfq_perturbation, TIMER_DEFERRABLE);
- err = tcf_block_get(&q->block, &q->filter_list, sch);
+ err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
if (err)
return err;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 net-next 10/14] net: sch: api: add extack support in qdisc_alloc
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the function qdisc_alloc which is
a common used function in the tc subsystem. Callers which are interested
in the receiving error can assign extack to get a more detailed
information why qdisc_alloc failed.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
include/net/sch_generic.h | 3 ++-
net/sched/sch_api.c | 2 +-
net/sched/sch_generic.c | 6 ++++--
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 2ea04863ea34..1dbfbec00050 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -470,7 +470,8 @@ void qdisc_destroy(struct Qdisc *qdisc);
void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n,
unsigned int len);
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
- const struct Qdisc_ops *ops);
+ const struct Qdisc_ops *ops,
+ struct netlink_ext_ack *extack);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops, u32 parentid);
void __qdisc_calculate_pkt_len(struct sk_buff *skb,
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index a58459569f35..fd3960ff0fe4 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1050,7 +1050,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
goto err_out;
}
- sch = qdisc_alloc(dev_queue, ops);
+ sch = qdisc_alloc(dev_queue, ops, extack);
if (IS_ERR(sch)) {
err = PTR_ERR(sch);
goto err_out2;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 5cdafe88b902..01457b27d36e 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -749,7 +749,8 @@ static struct lock_class_key qdisc_tx_busylock;
static struct lock_class_key qdisc_running_key;
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
- const struct Qdisc_ops *ops)
+ const struct Qdisc_ops *ops,
+ struct netlink_ext_ack *extack)
{
void *p;
struct Qdisc *sch;
@@ -758,6 +759,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
struct net_device *dev;
if (!dev_queue) {
+ NL_SET_ERR_MSG(extack, "No device queue given");
err = -EINVAL;
goto errout;
}
@@ -829,7 +831,7 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
if (!try_module_get(ops->owner))
return NULL;
- sch = qdisc_alloc(dev_queue, ops);
+ sch = qdisc_alloc(dev_queue, ops, NULL);
if (IS_ERR(sch)) {
module_put(ops->owner);
return NULL;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 net-next 11/14] net: sch: api: add extack support in qdisc_create_dflt
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the function qdisc_create_dflt which is
a common used function in the tc subsystem. Callers which are interested
in the receiving error can assign extack to get a more detailed
information why qdisc_create_dflt failed. The function qdisc_create_dflt will
also call an init callback which can fail by any per-qdisc specfic handling.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
include/net/pkt_sched.h | 3 ++-
include/net/sch_generic.h | 3 ++-
net/sched/sch_atm.c | 5 +++--
net/sched/sch_cbq.c | 9 +++++----
net/sched/sch_drr.c | 7 ++++---
net/sched/sch_dsmark.c | 5 +++--
net/sched/sch_fifo.c | 6 ++++--
net/sched/sch_generic.c | 15 +++++++++------
net/sched/sch_hfsc.c | 8 ++++----
net/sched/sch_htb.c | 9 +++++----
net/sched/sch_mq.c | 3 ++-
net/sched/sch_mqprio.c | 2 +-
net/sched/sch_multiq.c | 2 +-
net/sched/sch_prio.c | 3 ++-
net/sched/sch_qfq.c | 8 ++++----
net/sched/sch_red.c | 3 ++-
net/sched/sch_sfb.c | 2 +-
net/sched/sch_tbf.c | 3 ++-
18 files changed, 56 insertions(+), 40 deletions(-)
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index a4f21c0b4a43..e2c75f52557b 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -89,7 +89,8 @@ extern struct Qdisc_ops pfifo_head_drop_qdisc_ops;
int fifo_set_limit(struct Qdisc *q, unsigned int limit);
struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
- unsigned int limit);
+ unsigned int limit,
+ struct netlink_ext_ack *extack);
int register_qdisc(struct Qdisc_ops *qops);
int unregister_qdisc(struct Qdisc_ops *qops);
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 1dbfbec00050..e4ef4f6e7baf 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -473,7 +473,8 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops,
struct netlink_ext_ack *extack);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
- const struct Qdisc_ops *ops, u32 parentid);
+ const struct Qdisc_ops *ops, u32 parentid,
+ struct netlink_ext_ack *extack);
void __qdisc_calculate_pkt_len(struct sk_buff *skb,
const struct qdisc_size_table *stab);
int skb_do_redirect(struct sk_buff *);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 493d5c25d83a..cd49afca9617 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -290,7 +290,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
goto err_out;
}
- flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
+ flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid,
+ extack);
if (!flow->q)
flow->q = &noop_qdisc;
pr_debug("atm_tc_change: qdisc %p\n", flow->q);
@@ -546,7 +547,7 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt,
INIT_LIST_HEAD(&p->link.list);
list_add(&p->link.list, &p->flows);
p->link.q = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, sch->handle);
+ &pfifo_qdisc_ops, sch->handle, extack);
if (!p->link.q)
p->link.q = &noop_qdisc;
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 248ea26997b9..efe5bf15b031 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1172,7 +1172,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt,
q->link.common.classid = sch->handle;
q->link.qdisc = sch;
q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- sch->handle);
+ sch->handle, NULL);
if (!q->link.q)
q->link.q = &noop_qdisc;
else
@@ -1376,8 +1376,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
struct cbq_class *cl = (struct cbq_class *)arg;
if (new == NULL) {
- new = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, cl->common.classid);
+ new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ cl->common.classid, extack);
if (new == NULL)
return -ENOBUFS;
}
@@ -1596,7 +1596,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
cl->R_tab = rtab;
rtab = NULL;
- cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
+ cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid,
+ NULL);
if (!cl->q)
cl->q = &noop_qdisc;
else
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 9dfff065e27d..bf638ce57c50 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -114,7 +114,8 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->common.classid = classid;
cl->quantum = quantum;
cl->qdisc = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, classid);
+ &pfifo_qdisc_ops, classid,
+ NULL);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
else
@@ -209,8 +210,8 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
struct drr_class *cl = (struct drr_class *)arg;
if (new == NULL) {
- new = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, cl->common.classid);
+ new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ cl->common.classid, NULL);
if (new == NULL)
new = &noop_qdisc;
}
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 63f523b5e282..049714c57075 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -71,7 +71,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- sch->handle);
+ sch->handle, NULL);
if (new == NULL)
new = &noop_qdisc;
}
@@ -381,7 +381,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt,
p->default_index = default_index;
p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
- p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle);
+ p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle,
+ NULL);
if (p->q == NULL)
p->q = &noop_qdisc;
else
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index c65f23c70f40..24893d3b5d22 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -166,12 +166,14 @@ int fifo_set_limit(struct Qdisc *q, unsigned int limit)
EXPORT_SYMBOL(fifo_set_limit);
struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
- unsigned int limit)
+ unsigned int limit,
+ struct netlink_ext_ack *extack)
{
struct Qdisc *q;
int err = -ENOMEM;
- q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1));
+ q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1),
+ extack);
if (q) {
err = fifo_set_limit(q, limit);
if (err < 0) {
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 01457b27d36e..020db5e57290 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -824,21 +824,24 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops,
- unsigned int parentid)
+ unsigned int parentid,
+ struct netlink_ext_ack *extack)
{
struct Qdisc *sch;
- if (!try_module_get(ops->owner))
+ if (!try_module_get(ops->owner)) {
+ NL_SET_ERR_MSG(extack, "Failed to increase module reference counter");
return NULL;
+ }
- sch = qdisc_alloc(dev_queue, ops, NULL);
+ sch = qdisc_alloc(dev_queue, ops, extack);
if (IS_ERR(sch)) {
module_put(ops->owner);
return NULL;
}
sch->parent = parentid;
- if (!ops->init || ops->init(sch, NULL, NULL) == 0)
+ if (!ops->init || ops->init(sch, NULL, extack) == 0)
return sch;
qdisc_destroy(sch);
@@ -950,7 +953,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
if (dev->priv_flags & IFF_NO_QUEUE)
ops = &noqueue_qdisc_ops;
- qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT);
+ qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL);
if (!qdisc) {
netdev_info(dev, "activation failed\n");
return;
@@ -973,7 +976,7 @@ static void attach_default_qdiscs(struct net_device *dev)
dev->qdisc = txq->qdisc_sleeping;
qdisc_refcount_inc(dev->qdisc);
} else {
- qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT);
+ qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT, NULL);
if (qdisc) {
dev->qdisc = qdisc;
qdisc->ops->attach(qdisc);
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 9ae288fcbed8..3ae9877ea205 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1062,8 +1062,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->cl_common.classid = classid;
cl->sched = q;
cl->cl_parent = parent;
- cl->qdisc = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, classid);
+ cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ classid, NULL);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
else
@@ -1185,7 +1185,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
return -EINVAL;
if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- cl->cl_common.classid);
+ cl->cl_common.classid, NULL);
if (new == NULL)
new = &noop_qdisc;
}
@@ -1416,7 +1416,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
q->root.cl_common.classid = sch->handle;
q->root.sched = q;
q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- sch->handle);
+ sch->handle, NULL);
if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc;
else
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 54e1f860f1e5..1ea9846cc6ce 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1180,7 +1180,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
return -EINVAL;
if (new == NULL &&
(new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- cl->common.classid)) == NULL)
+ cl->common.classid, extack)) == NULL)
return -ENOBUFS;
*old = qdisc_replace(sch, new, &cl->un.leaf.q);
@@ -1290,7 +1290,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
if (!cl->level && htb_parent_last_child(cl)) {
new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- cl->parent->common.classid);
+ cl->parent->common.classid,
+ NULL);
last_child = 1;
}
@@ -1426,8 +1427,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
* so that can't be used inside of sch_tree_lock
* -- thanks to Karlis Peisenieks
*/
- new_q = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, classid);
+ new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ classid, NULL);
sch_tree_lock(sch);
if (parent && !parent->level) {
unsigned int qlen = parent->un.leaf.q->q.qlen;
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
index 50292e470432..f062a18e9162 100644
--- a/net/sched/sch_mq.c
+++ b/net/sched/sch_mq.c
@@ -61,7 +61,8 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt,
dev_queue = netdev_get_tx_queue(dev, ntx);
qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx),
TC_H_MAKE(TC_H_MAJ(sch->handle),
- TC_H_MIN(ntx + 1)));
+ TC_H_MIN(ntx + 1)),
+ extack);
if (!qdisc)
return -ENOMEM;
priv->qdiscs[ntx] = qdisc;
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index 29071cf329f3..0e9d761cdd80 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -230,7 +230,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt,
qdisc = qdisc_create_dflt(dev_queue,
get_default_qdisc_ops(dev, i),
TC_H_MAKE(TC_H_MAJ(sch->handle),
- TC_H_MIN(i + 1)));
+ TC_H_MIN(i + 1)), extack);
if (!qdisc)
return -ENOMEM;
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 35cbaf8bd96a..1da7ea8de0ad 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -216,7 +216,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
child = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops,
TC_H_MAKE(sch->handle,
- i + 1));
+ i + 1), extack);
if (child) {
sch_tree_lock(sch);
old = q->queues[i];
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 502352762f03..fe1510eb111f 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -176,7 +176,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
/* Before commit, make sure we can allocate all new qdiscs */
for (i = oldbands; i < qopt->bands; i++) {
queues[i] = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
- TC_H_MAKE(sch->handle, i + 1));
+ TC_H_MAKE(sch->handle, i + 1),
+ extack);
if (!queues[i]) {
while (i > oldbands)
qdisc_destroy(queues[--i]);
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index 6ab58509cf49..bb1a9c11fc54 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -480,8 +480,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->common.classid = classid;
cl->deficit = lmax;
- cl->qdisc = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, classid);
+ cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ classid, NULL);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
@@ -601,8 +601,8 @@ static int qfq_graft_class(struct Qdisc *sch, unsigned long arg,
struct qfq_class *cl = (struct qfq_class *)arg;
if (new == NULL) {
- new = qdisc_create_dflt(sch->dev_queue,
- &pfifo_qdisc_ops, cl->common.classid);
+ new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
+ cl->common.classid, NULL);
if (new == NULL)
new = &noop_qdisc;
}
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 19616fa0a1a8..094fcf072e78 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -217,7 +217,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt,
return -EINVAL;
if (ctl->limit > 0) {
- child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit);
+ child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit,
+ extack);
if (IS_ERR(child))
return PTR_ERR(child);
}
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index a1a11ded8e4f..7cbdad8419b7 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -513,7 +513,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
if (limit == 0)
limit = qdisc_dev(sch)->tx_queue_len;
- child = fifo_create_dflt(sch, &pfifo_qdisc_ops, limit);
+ child = fifo_create_dflt(sch, &pfifo_qdisc_ops, limit, extack);
if (IS_ERR(child))
return PTR_ERR(child);
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 1ab53ff80f46..83e76d046993 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -386,7 +386,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
if (err)
goto done;
} else if (qopt->limit > 0) {
- child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
+ child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit,
+ extack);
if (IS_ERR(child)) {
err = PTR_ERR(child);
goto done;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 net-next 12/14] net: sch: sch_cbq: add extack support
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the cbq qdisc implementation by
adding NL_SET_ERR_MSG in validation of user input.
Also it serves to illustrate a use case of how the infrastructure ops
api changes are to be used by individual qdiscs.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
net/sched/sch_cbq.c | 46 ++++++++++++++++++++++++++++++++++------------
1 file changed, 34 insertions(+), 12 deletions(-)
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index efe5bf15b031..f42025d53cfe 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1144,15 +1144,19 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt,
hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
q->delay_timer.function = cbq_undelay;
- if (!opt)
+ if (!opt) {
+ NL_SET_ERR_MSG(extack, "CBQ options are required for this operation");
return -EINVAL;
+ }
- err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL);
+ err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, extack);
if (err < 0)
return err;
- if (!tb[TCA_CBQ_RTAB] || !tb[TCA_CBQ_RATE])
+ if (!tb[TCA_CBQ_RTAB] || !tb[TCA_CBQ_RATE]) {
+ NL_SET_ERR_MSG(extack, "Rate specification missing or incomplete");
return -EINVAL;
+ }
r = nla_data(tb[TCA_CBQ_RATE]);
@@ -1462,24 +1466,32 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
struct cbq_class *parent;
struct qdisc_rate_table *rtab = NULL;
- if (!opt)
+ if (!opt) {
+ NL_SET_ERR_MSG(extack, "Mandatory qdisc options missing");
return -EINVAL;
+ }
- err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL);
+ err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, extack);
if (err < 0)
return err;
- if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE])
+ if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE]) {
+ NL_SET_ERR_MSG(extack, "Neither overlimit strategy nor policing attributes can be used for changing class params");
return -EOPNOTSUPP;
+ }
if (cl) {
/* Check parent */
if (parentid) {
if (cl->tparent &&
- cl->tparent->common.classid != parentid)
+ cl->tparent->common.classid != parentid) {
+ NL_SET_ERR_MSG(extack, "Invalid parent id");
return -EINVAL;
- if (!cl->tparent && parentid != TC_H_ROOT)
+ }
+ if (!cl->tparent && parentid != TC_H_ROOT) {
+ NL_SET_ERR_MSG(extack, "Parent must be root");
return -EINVAL;
+ }
}
if (tb[TCA_CBQ_RATE]) {
@@ -1496,6 +1508,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
if (err) {
+ NL_SET_ERR_MSG(extack, "Failed to replace specified rate estimator");
qdisc_put_rtab(rtab);
return err;
}
@@ -1534,8 +1547,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (parentid == TC_H_ROOT)
return -EINVAL;
- if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT])
+ if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT]) {
+ NL_SET_ERR_MSG(extack, "One of the following attributes MUST be specified: WRR, rate or link sharing");
return -EINVAL;
+ }
rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB],
extack);
@@ -1545,8 +1560,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (classid) {
err = -EINVAL;
if (TC_H_MAJ(classid ^ sch->handle) ||
- cbq_class_lookup(q, classid))
+ cbq_class_lookup(q, classid)) {
+ NL_SET_ERR_MSG(extack, "Specified class not found");
goto failure;
+ }
} else {
int i;
classid = TC_H_MAKE(sch->handle, 0x8000);
@@ -1558,8 +1575,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
break;
}
err = -ENOSR;
- if (i >= 0x8000)
+ if (i >= 0x8000) {
+ NL_SET_ERR_MSG(extack, "Unable to generate classid");
goto failure;
+ }
classid = classid|q->hgenerator;
}
@@ -1567,8 +1586,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (parentid) {
parent = cbq_class_lookup(q, parentid);
err = -EINVAL;
- if (!parent)
+ if (!parent) {
+ NL_SET_ERR_MSG(extack, "Failed to find parentid");
goto failure;
+ }
}
err = -ENOBUFS;
@@ -1588,6 +1609,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
if (err) {
+ NL_SET_ERR_MSG(extack, "Couldn't create new estimator");
tcf_block_put(cl->block);
kfree(cl);
goto failure;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 net-next 13/14] net: sch: sch_cbs: add extack support
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the cbs qdisc implementation by
adding NL_SET_ERR_MSG in validation of user input.
Also it serves to illustrate a use case of how the infrastructure ops
api changes are to be used by individual qdiscs.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
net/sched/sch_cbs.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c
index 8bf6e163d29c..cdd96b9a27bc 100644
--- a/net/sched/sch_cbs.c
+++ b/net/sched/sch_cbs.c
@@ -219,14 +219,17 @@ static void cbs_disable_offload(struct net_device *dev,
}
static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q,
- const struct tc_cbs_qopt *opt)
+ const struct tc_cbs_qopt *opt,
+ struct netlink_ext_ack *extack)
{
const struct net_device_ops *ops = dev->netdev_ops;
struct tc_cbs_qopt_offload cbs = { };
int err;
- if (!ops->ndo_setup_tc)
+ if (!ops->ndo_setup_tc) {
+ NL_SET_ERR_MSG(extack, "Specified device does not support cbs offload");
return -EOPNOTSUPP;
+ }
cbs.queue = q->queue;
@@ -237,8 +240,10 @@ static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q,
cbs.sendslope = opt->sendslope;
err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_CBS, &cbs);
- if (err < 0)
+ if (err < 0) {
+ NL_SET_ERR_MSG(extack, "Specified device failed to setup cbs hardware offload");
return err;
+ }
q->enqueue = cbs_enqueue_offload;
q->dequeue = cbs_dequeue_offload;
@@ -255,12 +260,14 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt,
struct tc_cbs_qopt *qopt;
int err;
- err = nla_parse_nested(tb, TCA_CBS_MAX, opt, cbs_policy, NULL);
+ err = nla_parse_nested(tb, TCA_CBS_MAX, opt, cbs_policy, extack);
if (err < 0)
return err;
- if (!tb[TCA_CBS_PARMS])
+ if (!tb[TCA_CBS_PARMS]) {
+ NL_SET_ERR_MSG(extack, "Missing CBS parameter which are mandatory");
return -EINVAL;
+ }
qopt = nla_data(tb[TCA_CBS_PARMS]);
@@ -277,7 +284,7 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt,
cbs_disable_offload(dev, q);
} else {
- err = cbs_enable_offload(dev, q, qopt);
+ err = cbs_enable_offload(dev, q, qopt, extack);
if (err < 0)
return err;
}
@@ -298,8 +305,10 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
struct cbs_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
- if (!opt)
+ if (!opt) {
+ NL_SET_ERR_MSG(extack, "Missing CBS qdisc options which are mandatory");
return -EINVAL;
+ }
q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
--
2.11.0
^ permalink raw reply related
* [PATCHv3 net-next 14/14] net: sch: sch_drr: add extack support
From: Alexander Aring @ 2017-12-18 22:45 UTC (permalink / raw)
To: jhs
Cc: xiyou.wangcong, jiri, davem, netdev, kernel, Alexander Aring,
David Ahern
In-Reply-To: <20171218224513.29836-1-aring@mojatatu.com>
This patch adds extack support for the drr qdisc implementation by
adding NL_SET_ERR_MSG in validation of user input.
Also it serves to illustrate a use case of how the infrastructure ops
api changes are to be used by individual qdiscs.
Cc: David Ahern <dsahern@gmail.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
---
net/sched/sch_drr.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index bf638ce57c50..e0b0cf8a9939 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -74,17 +74,21 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
u32 quantum;
int err;
- if (!opt)
+ if (!opt) {
+ NL_SET_ERR_MSG(extack, "DRR options are required for this operation");
return -EINVAL;
+ }
- err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy, NULL);
+ err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy, extack);
if (err < 0)
return err;
if (tb[TCA_DRR_QUANTUM]) {
quantum = nla_get_u32(tb[TCA_DRR_QUANTUM]);
- if (quantum == 0)
+ if (quantum == 0) {
+ NL_SET_ERR_MSG(extack, "Specified DRR quantum cannot be zero");
return -EINVAL;
+ }
} else
quantum = psched_mtu(qdisc_dev(sch));
@@ -95,8 +99,10 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
NULL,
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
- if (err)
+ if (err) {
+ NL_SET_ERR_MSG(extack, "Failed to replace estimator");
return err;
+ }
}
sch_tree_lock(sch);
@@ -127,6 +133,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
if (err) {
+ NL_SET_ERR_MSG(extack, "Failed to replace estimator");
qdisc_destroy(cl->qdisc);
kfree(cl);
return err;
@@ -179,8 +186,10 @@ static struct tcf_block *drr_tcf_block(struct Qdisc *sch, unsigned long cl,
{
struct drr_sched *q = qdisc_priv(sch);
- if (cl)
+ if (cl) {
+ NL_SET_ERR_MSG(extack, "DRR classid must be zero");
return NULL;
+ }
return q->block;
}
--
2.11.0
^ permalink raw reply related
* [PATCH ethtool v2] ethtool: Support for FEC encoding control
From: Jakub Kicinski @ 2017-12-18 22:57 UTC (permalink / raw)
To: John W. Linville
Cc: netdev, oss-drivers, Dustin Byford, Vidya Sagar Ravipati,
Dirk van der Merwe
From: Dustin Byford <dustin@cumulusnetworks.com>
As FEC settings and different FEC modes are mandatory
and configurable across various interfaces of 25G/50G/100G/40G,
the lack of FEC encoding control and reporting today is a source
for interoperability issues for many vendors
set-fec/show-fec option(s) are designed to provide control and report
the FEC encoding on the link.
$ethtool --set-fec swp1 encoding [off | RS | BaseR | auto]
Encoding: Types of encoding
Off : Turning off FEC
RS : Force RS-FEC encoding
BaseR : Force BaseR encoding
Auto : Default FEC settings for drivers, and would represent
asking the hardware to essentially go into a best effort mode.
Here are a few examples of what we would expect if encoding=auto:
- if autoneg is on, we are expecting FEC to be negotiated as on or off
as long as protocol supports it
- if the hardware is capable of detecting the FEC encoding on it's
receiver it will reconfigure its encoder to match
- in absence of the above, the configuration would be set to IEEE
defaults.
>From our understanding, this is essentially what most hardware/driver
combinations are doing today in the absence of a way for users to
control the behavior.
$ethtool --show-fec swp1
FEC parameters for swp1:
FEC encodings: RS
ethtool devname output:
$ethtool swp1
Settings for swp1:
root@hpe-7712-03:~# ethtool swp18
Settings for swp18:
Supported ports: [ FIBRE ]
Supported link modes: 40000baseCR4/Full
40000baseSR4/Full
40000baseLR4/Full
100000baseSR4/Full
100000baseCR4/Full
100000baseLR4_ER4/Full
Supported pause frame use: No
Supports auto-negotiation: Yes
Supported FEC modes: [RS | BaseR | None | Not reported]
Advertised link modes: Not reported
Advertised pause frame use: No
Advertised auto-negotiation: No
Advertised FEC modes: [RS | BaseR | None | Not reported]
Speed: 100000Mb/s
Duplex: Full
Port: FIBRE
PHYAD: 106
Transceiver: internal
Auto-negotiation: off
Link detected: yes
Signed-off-by: Vidya Sagar Ravipati <vidya.chowdary@gmail.com>
Signed-off-by: Dustin Byford <dustin@cumulusnetworks.com>
[code style + man page edits + commit message update]
Signed-off-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
---
v2:
- don't break lines after opening parnes.
ethtool.8.in | 31 ++++++++++++++++
ethtool.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 150 insertions(+)
diff --git a/ethtool.8.in b/ethtool.8.in
index 7ca8bfe43607..9573ffdc985d 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -378,6 +378,13 @@ ethtool \- query or control network driver and hardware settings
.RB [ ap-shared ]
.RB [ dedicated ]
.RB [ all ]
+.HP
+.B ethtool \-\-show\-fec
+.I devname
+.HP
+.B ethtool \-\-set\-fec
+.I devname
+.B4 encoding auto off rs baser
.
.\" Adjust lines (i.e. full justification) and hyphenate.
.ad
@@ -1070,6 +1077,30 @@ All components dedicated to this interface
.B all
All components used by this interface, even if shared
.RE
+.TP
+.B \-\-show\-fec
+Queries the specified network device for its support of Forward Error Correction.
+.TP
+.B \-\-set\-fec
+Configures Forward Error Correction for the specified network device.
+
+Forward Error Correction modes selected by a user are expected to be persisted
+after any hotplug events. If a module is swapped that does not support the
+current FEC mode, the driver or firmware must take the link down
+administratively and report the problem in the system logs for users to correct.
+.RS 4
+.TP
+.A4 encoding auto off rs baser
+Sets the FEC encoding for the device.
+.TS
+nokeep;
+lB l.
+auto Use the driver's default encoding
+off Turn off FEC
+RS Force RS-FEC encoding
+BaseR Force BaseR encoding
+.TE
+.RE
.SH BUGS
Not supported (in part or whole) on all network drivers.
.SH AUTHOR
diff --git a/ethtool.c b/ethtool.c
index 488f6bfb8378..79c076e42c6e 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -542,6 +542,9 @@ static void init_global_link_mode_masks(void)
ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
ETHTOOL_LINK_MODE_Backplane_BIT,
+ ETHTOOL_LINK_MODE_FEC_NONE_BIT,
+ ETHTOOL_LINK_MODE_FEC_RS_BIT,
+ ETHTOOL_LINK_MODE_FEC_BASER_BIT,
};
unsigned int i;
@@ -689,6 +692,7 @@ static void dump_link_caps(const char *prefix, const char *an_prefix,
};
int indent;
int did1, new_line_pend, i;
+ int fecreported = 0;
/* Indent just like the separate functions used to */
indent = strlen(prefix) + 14;
@@ -740,6 +744,26 @@ static void dump_link_caps(const char *prefix, const char *an_prefix,
fprintf(stdout, "Yes\n");
else
fprintf(stdout, "No\n");
+
+ fprintf(stdout, " %s FEC modes:", prefix);
+ if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
+ mask)) {
+ fprintf(stdout, " None");
+ fecreported = 1;
+ }
+ if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
+ mask)) {
+ fprintf(stdout, " BaseR");
+ fecreported = 1;
+ }
+ if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
+ mask)) {
+ fprintf(stdout, " RS");
+ fecreported = 1;
+ }
+ if (!fecreported)
+ fprintf(stdout, " Not reported");
+ fprintf(stdout, "\n");
}
}
@@ -1562,6 +1586,20 @@ static void dump_eeecmd(struct ethtool_eee *ep)
dump_link_caps("Link partner advertised EEE", "", link_mode, 1);
}
+static void dump_fec(u32 fec)
+{
+ if (fec & ETHTOOL_FEC_NONE)
+ fprintf(stdout, " None");
+ if (fec & ETHTOOL_FEC_AUTO)
+ fprintf(stdout, " Auto");
+ if (fec & ETHTOOL_FEC_OFF)
+ fprintf(stdout, " Off");
+ if (fec & ETHTOOL_FEC_BASER)
+ fprintf(stdout, " BaseR");
+ if (fec & ETHTOOL_FEC_RS)
+ fprintf(stdout, " RS");
+}
+
#define N_SOTS 7
static char *so_timestamping_labels[N_SOTS] = {
@@ -4812,6 +4850,84 @@ static int do_set_phy_tunable(struct cmd_context *ctx)
return err;
}
+static int fecmode_str_to_type(const char *str)
+{
+ int fecmode = 0;
+
+ if (!str)
+ return fecmode;
+
+ if (!strcasecmp(str, "auto"))
+ fecmode |= ETHTOOL_FEC_AUTO;
+ else if (!strcasecmp(str, "off"))
+ fecmode |= ETHTOOL_FEC_OFF;
+ else if (!strcasecmp(str, "rs"))
+ fecmode |= ETHTOOL_FEC_RS;
+ else if (!strcasecmp(str, "baser"))
+ fecmode |= ETHTOOL_FEC_BASER;
+
+ return fecmode;
+}
+
+static int do_gfec(struct cmd_context *ctx)
+{
+ struct ethtool_fecparam feccmd = { 0 };
+ int rv;
+
+ if (ctx->argc != 0)
+ exit_bad_args();
+
+ feccmd.cmd = ETHTOOL_GFECPARAM;
+ rv = send_ioctl(ctx, &feccmd);
+ if (rv != 0) {
+ perror("Cannot get FEC settings");
+ return rv;
+ }
+
+ fprintf(stdout, "FEC parameters for %s:\n", ctx->devname);
+ fprintf(stdout, "Configured FEC encodings:");
+ dump_fec(feccmd.fec);
+ fprintf(stdout, "\n");
+
+ fprintf(stdout, "Active FEC encoding:");
+ dump_fec(feccmd.active_fec);
+ fprintf(stdout, "\n");
+
+ return 0;
+}
+
+static int do_sfec(struct cmd_context *ctx)
+{
+ char *fecmode_str = NULL;
+ struct ethtool_fecparam feccmd;
+ struct cmdline_info cmdline_fec[] = {
+ { "encoding", CMDL_STR, &fecmode_str, &feccmd.fec},
+ };
+ int changed;
+ int fecmode;
+ int rv;
+
+ parse_generic_cmdline(ctx, &changed, cmdline_fec,
+ ARRAY_SIZE(cmdline_fec));
+
+ if (!fecmode_str)
+ exit_bad_args();
+
+ fecmode = fecmode_str_to_type(fecmode_str);
+ if (!fecmode)
+ exit_bad_args();
+
+ feccmd.cmd = ETHTOOL_SFECPARAM;
+ feccmd.fec = fecmode;
+ rv = send_ioctl(ctx, &feccmd);
+ if (rv != 0) {
+ perror("Cannot set FEC settings");
+ return rv;
+ }
+
+ return 0;
+}
+
#ifndef TEST_ETHTOOL
int send_ioctl(struct cmd_context *ctx, void *cmd)
{
@@ -5000,6 +5116,9 @@ static const struct option {
" [ ap-shared ]\n"
" [ dedicated ]\n"
" [ all ]\n"},
+ { "--show-fec", 1, do_gfec, "Show FEC settings"},
+ { "--set-fec", 1, do_sfec, "Set FEC settings",
+ " [ encoding auto|off|rs|baser ]\n"},
{ "-h|--help", 0, show_usage, "Show this help" },
{ "--version", 0, do_version, "Show version number" },
{}
--
2.15.1
^ permalink raw reply related
* [PATCH bpf-next] selftests/bpf: add netdevsim to config
From: Jakub Kicinski @ 2017-12-18 23:11 UTC (permalink / raw)
To: daniel, alexei.starovoitov; +Cc: netdev, oss-drivers, Jakub Kicinski
BPF offload tests (test_offload.py) will require netdevsim
to be built, add it to config.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/testing/selftests/bpf/config | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index 9d4897317c77..983dd25d49f4 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -4,3 +4,4 @@ CONFIG_NET_CLS_BPF=m
CONFIG_BPF_EVENTS=y
CONFIG_TEST_BPF=m
CONFIG_CGROUP_BPF=y
+CONFIG_NETDEVSIM=m
--
2.15.1
^ permalink raw reply related
* [PATCH] bpf: make function xdp_do_generic_redirect_map() static
From: Xiongwei Song @ 2017-12-18 23:17 UTC (permalink / raw)
To: ast, daniel, davem; +Cc: netdev, linux-kernel
The function xdp_do_generic_redirect_map() is only used in this file, so
make it static.
Clean up sparse warning:
net/core/filter.c:2687:5: warning: no previous prototype
for 'xdp_do_generic_redirect_map' [-Wmissing-prototypes]
Signed-off-by: Xiongwei Song <sxwjean@gmail.com>
---
net/core/filter.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index 754abe1041b7..130b842c3a15 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2684,8 +2684,9 @@ static int __xdp_generic_ok_fwd_dev(struct sk_buff *skb, struct net_device *fwd)
return 0;
}
-int xdp_do_generic_redirect_map(struct net_device *dev, struct sk_buff *skb,
- struct bpf_prog *xdp_prog)
+static int xdp_do_generic_redirect_map(struct net_device *dev,
+ struct sk_buff *skb,
+ struct bpf_prog *xdp_prog)
{
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
unsigned long map_owner = ri->map_owner;
--
2.15.1
^ permalink raw reply related
* Re: [PATCH 2/3] rhashtable: Add rhashtable_walk_curr
From: Herbert Xu @ 2017-12-18 23:38 UTC (permalink / raw)
To: Andreas Gruenbacher; +Cc: cluster-devel, Thomas Graf, netdev
In-Reply-To: <20171218133122.29179-2-agruenba@redhat.com>
On Mon, Dec 18, 2017 at 02:31:21PM +0100, Andreas Gruenbacher wrote:
> When iterating through an rhashtable is stopped with
> rhashtable_walk_stop and then resumed with rhashtable_walk_start, there
> currently is no way to get back to the current object and thus revisit
> the object rhashtable_walk_next has previously returned.
>
> This functionality is useful when dumping an rhashtable via the seq file
> interface: seq_read will convert one object after the other. When an
> object doesn't fit in the remaining buffer space anymore, user-space
> will be returned all objects that have been fully converted so far.
> Upon the next read from user-space, the object that didn't fit
> previously will be revisited.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Doesn't the helper that Tom Herbert just added do exactly this?
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 1/3] kallsyms: don't leak address when symbol not found
From: Steven Rostedt @ 2017-12-18 23:43 UTC (permalink / raw)
To: Tobin C. Harding
Cc: Felix Fietkau, kernel-hardening, Tycho Andersen, Linus Torvalds,
Kees Cook, Andrew Morton, Daniel Borkmann, Masahiro Yamada,
Alexei Starovoitov, linux-kernel, Network Development
In-Reply-To: <1513636889.2482269.1209330464.6971721E@webmail.messagingengine.com>
On Tue, 19 Dec 2017 09:41:29 +1100
"Tobin C. Harding" <me@tobin.cc> wrote:
> Current suggestion on list is to remove this function. Do you have a use
> case in mind where debugging will break? We could add a fix to this
> series if so. Otherwise next version will likely drop
> string_is_no_symbol()
What about adding a kernel command line parameter that lets one put
back the old behavior.
"insecure_print_all_symbols" ?
-- Steve
^ permalink raw reply
* Re: [PATCH 3/3] trace: print address if symbol not found
From: Steven Rostedt @ 2017-12-18 23:51 UTC (permalink / raw)
To: Tobin C. Harding
Cc: kernel-hardening, Tycho Andersen, Linus Torvalds, Kees Cook,
Andrew Morton, Daniel Borkmann, Masahiro Yamada,
Alexei Starovoitov, linux-kernel, Network Development
In-Reply-To: <20171218211614.GC19604@eros>
On Tue, 19 Dec 2017 08:16:14 +1100
"Tobin C. Harding" <me@tobin.cc> wrote:
> > > #endif /* _LINUX_KERNEL_TRACE_H */
> > > diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
> > > index 1e1558c99d56..3e28522a76f4 100644
> > > --- a/kernel/trace/trace_events_hist.c
> > > +++ b/kernel/trace/trace_events_hist.c
> > > @@ -982,7 +982,7 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
> > > return;
> > >
> > > seq_printf(m, "%*c", 1 + spaces, ' ');
> > > - sprint_symbol(str, stacktrace_entries[i]);
> > > + trace_sprint_symbol_addr(str, stacktrace_entries[i]);
> >
>
> If you have the time to give me some brief pointers on how I should go
> about testing this I'd love to test it before the next version. I know
> very little about ftrace.
For hitting the histogram stacktrace trigger (this code path), make
sure you have CONFIG_HIST_TRIGGERS enabled. And then do:
# cd /sys/kernel/debug/tracing
# echo 'hist:keys=common_pid.execname,stacktrace:vals=prev_state' > \
events/sched/sched_switch/trigger
# cat events/sched/sched_switch/hist
For the "sym" part, you can do (from the same directory):
# echo 'hist:keys=call_site.sym:vals=bytes_req' > \
events/kmem/kmalloc/trigger
# cat events/kmem/kmalloc/hist
And for sym-offset:
# echo 'hist:keys=call_site.sym-offset:vals=bytes_req' > \
events/kmem/kmalloc/trigger
# cat events/kmem/kmalloc/hist
-- Steve
^ permalink raw reply
* Re: [PATCH] bpf: fix broken BPF selftest build on s390
From: Daniel Borkmann @ 2017-12-19 0:21 UTC (permalink / raw)
To: Hendrik Brueckner, Alexei Starovoitov
Cc: Arnaldo Carvalho de Melo, linux-s390, netdev
In-Reply-To: <1513602597-12280-1-git-send-email-brueckner@linux.vnet.ibm.com>
On 12/18/2017 02:09 PM, Hendrik Brueckner wrote:
> With 720f228e8d31 ("bpf: fix broken BPF selftest build") the
> inclusion of arch-specific header files changed. Including the
> asm/bpf_perf_event.h on s390, correctly includes the s390 specific
> header file. This header file tries then to include the s390
> asm/ptrace.h and the build fails with:
>
> cc -Wall -O2 -I../../../include/uapi -I../../../lib -I../../../../include/generated -I../../../include test_verifier.c
> +/root/git/linux/tools/testing/selftests/bpf/libbpf.a /root/git/linux/tools/testing/selftests/bpf/cgroup_helpers.c -lcap -lelf -o
> +/root/git/linux/tools/testing/selftests/bpf/test_verifier
> In file included from ../../../include/uapi/asm/bpf_perf_event.h:4:0,
> from ../../../include/uapi/linux/bpf_perf_event.h:11,
> from test_verifier.c:29:
> ../../../include/uapi/../../arch/s390/include/uapi/asm/bpf_perf_event.h:7:9: error: unknown type name 'user_pt_regs'
> typedef user_pt_regs bpf_user_pt_regs_t;
> ^~~~~~~~~~~~
> make: *** [../lib.mk:109: /root/git/linux/tools/testing/selftests/bpf/test_verifier] Error 1
>
> This is caused by a recent update to the s390 asm/ptrace.h file
> that is not (yet) available in the local installation. That means,
> the s390 asm/ptrace.h must be included from the tools/arch/s390
> directory.
>
> Because there is no proper framework to deal with asm specific
> includes in tools/, slightly modify the s390 asm/bpf_perf_event.h
> to include the local ptrace.h header file.
>
> See also discussion on
> https://marc.info/?l=linux-s390&m=151359424420691&w=2
>
> Please note that this needs to be preserved until tools/ is able to
> correctly handle asm specific headers.
>
> References: https://marc.info/?l=linux-s390&m=151359424420691&w=2
> Fixes: 720f228e8d31 ("bpf: fix broken BPF selftest build")
> Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
> Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
> Cc: Alexei Starovoitov <ast@kernel.org>
Applied to bpf tree, thanks Hendrik!
^ permalink raw reply
* Re: [PATCH 3/3] trace: print address if symbol not found
From: Tobin C. Harding @ 2017-12-19 0:22 UTC (permalink / raw)
To: Steven Rostedt
Cc: kernel-hardening, Tycho Andersen, Linus Torvalds, Kees Cook,
Andrew Morton, Daniel Borkmann, Masahiro Yamada,
Alexei Starovoitov, linux-kernel, Network Development
In-Reply-To: <20171218185143.4046a71b@gandalf.local.home>
On Mon, Dec 18, 2017 at 06:51:43PM -0500, Steven Rostedt wrote:
> On Tue, 19 Dec 2017 08:16:14 +1100
> "Tobin C. Harding" <me@tobin.cc> wrote:
>
> > > > #endif /* _LINUX_KERNEL_TRACE_H */
> > > > diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
> > > > index 1e1558c99d56..3e28522a76f4 100644
> > > > --- a/kernel/trace/trace_events_hist.c
> > > > +++ b/kernel/trace/trace_events_hist.c
> > > > @@ -982,7 +982,7 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
> > > > return;
> > > >
> > > > seq_printf(m, "%*c", 1 + spaces, ' ');
> > > > - sprint_symbol(str, stacktrace_entries[i]);
> > > > + trace_sprint_symbol_addr(str, stacktrace_entries[i]);
> > >
>
> >
> > If you have the time to give me some brief pointers on how I should go
> > about testing this I'd love to test it before the next version. I know
> > very little about ftrace.
>
> For hitting the histogram stacktrace trigger (this code path), make
> sure you have CONFIG_HIST_TRIGGERS enabled. And then do:
>
> # cd /sys/kernel/debug/tracing
> # echo 'hist:keys=common_pid.execname,stacktrace:vals=prev_state' > \
> events/sched/sched_switch/trigger
> # cat events/sched/sched_switch/hist
>
> For the "sym" part, you can do (from the same directory):
>
> # echo 'hist:keys=call_site.sym:vals=bytes_req' > \
> events/kmem/kmalloc/trigger
> # cat events/kmem/kmalloc/hist
>
>
> And for sym-offset:
>
> # echo 'hist:keys=call_site.sym-offset:vals=bytes_req' > \
> events/kmem/kmalloc/trigger
> # cat events/kmem/kmalloc/hist
>
> -- Steve
Thanks, you're the man
^ permalink raw reply
* Re: [PATCH][next] bpf: fix spelling mistake: "funcation"-> "function"
From: Daniel Borkmann @ 2017-12-19 0:24 UTC (permalink / raw)
To: Colin King, Alexei Starovoitov, netdev; +Cc: kernel-janitors, linux-kernel
In-Reply-To: <20171218140312.6329-1-colin.king@canonical.com>
On 12/18/2017 03:03 PM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Trivial fix to spelling mistake in error message text.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Applied to bpf-next, thanks Colin!
^ permalink raw reply
* Re: [PATCH 1/3] kallsyms: don't leak address when symbol not found
From: Tobin C. Harding @ 2017-12-19 0:24 UTC (permalink / raw)
To: Steven Rostedt
Cc: Felix Fietkau, kernel-hardening, Tycho Andersen, Linus Torvalds,
Kees Cook, Andrew Morton, Daniel Borkmann, Masahiro Yamada,
Alexei Starovoitov, linux-kernel, Network Development
In-Reply-To: <20171218184324.527ffd0e@gandalf.local.home>
On Mon, Dec 18, 2017 at 06:43:24PM -0500, Steven Rostedt wrote:
> On Tue, 19 Dec 2017 09:41:29 +1100
> "Tobin C. Harding" <me@tobin.cc> wrote:
>
> > Current suggestion on list is to remove this function. Do you have a use
> > case in mind where debugging will break? We could add a fix to this
> > series if so. Otherwise next version will likely drop
> > string_is_no_symbol()
>
> What about adding a kernel command line parameter that lets one put
> back the old behavior.
>
> "insecure_print_all_symbols" ?
Cool. I've not done that before it will be a good learning
experience. I'll hack it up and see what people think.
thanks,
Tobin.
^ permalink raw reply
* Re: [PATCH][next] bpf: make function skip_callee static and return NULL rather than 0
From: Daniel Borkmann @ 2017-12-19 0:28 UTC (permalink / raw)
To: Colin King, Alexei Starovoitov, netdev; +Cc: kernel-janitors, linux-kernel
In-Reply-To: <20171218174707.15430-1-colin.king@canonical.com>
On 12/18/2017 06:47 PM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Function skip_callee is local to the source and does not need to
> be in global scope, so make it static. Also return NULL rather than 0.
> Cleans up two sparse warnings:
>
> symbol 'skip_callee' was not declared. Should it be static?
> Using plain integer as NULL pointer
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Makes sense, applied to bpf-next, thanks Colin!
^ permalink raw reply
* Re: [PATCH bpf-next] bpf: arm64: fix uninitialized variable
From: Daniel Borkmann @ 2017-12-19 0:34 UTC (permalink / raw)
To: Alexei Starovoitov, Alexei Starovoitov, David S . Miller
Cc: Arnd Bergmann, netdev, kernel-team
In-Reply-To: <68b024dd-4113-8c8a-a606-7b4b0206973d@fb.com>
On 12/18/2017 07:36 PM, Alexei Starovoitov wrote:
> On 12/18/17 10:19 AM, Daniel Borkmann wrote:
>> On 12/18/2017 07:09 PM, Alexei Starovoitov wrote:
>>> From: Alexei Starovoitov <ast@fb.com>
>>>
>>> fix the following issue:
>>> arch/arm64/net/bpf_jit_comp.c: In function 'bpf_int_jit_compile':
>>> arch/arm64/net/bpf_jit_comp.c:982:18: error: 'image_size' may be used
>>> uninitialized in this function [-Werror=maybe-uninitialized]
>>>
>>> Fixes: db496944fdaa ("bpf: arm64: add JIT support for multi-function programs")
>>> Reported-by: Arnd Bergmann <arnd@arndb.de>
>>> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
>>> ---
>>> arch/arm64/net/bpf_jit_comp.c | 1 +
>>> 1 file changed, 1 insertion(+)
>>>
>>> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
>>> index 396490cf7316..acaa935ed977 100644
>>> --- a/arch/arm64/net/bpf_jit_comp.c
>>> +++ b/arch/arm64/net/bpf_jit_comp.c
>>> @@ -897,6 +897,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>>> image_ptr = jit_data->image;
>>> header = jit_data->header;
>>> extra_pass = true;
>>> + image_size = sizeof(u32) * ctx.idx;
>>> goto skip_init_ctx;
>>> }
>>> memset(&ctx, 0, sizeof(ctx));
>>
>> I don't really mind, but it feels more complex than it needs to be
>> imho, since in the initial pass you fetch 'image_size' in fake pass
>> from ctx.idx, then we set ctx.idx to 0 again, do another pass and
>> use the cached ctx.idx from that second pass instead of the first
>> one where we set 'image_size' originally, so we definitely need to
>> take that into consideration in future reviews at least.
>
> not sure what you mean.
> This check: ctx.idx != jit_data->ctx.idx matters the most.
> After first alloc the 'image_size' variable used for dumping only.
> That's why the JITing itself worked fine. We could have removed it
> since it's computable from idx, but imo it's fine this way.
Fair enough, given final ctx.idx value must be guaranteed to never change
in future between pass#1 and pass#2 from the first bpf_int_jit_compile()
run, then lets go with this smaller version; applied to bpf-next, thanks
Alexei!
^ permalink raw reply
* Re: [PATCH bpf-next] selftests/bpf: add netdevsim to config
From: Daniel Borkmann @ 2017-12-19 0:36 UTC (permalink / raw)
To: Jakub Kicinski, alexei.starovoitov; +Cc: netdev, oss-drivers
In-Reply-To: <20171218231130.24619-1-jakub.kicinski@netronome.com>
On 12/19/2017 12:11 AM, Jakub Kicinski wrote:
> BPF offload tests (test_offload.py) will require netdevsim
> to be built, add it to config.
>
> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Applied to bpf-next, thanks Jakub!
^ permalink raw reply
* Re: [PATCH] bpf: make function xdp_do_generic_redirect_map() static
From: Daniel Borkmann @ 2017-12-19 0:38 UTC (permalink / raw)
To: Xiongwei Song, ast, davem; +Cc: netdev, linux-kernel
In-Reply-To: <20171218231715.3227-1-sxwjean@gmail.com>
On 12/19/2017 12:17 AM, Xiongwei Song wrote:
> The function xdp_do_generic_redirect_map() is only used in this file, so
> make it static.
>
> Clean up sparse warning:
> net/core/filter.c:2687:5: warning: no previous prototype
> for 'xdp_do_generic_redirect_map' [-Wmissing-prototypes]
>
> Signed-off-by: Xiongwei Song <sxwjean@gmail.com>
Applied to bpf-next, thanks Xiongwei!
^ permalink raw reply
* [RFC PATCH] virtio_net: Extend virtio to use VF datapath when available
From: Sridhar Samudrala @ 2017-12-19 0:40 UTC (permalink / raw)
To: mst, stephen, netdev, virtualization, alexander.duyck,
sridhar.samudrala
This patch enables virtio to switch over to a VF datapath when a VF netdev
is present with the same MAC address. It allows live migration of a VM
with a direct attached VF without the need to setup a bond/team between a
VF and virtio net device in the guest.
The hypervisor needs to unplug the VF device from the guest on the source
host and reset the MAC filter of the VF to initiate failover of datapath to
virtio before starting the migration. After the migration is completed, the
destination hypervisor sets the MAC filter on the VF and plugs it back to
the guest to switch over to VF datapath.
It is entirely based on netvsc implementation and it should be possible to
make this code generic and move it to a common location that can be shared
by netvsc and virtio.
Also, i think we should make this a negotiated feature that is off by
default via a new feature bit.
This patch is based on the discussion initiated by Jesse on this thread.
https://marc.info/?l=linux-virtualization&m=151189725224231&w=2
Signed-off-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
---
drivers/net/virtio_net.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 339 insertions(+), 2 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 559b215c0169..a34c717bb15b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -31,6 +31,8 @@
#include <linux/average.h>
#include <linux/filter.h>
#include <net/route.h>
+#include <linux/netdevice.h>
+#include <linux/netpoll.h>
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
@@ -56,6 +58,8 @@ module_param(napi_tx, bool, 0644);
*/
DECLARE_EWMA(pkt_len, 0, 64)
+#define VF_TAKEOVER_INT (HZ / 10)
+
#define VIRTNET_DRIVER_VERSION "1.0.0"
static const unsigned long guest_offloads[] = {
@@ -117,6 +121,15 @@ struct receive_queue {
char name[40];
};
+struct virtnet_vf_pcpu_stats {
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ struct u64_stats_sync syncp;
+ u32 tx_dropped;
+};
+
struct virtnet_info {
struct virtio_device *vdev;
struct virtqueue *cvq;
@@ -179,6 +192,11 @@ struct virtnet_info {
u32 speed;
unsigned long guest_offloads;
+
+ /* State to manage the associated VF interface. */
+ struct net_device __rcu *vf_netdev;
+ struct virtnet_vf_pcpu_stats __percpu *vf_stats;
+ struct delayed_work vf_takeover;
};
struct padded_vnet_hdr {
@@ -1300,16 +1318,51 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
}
+/* Send skb on the slave VF device. */
+static int virtnet_vf_xmit(struct net_device *dev, struct net_device *vf_netdev,
+ struct sk_buff *skb)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ unsigned int len = skb->len;
+ int rc;
+
+ skb->dev = vf_netdev;
+ skb->queue_mapping = qdisc_skb_cb(skb)->slave_dev_queue_mapping;
+
+ rc = dev_queue_xmit(skb);
+ if (likely(rc == NET_XMIT_SUCCESS || rc == NET_XMIT_CN)) {
+ struct virtnet_vf_pcpu_stats *pcpu_stats
+ = this_cpu_ptr(vi->vf_stats);
+
+ u64_stats_update_begin(&pcpu_stats->syncp);
+ pcpu_stats->tx_packets++;
+ pcpu_stats->tx_bytes += len;
+ u64_stats_update_end(&pcpu_stats->syncp);
+ } else {
+ this_cpu_inc(vi->vf_stats->tx_dropped);
+ }
+
+ return rc;
+}
+
static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
int qnum = skb_get_queue_mapping(skb);
struct send_queue *sq = &vi->sq[qnum];
+ struct net_device *vf_netdev;
int err;
struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
bool kick = !skb->xmit_more;
bool use_napi = sq->napi.weight;
+ /* if VF is present and up then redirect packets
+ * called with rcu_read_lock_bh
+ */
+ vf_netdev = rcu_dereference_bh(vi->vf_netdev);
+ if (vf_netdev && netif_running(vf_netdev) && !netpoll_tx_running(dev))
+ return virtnet_vf_xmit(dev, vf_netdev, skb);
+
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(sq);
@@ -1456,10 +1509,41 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
return ret;
}
+static void virtnet_get_vf_stats(struct net_device *dev,
+ struct virtnet_vf_pcpu_stats *tot)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ int i;
+
+ memset(tot, 0, sizeof(*tot));
+
+ for_each_possible_cpu(i) {
+ const struct virtnet_vf_pcpu_stats *stats
+ = per_cpu_ptr(vi->vf_stats, i);
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&stats->syncp);
+ rx_packets = stats->rx_packets;
+ tx_packets = stats->tx_packets;
+ rx_bytes = stats->rx_bytes;
+ tx_bytes = stats->tx_bytes;
+ } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+
+ tot->rx_packets += rx_packets;
+ tot->tx_packets += tx_packets;
+ tot->rx_bytes += rx_bytes;
+ tot->tx_bytes += tx_bytes;
+ tot->tx_dropped += stats->tx_dropped;
+ }
+}
+
static void virtnet_stats(struct net_device *dev,
struct rtnl_link_stats64 *tot)
{
struct virtnet_info *vi = netdev_priv(dev);
+ struct virtnet_vf_pcpu_stats vf_stats;
int cpu;
unsigned int start;
@@ -1490,6 +1574,13 @@ static void virtnet_stats(struct net_device *dev,
tot->rx_dropped = dev->stats.rx_dropped;
tot->rx_length_errors = dev->stats.rx_length_errors;
tot->rx_frame_errors = dev->stats.rx_frame_errors;
+
+ virtnet_get_vf_stats(dev, &vf_stats);
+ tot->rx_packets += vf_stats.rx_packets;
+ tot->tx_packets += vf_stats.tx_packets;
+ tot->rx_bytes += vf_stats.rx_bytes;
+ tot->tx_bytes += vf_stats.tx_bytes;
+ tot->tx_dropped += vf_stats.tx_dropped;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2508,6 +2599,47 @@ static int virtnet_validate(struct virtio_device *vdev)
return 0;
}
+static void __virtnet_vf_setup(struct net_device *ndev,
+ struct net_device *vf_netdev)
+{
+ int ret;
+
+ /* Align MTU of VF with master */
+ ret = dev_set_mtu(vf_netdev, ndev->mtu);
+ if (ret)
+ netdev_warn(vf_netdev,
+ "unable to change mtu to %u\n", ndev->mtu);
+
+ if (netif_running(ndev)) {
+ ret = dev_open(vf_netdev);
+ if (ret)
+ netdev_warn(vf_netdev,
+ "unable to open: %d\n", ret);
+ }
+}
+
+/* Setup VF as slave of the virtio device.
+ * Runs in workqueue to avoid recursion in netlink callbacks.
+ */
+static void virtnet_vf_setup(struct work_struct *w)
+{
+ struct virtnet_info *vi
+ = container_of(w, struct virtnet_info, vf_takeover.work);
+ struct net_device *ndev = vi->dev;
+ struct net_device *vf_netdev;
+
+ if (!rtnl_trylock()) {
+ schedule_delayed_work(&vi->vf_takeover, 0);
+ return;
+ }
+
+ vf_netdev = rtnl_dereference(vi->vf_netdev);
+ if (vf_netdev)
+ __virtnet_vf_setup(ndev, vf_netdev);
+
+ rtnl_unlock();
+}
+
static int virtnet_probe(struct virtio_device *vdev)
{
int i, err;
@@ -2600,6 +2732,11 @@ static int virtnet_probe(struct virtio_device *vdev)
}
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
+ INIT_DELAYED_WORK(&vi->vf_takeover, virtnet_vf_setup);
+
+ vi->vf_stats = netdev_alloc_pcpu_stats(struct virtnet_vf_pcpu_stats);
+ if (!vi->vf_stats)
+ goto free_stats;
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
@@ -2634,7 +2771,7 @@ static int virtnet_probe(struct virtio_device *vdev)
*/
dev_err(&vdev->dev, "device MTU appears to have changed "
"it is now %d < %d", mtu, dev->min_mtu);
- goto free_stats;
+ goto free_vf_stats;
}
dev->mtu = mtu;
@@ -2658,7 +2795,7 @@ static int virtnet_probe(struct virtio_device *vdev)
/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
err = init_vqs(vi);
if (err)
- goto free_stats;
+ goto free_vf_stats;
#ifdef CONFIG_SYSFS
if (vi->mergeable_rx_bufs)
@@ -2712,6 +2849,8 @@ static int virtnet_probe(struct virtio_device *vdev)
cancel_delayed_work_sync(&vi->refill);
free_receive_page_frags(vi);
virtnet_del_vqs(vi);
+free_vf_stats:
+ free_percpu(vi->vf_stats);
free_stats:
free_percpu(vi->stats);
free:
@@ -2733,19 +2872,178 @@ static void remove_vq_common(struct virtnet_info *vi)
virtnet_del_vqs(vi);
}
+static struct net_device *get_virtio_bymac(const u8 *mac)
+{
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+
+ for_each_netdev(&init_net, dev) {
+ if (dev->netdev_ops != &virtnet_netdev)
+ continue; /* not a virtio_net device */
+
+ if (ether_addr_equal(mac, dev->perm_addr))
+ return dev;
+ }
+
+ return NULL;
+}
+
+static struct net_device *get_virtio_byref(struct net_device *vf_netdev)
+{
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+
+ for_each_netdev(&init_net, dev) {
+ struct virtnet_info *vi;
+
+ if (dev->netdev_ops != &virtnet_netdev)
+ continue; /* not a virtio_net device */
+
+ vi = netdev_priv(dev);
+ if (rtnl_dereference(vi->vf_netdev) == vf_netdev)
+ return dev; /* a match */
+ }
+
+ return NULL;
+}
+
+/* Called when VF is injecting data into network stack.
+ * Change the associated network device from VF to virtio.
+ * note: already called with rcu_read_lock
+ */
+static rx_handler_result_t virtnet_vf_handle_frame(struct sk_buff **pskb)
+{
+ struct sk_buff *skb = *pskb;
+ struct net_device *ndev = rcu_dereference(skb->dev->rx_handler_data);
+ struct virtnet_info *vi = netdev_priv(ndev);
+ struct virtnet_vf_pcpu_stats *pcpu_stats =
+ this_cpu_ptr(vi->vf_stats);
+
+ skb->dev = ndev;
+
+ u64_stats_update_begin(&pcpu_stats->syncp);
+ pcpu_stats->rx_packets++;
+ pcpu_stats->rx_bytes += skb->len;
+ u64_stats_update_end(&pcpu_stats->syncp);
+
+ return RX_HANDLER_ANOTHER;
+}
+
+static int virtnet_vf_join(struct net_device *vf_netdev,
+ struct net_device *ndev)
+{
+ struct virtnet_info *vi = netdev_priv(ndev);
+ int ret;
+
+ ret = netdev_rx_handler_register(vf_netdev,
+ virtnet_vf_handle_frame, ndev);
+ if (ret != 0) {
+ netdev_err(vf_netdev,
+ "can not register virtio VF receive handler (err = %d)\n",
+ ret);
+ goto rx_handler_failed;
+ }
+
+ ret = netdev_upper_dev_link(vf_netdev, ndev, NULL);
+ if (ret != 0) {
+ netdev_err(vf_netdev,
+ "can not set master device %s (err = %d)\n",
+ ndev->name, ret);
+ goto upper_link_failed;
+ }
+
+ /* set slave flag before open to prevent IPv6 addrconf */
+ vf_netdev->flags |= IFF_SLAVE;
+
+ schedule_delayed_work(&vi->vf_takeover, VF_TAKEOVER_INT);
+
+ call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
+
+ netdev_info(vf_netdev, "joined to %s\n", ndev->name);
+ return 0;
+
+upper_link_failed:
+ netdev_rx_handler_unregister(vf_netdev);
+rx_handler_failed:
+ return ret;
+}
+
+static int virtnet_register_vf(struct net_device *vf_netdev)
+{
+ struct net_device *ndev;
+ struct virtnet_info *vi;
+
+ if (vf_netdev->addr_len != ETH_ALEN)
+ return NOTIFY_DONE;
+
+ /* We will use the MAC address to locate the virtio_net interface to
+ * associate with the VF interface. If we don't find a matching
+ * virtio interface, move on.
+ */
+ ndev = get_virtio_bymac(vf_netdev->perm_addr);
+ if (!ndev)
+ return NOTIFY_DONE;
+
+ vi = netdev_priv(ndev);
+ if (rtnl_dereference(vi->vf_netdev))
+ return NOTIFY_DONE;
+
+ if (virtnet_vf_join(vf_netdev, ndev) != 0)
+ return NOTIFY_DONE;
+
+ netdev_info(ndev, "VF registering %s\n", vf_netdev->name);
+
+ dev_hold(vf_netdev);
+ rcu_assign_pointer(vi->vf_netdev, vf_netdev);
+
+ return NOTIFY_OK;
+}
+
+static int virtnet_unregister_vf(struct net_device *vf_netdev)
+{
+ struct net_device *ndev;
+ struct virtnet_info *vi;
+
+ ndev = get_virtio_byref(vf_netdev);
+ if (!ndev)
+ return NOTIFY_DONE;
+
+ vi = netdev_priv(ndev);
+ cancel_delayed_work_sync(&vi->vf_takeover);
+
+ netdev_info(ndev, "VF unregistering %s\n", vf_netdev->name);
+
+ netdev_rx_handler_unregister(vf_netdev);
+ netdev_upper_dev_unlink(vf_netdev, ndev);
+ RCU_INIT_POINTER(vi->vf_netdev, NULL);
+ dev_put(vf_netdev);
+
+ return NOTIFY_OK;
+}
+
static void virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+ struct net_device *vf_netdev;
virtnet_cpu_notif_remove(vi);
/* Make sure no work handler is accessing the device. */
flush_work(&vi->config_work);
+ rtnl_lock();
+ vf_netdev = rtnl_dereference(vi->vf_netdev);
+ if (vf_netdev)
+ virtnet_unregister_vf(vf_netdev);
+ rtnl_unlock();
+
unregister_netdev(vi->dev);
remove_vq_common(vi);
+ free_percpu(vi->vf_stats);
free_percpu(vi->stats);
free_netdev(vi->dev);
}
@@ -2823,6 +3121,42 @@ static struct virtio_driver virtio_net_driver = {
#endif
};
+static int virtio_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
+
+ /* Skip our own events */
+ if (event_dev->netdev_ops == &virtnet_netdev)
+ return NOTIFY_DONE;
+
+ /* Avoid non-Ethernet type devices */
+ if (event_dev->type != ARPHRD_ETHER)
+ return NOTIFY_DONE;
+
+ /* Avoid Vlan dev with same MAC registering as VF */
+ if (is_vlan_dev(event_dev))
+ return NOTIFY_DONE;
+
+ /* Avoid Bonding master dev with same MAC registering as VF */
+ if ((event_dev->priv_flags & IFF_BONDING) &&
+ (event_dev->flags & IFF_MASTER))
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_REGISTER:
+ return virtnet_register_vf(event_dev);
+ case NETDEV_UNREGISTER:
+ return virtnet_unregister_vf(event_dev);
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static struct notifier_block virtio_netdev_notifier = {
+ .notifier_call = virtio_netdev_event,
+};
+
static __init int virtio_net_driver_init(void)
{
int ret;
@@ -2841,6 +3175,8 @@ static __init int virtio_net_driver_init(void)
ret = register_virtio_driver(&virtio_net_driver);
if (ret)
goto err_virtio;
+
+ register_netdevice_notifier(&virtio_netdev_notifier);
return 0;
err_virtio:
cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
@@ -2853,6 +3189,7 @@ module_init(virtio_net_driver_init);
static __exit void virtio_net_driver_exit(void)
{
+ unregister_netdevice_notifier(&virtio_netdev_notifier);
unregister_virtio_driver(&virtio_net_driver);
cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
cpuhp_remove_multi_state(virtionet_online);
--
2.14.3
^ permalink raw reply related
* Re: [PATCH net-next] bpf/cgroup: fix a verification error for a CGROUP_DEVICE type prog
From: Daniel Borkmann @ 2017-12-19 0:46 UTC (permalink / raw)
To: Yonghong Song, ast, netdev; +Cc: guro, kernel-team
In-Reply-To: <20171218181344.2000185-1-yhs@fb.com>
On 12/18/2017 07:13 PM, Yonghong Song wrote:
> The tools/testing/selftests/bpf test program
> test_dev_cgroup fails with the following error
> when compiled with llvm 6.0. (I did not try
> with earlier versions.)
>
> libbpf: load bpf program failed: Permission denied
> libbpf: -- BEGIN DUMP LOG ---
> libbpf:
> 0: (61) r2 = *(u32 *)(r1 +4)
> 1: (b7) r0 = 0
> 2: (55) if r2 != 0x1 goto pc+8
> R0=inv0 R1=ctx(id=0,off=0,imm=0) R2=inv1 R10=fp0
> 3: (69) r2 = *(u16 *)(r1 +0)
> invalid bpf_context access off=0 size=2
> ...
>
> The culprit is the following statement in dev_cgroup.c:
> short type = ctx->access_type & 0xFFFF;
> This code is typical as the ctx->access_type is assigned
> as below in kernel/bpf/cgroup.c:
> struct bpf_cgroup_dev_ctx ctx = {
> .access_type = (access << 16) | dev_type,
> .major = major,
> .minor = minor,
> };
>
> The compiler converts it to u16 access while
> the verifier cgroup_dev_is_valid_access rejects
> any non u32 access.
>
> This patch permits the field access_type to be accessible
> with type u16 and u8 as well.
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
> Tested-by: Roman Gushchin <guro@fb.com>
Looks good, applied to bpf-next, thanks Yonghong!
^ permalink raw reply
* linux-next: manual merge of the net-next tree with the net tree
From: Stephen Rothwell @ 2017-12-19 0:51 UTC (permalink / raw)
To: David Miller, Networking
Cc: Linux-Next Mailing List, Linux Kernel Mailing List, Zhao Qiang,
Heiner Kallweit
Hi all,
Today's linux-next merge of the net-next tree got a conflict in:
drivers/net/phy/marvell.c
between commit:
c505873eaece ("net: phy: marvell: Limit 88m1101 autoneg errata to 88E1145 as well.")
from the net tree and commit:
80274abafc60 ("net: phy: remove generic settings for callbacks config_aneg and read_status from drivers")
from the net-next tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
--
Cheers,
Stephen Rothwell
diff --cc drivers/net/phy/marvell.c
index 82104edca393,2fc026dc170a..000000000000
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@@ -2085,8 -2070,7 +2082,7 @@@ static struct phy_driver marvell_driver
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
.config_init = &m88e1145_config_init,
- .config_aneg = &marvell_config_aneg,
+ .config_aneg = &m88e1101_config_aneg,
- .read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
^ permalink raw reply
* Re: [Patch net-next] net_sched: properly check for empty skb array on error path
From: John Fastabend @ 2017-12-19 1:25 UTC (permalink / raw)
To: Cong Wang, netdev
In-Reply-To: <20171218223426.4685-1-xiyou.wangcong@gmail.com>
On 12/18/2017 02:34 PM, Cong Wang wrote:
> First, the check of &q->ring.queue against NULL is wrong, it
> is always false. We should check the value rather than the address.
>
Thanks.
> Secondly, we need the same check in pfifo_fast_reset() too,
> as both ->reset() and ->destroy() are called in qdisc_destroy().
>
not that it hurts to have the check here, but if init fails
in qdisc_create it seems only ->destroy() is called without
a ->reset().
Is there another path for init() to fail that I'm missing.
> Fixes: c5ad119fb6c0 ("net: sched: pfifo_fast use skb_array")
> Reported-by: syzbot <syzkaller@googlegroups.com>
> Cc: John Fastabend <john.fastabend@gmail.com>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
> ---
> net/sched/sch_generic.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
^ 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