diff options
-rw-r--r-- | include/net/pkt_cls.h | 13 | ||||
-rw-r--r-- | include/uapi/linux/pkt_cls.h | 1 | ||||
-rw-r--r-- | net/sched/cls_u32.c | 37 |
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 | ||
395 | static inline bool tc_should_offload(struct net_device *dev) | 395 | /* tca flags definitions */ |
396 | #define TCA_CLS_FLAGS_SKIP_HW 1 | ||
397 | |||
398 | static 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 | ||
445 | static void u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) | 446 | static 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 | ||
485 | static void u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n) | 488 | static 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 | ||
684 | static int u32_set_parms(struct net *net, struct tcf_proto *tp, | 690 | 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 | #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, |