aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/pkt_cls.h13
-rw-r--r--include/uapi/linux/pkt_cls.h1
-rw-r--r--net/sched/cls_u32.c37
3 files changed, 39 insertions, 12 deletions
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 6096e96fb78b..bea14eee373e 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -392,12 +392,21 @@ struct tc_cls_u32_offload {
392 }; 392 };
393}; 393};
394 394
395static inline bool tc_should_offload(struct net_device *dev) 395/* tca flags definitions */
396#define TCA_CLS_FLAGS_SKIP_HW 1
397
398static inline bool tc_should_offload(struct net_device *dev, u32 flags)
396{ 399{
397 if (!(dev->features & NETIF_F_HW_TC)) 400 if (!(dev->features & NETIF_F_HW_TC))
398 return false; 401 return false;
399 402
400 return dev->netdev_ops->ndo_setup_tc; 403 if (flags & TCA_CLS_FLAGS_SKIP_HW)
404 return false;
405
406 if (!dev->netdev_ops->ndo_setup_tc)
407 return false;
408
409 return true;
401} 410}
402 411
403#endif 412#endif
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 439873775d49..9874f5680926 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -172,6 +172,7 @@ enum {
172 TCA_U32_INDEV, 172 TCA_U32_INDEV,
173 TCA_U32_PCNT, 173 TCA_U32_PCNT,
174 TCA_U32_MARK, 174 TCA_U32_MARK,
175 TCA_U32_FLAGS,
175 __TCA_U32_MAX 176 __TCA_U32_MAX
176}; 177};
177 178
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 24e888b9b728..563cdad76448 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -59,6 +59,7 @@ struct tc_u_knode {
59#ifdef CONFIG_CLS_U32_PERF 59#ifdef CONFIG_CLS_U32_PERF
60 struct tc_u32_pcnt __percpu *pf; 60 struct tc_u32_pcnt __percpu *pf;
61#endif 61#endif
62 u32 flags;
62#ifdef CONFIG_CLS_U32_MARK 63#ifdef CONFIG_CLS_U32_MARK
63 u32 val; 64 u32 val;
64 u32 mask; 65 u32 mask;
@@ -434,7 +435,7 @@ static void u32_remove_hw_knode(struct tcf_proto *tp, u32 handle)
434 offload.type = TC_SETUP_CLSU32; 435 offload.type = TC_SETUP_CLSU32;
435 offload.cls_u32 = &u32_offload; 436 offload.cls_u32 = &u32_offload;
436 437
437 if (tc_should_offload(dev)) { 438 if (tc_should_offload(dev, 0)) {
438 offload.cls_u32->command = TC_CLSU32_DELETE_KNODE; 439 offload.cls_u32->command = TC_CLSU32_DELETE_KNODE;
439 offload.cls_u32->knode.handle = handle; 440 offload.cls_u32->knode.handle = handle;
440 dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, 441 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 } 443 }
443} 444}
444 445
445static void u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) 446static void u32_replace_hw_hnode(struct tcf_proto *tp,
447 struct tc_u_hnode *h,
448 u32 flags)
446{ 449{
447 struct net_device *dev = tp->q->dev_queue->dev; 450 struct net_device *dev = tp->q->dev_queue->dev;
448 struct tc_cls_u32_offload u32_offload = {0}; 451 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 offload.type = TC_SETUP_CLSU32; 454 offload.type = TC_SETUP_CLSU32;
452 offload.cls_u32 = &u32_offload; 455 offload.cls_u32 = &u32_offload;
453 456
454 if (tc_should_offload(dev)) { 457 if (tc_should_offload(dev, flags)) {
455 offload.cls_u32->command = TC_CLSU32_NEW_HNODE; 458 offload.cls_u32->command = TC_CLSU32_NEW_HNODE;
456 offload.cls_u32->hnode.divisor = h->divisor; 459 offload.cls_u32->hnode.divisor = h->divisor;
457 offload.cls_u32->hnode.handle = h->handle; 460 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 offload.type = TC_SETUP_CLSU32; 474 offload.type = TC_SETUP_CLSU32;
472 offload.cls_u32 = &u32_offload; 475 offload.cls_u32 = &u32_offload;
473 476
474 if (tc_should_offload(dev)) { 477 if (tc_should_offload(dev, 0)) {
475 offload.cls_u32->command = TC_CLSU32_DELETE_HNODE; 478 offload.cls_u32->command = TC_CLSU32_DELETE_HNODE;
476 offload.cls_u32->hnode.divisor = h->divisor; 479 offload.cls_u32->hnode.divisor = h->divisor;
477 offload.cls_u32->hnode.handle = h->handle; 480 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 } 485 }
483} 486}
484 487
485static void u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n) 488static void u32_replace_hw_knode(struct tcf_proto *tp,
489 struct tc_u_knode *n,
490 u32 flags)
486{ 491{
487 struct net_device *dev = tp->q->dev_queue->dev; 492 struct net_device *dev = tp->q->dev_queue->dev;
488 struct tc_cls_u32_offload u32_offload = {0}; 493 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 offload.type = TC_SETUP_CLSU32; 496 offload.type = TC_SETUP_CLSU32;
492 offload.cls_u32 = &u32_offload; 497 offload.cls_u32 = &u32_offload;
493 498
494 if (tc_should_offload(dev)) { 499 if (tc_should_offload(dev, flags)) {
495 offload.cls_u32->command = TC_CLSU32_REPLACE_KNODE; 500 offload.cls_u32->command = TC_CLSU32_REPLACE_KNODE;
496 offload.cls_u32->knode.handle = n->handle; 501 offload.cls_u32->knode.handle = n->handle;
497 offload.cls_u32->knode.fshift = n->fshift; 502 offload.cls_u32->knode.fshift = n->fshift;
@@ -679,6 +684,7 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
679 [TCA_U32_SEL] = { .len = sizeof(struct tc_u32_sel) }, 684 [TCA_U32_SEL] = { .len = sizeof(struct tc_u32_sel) },
680 [TCA_U32_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, 685 [TCA_U32_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ },
681 [TCA_U32_MARK] = { .len = sizeof(struct tc_u32_mark) }, 686 [TCA_U32_MARK] = { .len = sizeof(struct tc_u32_mark) },
687 [TCA_U32_FLAGS] = { .type = NLA_U32 },
682}; 688};
683 689
684static int u32_set_parms(struct net *net, struct tcf_proto *tp, 690static 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#endif 792#endif
787 new->fshift = n->fshift; 793 new->fshift = n->fshift;
788 new->res = n->res; 794 new->res = n->res;
795 new->flags = n->flags;
789 RCU_INIT_POINTER(new->ht_down, n->ht_down); 796 RCU_INIT_POINTER(new->ht_down, n->ht_down);
790 797
791 /* bump reference count as long as we hold pointer to structure */ 798 /* 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 struct tc_u32_sel *s; 832 struct tc_u32_sel *s;
826 struct nlattr *opt = tca[TCA_OPTIONS]; 833 struct nlattr *opt = tca[TCA_OPTIONS];
827 struct nlattr *tb[TCA_U32_MAX + 1]; 834 struct nlattr *tb[TCA_U32_MAX + 1];
828 u32 htid; 835 u32 htid, flags = 0;
829 int err; 836 int err;
830#ifdef CONFIG_CLS_U32_PERF 837#ifdef CONFIG_CLS_U32_PERF
831 size_t size; 838 size_t size;
@@ -838,6 +845,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
838 if (err < 0) 845 if (err < 0)
839 return err; 846 return err;
840 847
848 if (tb[TCA_U32_FLAGS])
849 flags = nla_get_u32(tb[TCA_U32_FLAGS]);
850
841 n = (struct tc_u_knode *)*arg; 851 n = (struct tc_u_knode *)*arg;
842 if (n) { 852 if (n) {
843 struct tc_u_knode *new; 853 struct tc_u_knode *new;
@@ -845,6 +855,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
845 if (TC_U32_KEY(n->handle) == 0) 855 if (TC_U32_KEY(n->handle) == 0)
846 return -EINVAL; 856 return -EINVAL;
847 857
858 if (n->flags != flags)
859 return -EINVAL;
860
848 new = u32_init_knode(tp, n); 861 new = u32_init_knode(tp, n);
849 if (!new) 862 if (!new)
850 return -ENOMEM; 863 return -ENOMEM;
@@ -861,7 +874,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
861 u32_replace_knode(tp, tp_c, new); 874 u32_replace_knode(tp, tp_c, new);
862 tcf_unbind_filter(tp, &n->res); 875 tcf_unbind_filter(tp, &n->res);
863 call_rcu(&n->rcu, u32_delete_key_rcu); 876 call_rcu(&n->rcu, u32_delete_key_rcu);
864 u32_replace_hw_knode(tp, new); 877 u32_replace_hw_knode(tp, new, flags);
865 return 0; 878 return 0;
866 } 879 }
867 880
@@ -889,7 +902,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
889 rcu_assign_pointer(tp_c->hlist, ht); 902 rcu_assign_pointer(tp_c->hlist, ht);
890 *arg = (unsigned long)ht; 903 *arg = (unsigned long)ht;
891 904
892 u32_replace_hw_hnode(tp, ht); 905 u32_replace_hw_hnode(tp, ht, flags);
893 return 0; 906 return 0;
894 } 907 }
895 908
@@ -940,6 +953,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
940 RCU_INIT_POINTER(n->ht_up, ht); 953 RCU_INIT_POINTER(n->ht_up, ht);
941 n->handle = handle; 954 n->handle = handle;
942 n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; 955 n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
956 n->flags = flags;
943 tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE); 957 tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE);
944 n->tp = tp; 958 n->tp = tp;
945 959
@@ -972,7 +986,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
972 986
973 RCU_INIT_POINTER(n->next, pins); 987 RCU_INIT_POINTER(n->next, pins);
974 rcu_assign_pointer(*ins, n); 988 rcu_assign_pointer(*ins, n);
975 u32_replace_hw_knode(tp, n); 989 u32_replace_hw_knode(tp, n, flags);
976 *arg = (unsigned long)n; 990 *arg = (unsigned long)n;
977 return 0; 991 return 0;
978 } 992 }
@@ -1077,6 +1091,9 @@ static int u32_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
1077 nla_put_u32(skb, TCA_U32_LINK, ht_down->handle)) 1091 nla_put_u32(skb, TCA_U32_LINK, ht_down->handle))
1078 goto nla_put_failure; 1092 goto nla_put_failure;
1079 1093
1094 if (n->flags && nla_put_u32(skb, TCA_U32_FLAGS, n->flags))
1095 goto nla_put_failure;
1096
1080#ifdef CONFIG_CLS_U32_MARK 1097#ifdef CONFIG_CLS_U32_MARK
1081 if ((n->val || n->mask)) { 1098 if ((n->val || n->mask)) {
1082 struct tc_u32_mark mark = {.val = n->val, 1099 struct tc_u32_mark mark = {.val = n->val,