Commit bd070e21 authored by David S. Miller's avatar David S. Miller

Merge branch 'tc-sw-only'

John Fastabend says:

====================
tc software only

This adds a software only flag to tc but incorporates a bunch of comments
from the original attempt at this.

First instead of having the offload decision logic be embedded in cls_u32
I lifted into cls_pkt.h so it can be used anywhere and named the flag
TCA_CLS_FLAGS_SKIP_HW (Thanks Jiri ;)

In order to do this I put the flag defines in pkt_cls.h as well. However
it was suggested that perhaps these flags could be lifted into the
upper layer of TCA_ as well but I'm afraid this can not be done with
existing tc design as far as I can tell. The problem is the filters are
packed and unpacked in the classifier specific code and pushing the flags
through the high level doesn't seem easily doable. And we already have
this design where classifiers handle generic options such as actions and
policers. So I think adding one more thing here is OK as 'tc', et. al.
already know how to handle this type of thing.
====================
Acked-by: default avatarPravin B Shelar <pshelar@ovn.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d2e42a17 9e8ce79c
...@@ -8400,9 +8400,6 @@ int __ixgbe_setup_tc(struct net_device *dev, u32 handle, __be16 proto, ...@@ -8400,9 +8400,6 @@ int __ixgbe_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
if (TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS) && if (TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS) &&
tc->type == TC_SETUP_CLSU32) { tc->type == TC_SETUP_CLSU32) {
if (!(dev->features & NETIF_F_HW_TC))
return -EINVAL;
switch (tc->cls_u32->command) { switch (tc->cls_u32->command) {
case TC_CLSU32_NEW_KNODE: case TC_CLSU32_NEW_KNODE:
case TC_CLSU32_REPLACE_KNODE: case TC_CLSU32_REPLACE_KNODE:
......
...@@ -392,4 +392,21 @@ struct tc_cls_u32_offload { ...@@ -392,4 +392,21 @@ struct tc_cls_u32_offload {
}; };
}; };
/* tca flags definitions */
#define TCA_CLS_FLAGS_SKIP_HW 1
static inline bool tc_should_offload(struct net_device *dev, u32 flags)
{
if (!(dev->features & NETIF_F_HW_TC))
return false;
if (flags & TCA_CLS_FLAGS_SKIP_HW)
return false;
if (!dev->netdev_ops->ndo_setup_tc)
return false;
return true;
}
#endif #endif
...@@ -172,6 +172,7 @@ enum { ...@@ -172,6 +172,7 @@ enum {
TCA_U32_INDEV, TCA_U32_INDEV,
TCA_U32_PCNT, TCA_U32_PCNT,
TCA_U32_MARK, TCA_U32_MARK,
TCA_U32_FLAGS,
__TCA_U32_MAX __TCA_U32_MAX
}; };
......
...@@ -59,6 +59,7 @@ struct tc_u_knode { ...@@ -59,6 +59,7 @@ struct tc_u_knode {
#ifdef CONFIG_CLS_U32_PERF #ifdef CONFIG_CLS_U32_PERF
struct tc_u32_pcnt __percpu *pf; struct tc_u32_pcnt __percpu *pf;
#endif #endif
u32 flags;
#ifdef CONFIG_CLS_U32_MARK #ifdef CONFIG_CLS_U32_MARK
u32 val; u32 val;
u32 mask; u32 mask;
...@@ -434,7 +435,7 @@ static void u32_remove_hw_knode(struct tcf_proto *tp, u32 handle) ...@@ -434,7 +435,7 @@ static void u32_remove_hw_knode(struct tcf_proto *tp, u32 handle)
offload.type = TC_SETUP_CLSU32; offload.type = TC_SETUP_CLSU32;
offload.cls_u32 = &u32_offload; offload.cls_u32 = &u32_offload;
if (dev->netdev_ops->ndo_setup_tc) { if (tc_should_offload(dev, 0)) {
offload.cls_u32->command = TC_CLSU32_DELETE_KNODE; offload.cls_u32->command = TC_CLSU32_DELETE_KNODE;
offload.cls_u32->knode.handle = handle; offload.cls_u32->knode.handle = handle;
dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
...@@ -442,7 +443,9 @@ static void u32_remove_hw_knode(struct tcf_proto *tp, u32 handle) ...@@ -442,7 +443,9 @@ static void u32_remove_hw_knode(struct tcf_proto *tp, u32 handle)
} }
} }
static void u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) static void u32_replace_hw_hnode(struct tcf_proto *tp,
struct tc_u_hnode *h,
u32 flags)
{ {
struct net_device *dev = tp->q->dev_queue->dev; struct net_device *dev = tp->q->dev_queue->dev;
struct tc_cls_u32_offload u32_offload = {0}; struct tc_cls_u32_offload u32_offload = {0};
...@@ -451,7 +454,7 @@ static void u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) ...@@ -451,7 +454,7 @@ static void u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h)
offload.type = TC_SETUP_CLSU32; offload.type = TC_SETUP_CLSU32;
offload.cls_u32 = &u32_offload; offload.cls_u32 = &u32_offload;
if (dev->netdev_ops->ndo_setup_tc) { if (tc_should_offload(dev, flags)) {
offload.cls_u32->command = TC_CLSU32_NEW_HNODE; offload.cls_u32->command = TC_CLSU32_NEW_HNODE;
offload.cls_u32->hnode.divisor = h->divisor; offload.cls_u32->hnode.divisor = h->divisor;
offload.cls_u32->hnode.handle = h->handle; offload.cls_u32->hnode.handle = h->handle;
...@@ -471,7 +474,7 @@ static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) ...@@ -471,7 +474,7 @@ static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h)
offload.type = TC_SETUP_CLSU32; offload.type = TC_SETUP_CLSU32;
offload.cls_u32 = &u32_offload; offload.cls_u32 = &u32_offload;
if (dev->netdev_ops->ndo_setup_tc) { if (tc_should_offload(dev, 0)) {
offload.cls_u32->command = TC_CLSU32_DELETE_HNODE; offload.cls_u32->command = TC_CLSU32_DELETE_HNODE;
offload.cls_u32->hnode.divisor = h->divisor; offload.cls_u32->hnode.divisor = h->divisor;
offload.cls_u32->hnode.handle = h->handle; offload.cls_u32->hnode.handle = h->handle;
...@@ -482,7 +485,9 @@ static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) ...@@ -482,7 +485,9 @@ static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h)
} }
} }
static void u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n) static void u32_replace_hw_knode(struct tcf_proto *tp,
struct tc_u_knode *n,
u32 flags)
{ {
struct net_device *dev = tp->q->dev_queue->dev; struct net_device *dev = tp->q->dev_queue->dev;
struct tc_cls_u32_offload u32_offload = {0}; struct tc_cls_u32_offload u32_offload = {0};
...@@ -491,7 +496,7 @@ static void u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n) ...@@ -491,7 +496,7 @@ static void u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n)
offload.type = TC_SETUP_CLSU32; offload.type = TC_SETUP_CLSU32;
offload.cls_u32 = &u32_offload; offload.cls_u32 = &u32_offload;
if (dev->netdev_ops->ndo_setup_tc) { if (tc_should_offload(dev, flags)) {
offload.cls_u32->command = TC_CLSU32_REPLACE_KNODE; offload.cls_u32->command = TC_CLSU32_REPLACE_KNODE;
offload.cls_u32->knode.handle = n->handle; offload.cls_u32->knode.handle = n->handle;
offload.cls_u32->knode.fshift = n->fshift; offload.cls_u32->knode.fshift = n->fshift;
...@@ -679,6 +684,7 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = { ...@@ -679,6 +684,7 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
[TCA_U32_SEL] = { .len = sizeof(struct tc_u32_sel) }, [TCA_U32_SEL] = { .len = sizeof(struct tc_u32_sel) },
[TCA_U32_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, [TCA_U32_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ },
[TCA_U32_MARK] = { .len = sizeof(struct tc_u32_mark) }, [TCA_U32_MARK] = { .len = sizeof(struct tc_u32_mark) },
[TCA_U32_FLAGS] = { .type = NLA_U32 },
}; };
static int u32_set_parms(struct net *net, struct tcf_proto *tp, static int u32_set_parms(struct net *net, struct tcf_proto *tp,
...@@ -786,6 +792,7 @@ static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp, ...@@ -786,6 +792,7 @@ static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp,
#endif #endif
new->fshift = n->fshift; new->fshift = n->fshift;
new->res = n->res; new->res = n->res;
new->flags = n->flags;
RCU_INIT_POINTER(new->ht_down, n->ht_down); RCU_INIT_POINTER(new->ht_down, n->ht_down);
/* bump reference count as long as we hold pointer to structure */ /* bump reference count as long as we hold pointer to structure */
...@@ -825,7 +832,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -825,7 +832,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
struct tc_u32_sel *s; struct tc_u32_sel *s;
struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *opt = tca[TCA_OPTIONS];
struct nlattr *tb[TCA_U32_MAX + 1]; struct nlattr *tb[TCA_U32_MAX + 1];
u32 htid; u32 htid, flags = 0;
int err; int err;
#ifdef CONFIG_CLS_U32_PERF #ifdef CONFIG_CLS_U32_PERF
size_t size; size_t size;
...@@ -838,6 +845,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -838,6 +845,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
if (err < 0) if (err < 0)
return err; return err;
if (tb[TCA_U32_FLAGS])
flags = nla_get_u32(tb[TCA_U32_FLAGS]);
n = (struct tc_u_knode *)*arg; n = (struct tc_u_knode *)*arg;
if (n) { if (n) {
struct tc_u_knode *new; struct tc_u_knode *new;
...@@ -845,6 +855,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -845,6 +855,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
if (TC_U32_KEY(n->handle) == 0) if (TC_U32_KEY(n->handle) == 0)
return -EINVAL; return -EINVAL;
if (n->flags != flags)
return -EINVAL;
new = u32_init_knode(tp, n); new = u32_init_knode(tp, n);
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
...@@ -861,7 +874,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -861,7 +874,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
u32_replace_knode(tp, tp_c, new); u32_replace_knode(tp, tp_c, new);
tcf_unbind_filter(tp, &n->res); tcf_unbind_filter(tp, &n->res);
call_rcu(&n->rcu, u32_delete_key_rcu); call_rcu(&n->rcu, u32_delete_key_rcu);
u32_replace_hw_knode(tp, new); u32_replace_hw_knode(tp, new, flags);
return 0; return 0;
} }
...@@ -889,7 +902,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -889,7 +902,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
rcu_assign_pointer(tp_c->hlist, ht); rcu_assign_pointer(tp_c->hlist, ht);
*arg = (unsigned long)ht; *arg = (unsigned long)ht;
u32_replace_hw_hnode(tp, ht); u32_replace_hw_hnode(tp, ht, flags);
return 0; return 0;
} }
...@@ -940,6 +953,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -940,6 +953,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
RCU_INIT_POINTER(n->ht_up, ht); RCU_INIT_POINTER(n->ht_up, ht);
n->handle = handle; n->handle = handle;
n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
n->flags = flags;
tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE); tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE);
n->tp = tp; n->tp = tp;
...@@ -972,7 +986,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -972,7 +986,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
RCU_INIT_POINTER(n->next, pins); RCU_INIT_POINTER(n->next, pins);
rcu_assign_pointer(*ins, n); rcu_assign_pointer(*ins, n);
u32_replace_hw_knode(tp, n); u32_replace_hw_knode(tp, n, flags);
*arg = (unsigned long)n; *arg = (unsigned long)n;
return 0; return 0;
} }
...@@ -1077,6 +1091,9 @@ static int u32_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, ...@@ -1077,6 +1091,9 @@ static int u32_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
nla_put_u32(skb, TCA_U32_LINK, ht_down->handle)) nla_put_u32(skb, TCA_U32_LINK, ht_down->handle))
goto nla_put_failure; goto nla_put_failure;
if (n->flags && nla_put_u32(skb, TCA_U32_FLAGS, n->flags))
goto nla_put_failure;
#ifdef CONFIG_CLS_U32_MARK #ifdef CONFIG_CLS_U32_MARK
if ((n->val || n->mask)) { if ((n->val || n->mask)) {
struct tc_u32_mark mark = {.val = n->val, struct tc_u32_mark mark = {.val = n->val,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment