diff options
-rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 | ||||
-rw-r--r-- | include/net/act_api.h | 4 | ||||
-rw-r--r-- | include/net/pkt_cls.h | 40 | ||||
-rw-r--r-- | net/sched/act_api.c | 11 | ||||
-rw-r--r-- | net/sched/cls_api.c | 51 |
7 files changed, 85 insertions, 41 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index ee57a89252bb..b4f03748adc0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
@@ -8396,12 +8396,14 @@ static int parse_tc_actions(struct ixgbe_adapter *adapter, | |||
8396 | struct tcf_exts *exts, u64 *action, u8 *queue) | 8396 | struct tcf_exts *exts, u64 *action, u8 *queue) |
8397 | { | 8397 | { |
8398 | const struct tc_action *a; | 8398 | const struct tc_action *a; |
8399 | LIST_HEAD(actions); | ||
8399 | int err; | 8400 | int err; |
8400 | 8401 | ||
8401 | if (tc_no_actions(exts)) | 8402 | if (tc_no_actions(exts)) |
8402 | return -EINVAL; | 8403 | return -EINVAL; |
8403 | 8404 | ||
8404 | tc_for_each_action(a, exts) { | 8405 | tcf_exts_to_list(exts, &actions); |
8406 | list_for_each_entry(a, &actions, list) { | ||
8405 | 8407 | ||
8406 | /* Drop action */ | 8408 | /* Drop action */ |
8407 | if (is_tcf_gact_shot(a)) { | 8409 | if (is_tcf_gact_shot(a)) { |
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 0f19b01e3fff..dc8b1cb0fdc8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | |||
@@ -318,6 +318,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, | |||
318 | u32 *action, u32 *flow_tag) | 318 | u32 *action, u32 *flow_tag) |
319 | { | 319 | { |
320 | const struct tc_action *a; | 320 | const struct tc_action *a; |
321 | LIST_HEAD(actions); | ||
321 | 322 | ||
322 | if (tc_no_actions(exts)) | 323 | if (tc_no_actions(exts)) |
323 | return -EINVAL; | 324 | return -EINVAL; |
@@ -325,7 +326,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, | |||
325 | *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; | 326 | *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; |
326 | *action = 0; | 327 | *action = 0; |
327 | 328 | ||
328 | tc_for_each_action(a, exts) { | 329 | tcf_exts_to_list(exts, &actions); |
330 | list_for_each_entry(a, &actions, list) { | ||
329 | /* Only support a single action per rule */ | 331 | /* Only support a single action per rule */ |
330 | if (*action) | 332 | if (*action) |
331 | return -EINVAL; | 333 | return -EINVAL; |
@@ -362,13 +364,15 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, | |||
362 | u32 *action, u32 *dest_vport) | 364 | u32 *action, u32 *dest_vport) |
363 | { | 365 | { |
364 | const struct tc_action *a; | 366 | const struct tc_action *a; |
367 | LIST_HEAD(actions); | ||
365 | 368 | ||
366 | if (tc_no_actions(exts)) | 369 | if (tc_no_actions(exts)) |
367 | return -EINVAL; | 370 | return -EINVAL; |
368 | 371 | ||
369 | *action = 0; | 372 | *action = 0; |
370 | 373 | ||
371 | tc_for_each_action(a, exts) { | 374 | tcf_exts_to_list(exts, &actions); |
375 | list_for_each_entry(a, &actions, list) { | ||
372 | /* Only support a single action per rule */ | 376 | /* Only support a single action per rule */ |
373 | if (*action) | 377 | if (*action) |
374 | return -EINVAL; | 378 | return -EINVAL; |
@@ -503,6 +507,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, | |||
503 | struct mlx5e_tc_flow *flow; | 507 | struct mlx5e_tc_flow *flow; |
504 | struct tc_action *a; | 508 | struct tc_action *a; |
505 | struct mlx5_fc *counter; | 509 | struct mlx5_fc *counter; |
510 | LIST_HEAD(actions); | ||
506 | u64 bytes; | 511 | u64 bytes; |
507 | u64 packets; | 512 | u64 packets; |
508 | u64 lastuse; | 513 | u64 lastuse; |
@@ -518,7 +523,8 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, | |||
518 | 523 | ||
519 | mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); | 524 | mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); |
520 | 525 | ||
521 | tc_for_each_action(a, f->exts) | 526 | tcf_exts_to_list(f->exts, &actions); |
527 | list_for_each_entry(a, &actions, list) | ||
522 | tcf_action_stats_update(a, bytes, packets, lastuse); | 528 | tcf_action_stats_update(a, bytes, packets, lastuse); |
523 | 529 | ||
524 | return 0; | 530 | return 0; |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 1fe9fbdc9102..1f8168906811 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c | |||
@@ -1121,6 +1121,7 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port, | |||
1121 | bool ingress) | 1121 | bool ingress) |
1122 | { | 1122 | { |
1123 | const struct tc_action *a; | 1123 | const struct tc_action *a; |
1124 | LIST_HEAD(actions); | ||
1124 | int err; | 1125 | int err; |
1125 | 1126 | ||
1126 | if (!tc_single_action(cls->exts)) { | 1127 | if (!tc_single_action(cls->exts)) { |
@@ -1128,7 +1129,8 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port, | |||
1128 | return -ENOTSUPP; | 1129 | return -ENOTSUPP; |
1129 | } | 1130 | } |
1130 | 1131 | ||
1131 | tc_for_each_action(a, cls->exts) { | 1132 | tcf_exts_to_list(cls->exts, &actions); |
1133 | list_for_each_entry(a, &actions, list) { | ||
1132 | if (!is_tcf_mirred_mirror(a) || protocol != htons(ETH_P_ALL)) | 1134 | if (!is_tcf_mirred_mirror(a) || protocol != htons(ETH_P_ALL)) |
1133 | return -ENOTSUPP; | 1135 | return -ENOTSUPP; |
1134 | 1136 | ||
diff --git a/include/net/act_api.h b/include/net/act_api.h index 870332ff61eb..82f3c912a5b1 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h | |||
@@ -176,8 +176,8 @@ int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops); | |||
176 | int tcf_unregister_action(struct tc_action_ops *a, | 176 | int tcf_unregister_action(struct tc_action_ops *a, |
177 | struct pernet_operations *ops); | 177 | struct pernet_operations *ops); |
178 | int tcf_action_destroy(struct list_head *actions, int bind); | 178 | int tcf_action_destroy(struct list_head *actions, int bind); |
179 | int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, | 179 | int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, |
180 | struct tcf_result *res); | 180 | int nr_actions, struct tcf_result *res); |
181 | int tcf_action_init(struct net *net, struct nlattr *nla, | 181 | int tcf_action_init(struct net *net, struct nlattr *nla, |
182 | struct nlattr *est, char *n, int ovr, | 182 | struct nlattr *est, char *n, int ovr, |
183 | int bind, struct list_head *); | 183 | int bind, struct list_head *); |
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 00dd5c4c1d0a..c99508d426cc 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h | |||
@@ -59,7 +59,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r) | |||
59 | struct tcf_exts { | 59 | struct tcf_exts { |
60 | #ifdef CONFIG_NET_CLS_ACT | 60 | #ifdef CONFIG_NET_CLS_ACT |
61 | __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ | 61 | __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ |
62 | struct list_head actions; | 62 | int nr_actions; |
63 | struct tc_action **actions; | ||
63 | #endif | 64 | #endif |
64 | /* Map to export classifier specific extension TLV types to the | 65 | /* Map to export classifier specific extension TLV types to the |
65 | * generic extensions API. Unsupported extensions must be set to 0. | 66 | * generic extensions API. Unsupported extensions must be set to 0. |
@@ -72,7 +73,10 @@ static inline void tcf_exts_init(struct tcf_exts *exts, int action, int police) | |||
72 | { | 73 | { |
73 | #ifdef CONFIG_NET_CLS_ACT | 74 | #ifdef CONFIG_NET_CLS_ACT |
74 | exts->type = 0; | 75 | exts->type = 0; |
75 | INIT_LIST_HEAD(&exts->actions); | 76 | exts->nr_actions = 0; |
77 | exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *), | ||
78 | GFP_KERNEL); | ||
79 | WARN_ON(!exts->actions); /* TODO: propagate the error to callers */ | ||
76 | #endif | 80 | #endif |
77 | exts->action = action; | 81 | exts->action = action; |
78 | exts->police = police; | 82 | exts->police = police; |
@@ -89,7 +93,7 @@ static inline int | |||
89 | tcf_exts_is_predicative(struct tcf_exts *exts) | 93 | tcf_exts_is_predicative(struct tcf_exts *exts) |
90 | { | 94 | { |
91 | #ifdef CONFIG_NET_CLS_ACT | 95 | #ifdef CONFIG_NET_CLS_ACT |
92 | return !list_empty(&exts->actions); | 96 | return exts->nr_actions; |
93 | #else | 97 | #else |
94 | return 0; | 98 | return 0; |
95 | #endif | 99 | #endif |
@@ -108,6 +112,20 @@ tcf_exts_is_available(struct tcf_exts *exts) | |||
108 | return tcf_exts_is_predicative(exts); | 112 | return tcf_exts_is_predicative(exts); |
109 | } | 113 | } |
110 | 114 | ||
115 | static inline void tcf_exts_to_list(const struct tcf_exts *exts, | ||
116 | struct list_head *actions) | ||
117 | { | ||
118 | #ifdef CONFIG_NET_CLS_ACT | ||
119 | int i; | ||
120 | |||
121 | for (i = 0; i < exts->nr_actions; i++) { | ||
122 | struct tc_action *a = exts->actions[i]; | ||
123 | |||
124 | list_add(&a->list, actions); | ||
125 | } | ||
126 | #endif | ||
127 | } | ||
128 | |||
111 | /** | 129 | /** |
112 | * tcf_exts_exec - execute tc filter extensions | 130 | * tcf_exts_exec - execute tc filter extensions |
113 | * @skb: socket buffer | 131 | * @skb: socket buffer |
@@ -124,27 +142,21 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts, | |||
124 | struct tcf_result *res) | 142 | struct tcf_result *res) |
125 | { | 143 | { |
126 | #ifdef CONFIG_NET_CLS_ACT | 144 | #ifdef CONFIG_NET_CLS_ACT |
127 | if (!list_empty(&exts->actions)) | 145 | if (exts->nr_actions) |
128 | return tcf_action_exec(skb, &exts->actions, res); | 146 | return tcf_action_exec(skb, exts->actions, exts->nr_actions, |
147 | res); | ||
129 | #endif | 148 | #endif |
130 | return 0; | 149 | return 0; |
131 | } | 150 | } |
132 | 151 | ||
133 | #ifdef CONFIG_NET_CLS_ACT | 152 | #ifdef CONFIG_NET_CLS_ACT |
134 | 153 | ||
135 | #define tc_no_actions(_exts) \ | 154 | #define tc_no_actions(_exts) ((_exts)->nr_actions == 0) |
136 | (list_empty(&(_exts)->actions)) | 155 | #define tc_single_action(_exts) ((_exts)->nr_actions == 1) |
137 | |||
138 | #define tc_for_each_action(_a, _exts) \ | ||
139 | list_for_each_entry(_a, &(_exts)->actions, list) | ||
140 | |||
141 | #define tc_single_action(_exts) \ | ||
142 | (list_is_singular(&(_exts)->actions)) | ||
143 | 156 | ||
144 | #else /* CONFIG_NET_CLS_ACT */ | 157 | #else /* CONFIG_NET_CLS_ACT */ |
145 | 158 | ||
146 | #define tc_no_actions(_exts) true | 159 | #define tc_no_actions(_exts) true |
147 | #define tc_for_each_action(_a, _exts) while ((void)(_a), 0) | ||
148 | #define tc_single_action(_exts) false | 160 | #define tc_single_action(_exts) false |
149 | 161 | ||
150 | #endif /* CONFIG_NET_CLS_ACT */ | 162 | #endif /* CONFIG_NET_CLS_ACT */ |
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index b4c7be38b632..d09d0687594b 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -420,18 +420,19 @@ static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) | |||
420 | return res; | 420 | return res; |
421 | } | 421 | } |
422 | 422 | ||
423 | int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, | 423 | int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, |
424 | struct tcf_result *res) | 424 | int nr_actions, struct tcf_result *res) |
425 | { | 425 | { |
426 | const struct tc_action *a; | 426 | int ret = -1, i; |
427 | int ret = -1; | ||
428 | 427 | ||
429 | if (skb->tc_verd & TC_NCLS) { | 428 | if (skb->tc_verd & TC_NCLS) { |
430 | skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); | 429 | skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); |
431 | ret = TC_ACT_OK; | 430 | ret = TC_ACT_OK; |
432 | goto exec_done; | 431 | goto exec_done; |
433 | } | 432 | } |
434 | list_for_each_entry(a, actions, list) { | 433 | for (i = 0; i < nr_actions; i++) { |
434 | const struct tc_action *a = actions[i]; | ||
435 | |||
435 | repeat: | 436 | repeat: |
436 | ret = a->ops->act(skb, a, res); | 437 | ret = a->ops->act(skb, a, res); |
437 | if (ret == TC_ACT_REPEAT) | 438 | if (ret == TC_ACT_REPEAT) |
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 843a716a4303..a7c5645373af 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
@@ -541,8 +541,12 @@ out: | |||
541 | void tcf_exts_destroy(struct tcf_exts *exts) | 541 | void tcf_exts_destroy(struct tcf_exts *exts) |
542 | { | 542 | { |
543 | #ifdef CONFIG_NET_CLS_ACT | 543 | #ifdef CONFIG_NET_CLS_ACT |
544 | tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); | 544 | LIST_HEAD(actions); |
545 | INIT_LIST_HEAD(&exts->actions); | 545 | |
546 | tcf_exts_to_list(exts, &actions); | ||
547 | tcf_action_destroy(&actions, TCA_ACT_UNBIND); | ||
548 | kfree(exts->actions); | ||
549 | exts->nr_actions = 0; | ||
546 | #endif | 550 | #endif |
547 | } | 551 | } |
548 | EXPORT_SYMBOL(tcf_exts_destroy); | 552 | EXPORT_SYMBOL(tcf_exts_destroy); |
@@ -554,7 +558,6 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, | |||
554 | { | 558 | { |
555 | struct tc_action *act; | 559 | struct tc_action *act; |
556 | 560 | ||
557 | INIT_LIST_HEAD(&exts->actions); | ||
558 | if (exts->police && tb[exts->police]) { | 561 | if (exts->police && tb[exts->police]) { |
559 | act = tcf_action_init_1(net, tb[exts->police], rate_tlv, | 562 | act = tcf_action_init_1(net, tb[exts->police], rate_tlv, |
560 | "police", ovr, | 563 | "police", ovr, |
@@ -563,14 +566,20 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, | |||
563 | return PTR_ERR(act); | 566 | return PTR_ERR(act); |
564 | 567 | ||
565 | act->type = exts->type = TCA_OLD_COMPAT; | 568 | act->type = exts->type = TCA_OLD_COMPAT; |
566 | list_add(&act->list, &exts->actions); | 569 | exts->actions[0] = act; |
570 | exts->nr_actions = 1; | ||
567 | } else if (exts->action && tb[exts->action]) { | 571 | } else if (exts->action && tb[exts->action]) { |
568 | int err; | 572 | LIST_HEAD(actions); |
573 | int err, i = 0; | ||
574 | |||
569 | err = tcf_action_init(net, tb[exts->action], rate_tlv, | 575 | err = tcf_action_init(net, tb[exts->action], rate_tlv, |
570 | NULL, ovr, | 576 | NULL, ovr, |
571 | TCA_ACT_BIND, &exts->actions); | 577 | TCA_ACT_BIND, &actions); |
572 | if (err) | 578 | if (err) |
573 | return err; | 579 | return err; |
580 | list_for_each_entry(act, &actions, list) | ||
581 | exts->actions[i++] = act; | ||
582 | exts->nr_actions = i; | ||
574 | } | 583 | } |
575 | } | 584 | } |
576 | #else | 585 | #else |
@@ -587,37 +596,49 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, | |||
587 | struct tcf_exts *src) | 596 | struct tcf_exts *src) |
588 | { | 597 | { |
589 | #ifdef CONFIG_NET_CLS_ACT | 598 | #ifdef CONFIG_NET_CLS_ACT |
590 | LIST_HEAD(tmp); | 599 | struct tcf_exts old = *dst; |
600 | |||
591 | tcf_tree_lock(tp); | 601 | tcf_tree_lock(tp); |
592 | list_splice_init(&dst->actions, &tmp); | 602 | dst->nr_actions = src->nr_actions; |
593 | list_splice(&src->actions, &dst->actions); | 603 | dst->actions = src->actions; |
594 | dst->type = src->type; | 604 | dst->type = src->type; |
595 | tcf_tree_unlock(tp); | 605 | tcf_tree_unlock(tp); |
596 | tcf_action_destroy(&tmp, TCA_ACT_UNBIND); | 606 | |
607 | tcf_exts_destroy(&old); | ||
597 | #endif | 608 | #endif |
598 | } | 609 | } |
599 | EXPORT_SYMBOL(tcf_exts_change); | 610 | EXPORT_SYMBOL(tcf_exts_change); |
600 | 611 | ||
601 | #define tcf_exts_first_act(ext) \ | 612 | #ifdef CONFIG_NET_CLS_ACT |
602 | list_first_entry_or_null(&(exts)->actions, \ | 613 | static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts) |
603 | struct tc_action, list) | 614 | { |
615 | if (exts->nr_actions == 0) | ||
616 | return NULL; | ||
617 | else | ||
618 | return exts->actions[0]; | ||
619 | } | ||
620 | #endif | ||
604 | 621 | ||
605 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) | 622 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) |
606 | { | 623 | { |
607 | #ifdef CONFIG_NET_CLS_ACT | 624 | #ifdef CONFIG_NET_CLS_ACT |
608 | struct nlattr *nest; | 625 | struct nlattr *nest; |
609 | 626 | ||
610 | if (exts->action && !list_empty(&exts->actions)) { | 627 | if (exts->action && exts->nr_actions) { |
611 | /* | 628 | /* |
612 | * again for backward compatible mode - we want | 629 | * again for backward compatible mode - we want |
613 | * to work with both old and new modes of entering | 630 | * to work with both old and new modes of entering |
614 | * tc data even if iproute2 was newer - jhs | 631 | * tc data even if iproute2 was newer - jhs |
615 | */ | 632 | */ |
616 | if (exts->type != TCA_OLD_COMPAT) { | 633 | if (exts->type != TCA_OLD_COMPAT) { |
634 | LIST_HEAD(actions); | ||
635 | |||
617 | nest = nla_nest_start(skb, exts->action); | 636 | nest = nla_nest_start(skb, exts->action); |
618 | if (nest == NULL) | 637 | if (nest == NULL) |
619 | goto nla_put_failure; | 638 | goto nla_put_failure; |
620 | if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0) | 639 | |
640 | tcf_exts_to_list(exts, &actions); | ||
641 | if (tcf_action_dump(skb, &actions, 0, 0) < 0) | ||
621 | goto nla_put_failure; | 642 | goto nla_put_failure; |
622 | nla_nest_end(skb, nest); | 643 | nla_nest_end(skb, nest); |
623 | } else if (exts->police) { | 644 | } else if (exts->police) { |