diff options
author | David S. Miller <davem@davemloft.net> | 2016-05-10 23:50:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-10 23:50:16 -0400 |
commit | 6e14313f01f02f324d5dd68a49d34ec1e4bb569e (patch) | |
tree | 9df50855210ff3adbf60291dfba1ea284370d9e0 /net | |
parent | 84a527a41f38a80353f185d05e41b021e1ff672b (diff) | |
parent | 4e8c861550105f7aaa85a19b2571151cb8eceaa2 (diff) |
Merge branch 'net-sched-fixes'
Jamal Hadi Salim says:
====================
Some actions were broken in allowing for late binding of actions.
Late binding workflow is as follows:
a) create an action and provide all necessary parameters for it
Optionally provide an index or let the kernel give you one.
Example:
sudo tc actions add action police rate 1kbit burst 90k drop index 1
b) later on bind to the pre-created action from a filter definition
by merely specifying the index.
Example:
sudo tc filter add dev lo parent ffff: protocol ip prio 8 \
u32 match ip src 127.0.0.8/32 flowid 1:8 action police index 1
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/act_ife.c | 14 | ||||
-rw-r--r-- | net/sched/act_ipt.c | 19 | ||||
-rw-r--r-- | net/sched/act_mirred.c | 19 | ||||
-rw-r--r-- | net/sched/act_simple.c | 18 | ||||
-rw-r--r-- | net/sched/act_skbedit.c | 18 | ||||
-rw-r--r-- | net/sched/act_vlan.c | 22 |
6 files changed, 74 insertions, 36 deletions
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index c589a9ba506a..343d011aa818 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c | |||
@@ -423,7 +423,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, | |||
423 | u16 ife_type = 0; | 423 | u16 ife_type = 0; |
424 | u8 *daddr = NULL; | 424 | u8 *daddr = NULL; |
425 | u8 *saddr = NULL; | 425 | u8 *saddr = NULL; |
426 | int ret = 0; | 426 | int ret = 0, exists = 0; |
427 | int err; | 427 | int err; |
428 | 428 | ||
429 | err = nla_parse_nested(tb, TCA_IFE_MAX, nla, ife_policy); | 429 | err = nla_parse_nested(tb, TCA_IFE_MAX, nla, ife_policy); |
@@ -435,25 +435,29 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, | |||
435 | 435 | ||
436 | parm = nla_data(tb[TCA_IFE_PARMS]); | 436 | parm = nla_data(tb[TCA_IFE_PARMS]); |
437 | 437 | ||
438 | exists = tcf_hash_check(tn, parm->index, a, bind); | ||
439 | if (exists && bind) | ||
440 | return 0; | ||
441 | |||
438 | if (parm->flags & IFE_ENCODE) { | 442 | if (parm->flags & IFE_ENCODE) { |
439 | /* Until we get issued the ethertype, we cant have | 443 | /* Until we get issued the ethertype, we cant have |
440 | * a default.. | 444 | * a default.. |
441 | **/ | 445 | **/ |
442 | if (!tb[TCA_IFE_TYPE]) { | 446 | if (!tb[TCA_IFE_TYPE]) { |
447 | if (exists) | ||
448 | tcf_hash_release(a, bind); | ||
443 | pr_info("You MUST pass etherype for encoding\n"); | 449 | pr_info("You MUST pass etherype for encoding\n"); |
444 | return -EINVAL; | 450 | return -EINVAL; |
445 | } | 451 | } |
446 | } | 452 | } |
447 | 453 | ||
448 | if (!tcf_hash_check(tn, parm->index, a, bind)) { | 454 | if (!exists) { |
449 | ret = tcf_hash_create(tn, parm->index, est, a, sizeof(*ife), | 455 | ret = tcf_hash_create(tn, parm->index, est, a, sizeof(*ife), |
450 | bind, false); | 456 | bind, false); |
451 | if (ret) | 457 | if (ret) |
452 | return ret; | 458 | return ret; |
453 | ret = ACT_P_CREATED; | 459 | ret = ACT_P_CREATED; |
454 | } else { | 460 | } else { |
455 | if (bind) /* dont override defaults */ | ||
456 | return 0; | ||
457 | tcf_hash_release(a, bind); | 461 | tcf_hash_release(a, bind); |
458 | if (!ovr) | 462 | if (!ovr) |
459 | return -EEXIST; | 463 | return -EEXIST; |
@@ -495,6 +499,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, | |||
495 | NULL); | 499 | NULL); |
496 | if (err) { | 500 | if (err) { |
497 | metadata_parse_err: | 501 | metadata_parse_err: |
502 | if (exists) | ||
503 | tcf_hash_release(a, bind); | ||
498 | if (ret == ACT_P_CREATED) | 504 | if (ret == ACT_P_CREATED) |
499 | _tcf_ife_cleanup(a, bind); | 505 | _tcf_ife_cleanup(a, bind); |
500 | 506 | ||
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 350e134cffb3..8b5270008a6e 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
@@ -96,7 +96,7 @@ static int __tcf_ipt_init(struct tc_action_net *tn, struct nlattr *nla, | |||
96 | struct tcf_ipt *ipt; | 96 | struct tcf_ipt *ipt; |
97 | struct xt_entry_target *td, *t; | 97 | struct xt_entry_target *td, *t; |
98 | char *tname; | 98 | char *tname; |
99 | int ret = 0, err; | 99 | int ret = 0, err, exists = 0; |
100 | u32 hook = 0; | 100 | u32 hook = 0; |
101 | u32 index = 0; | 101 | u32 index = 0; |
102 | 102 | ||
@@ -107,18 +107,23 @@ static int __tcf_ipt_init(struct tc_action_net *tn, struct nlattr *nla, | |||
107 | if (err < 0) | 107 | if (err < 0) |
108 | return err; | 108 | return err; |
109 | 109 | ||
110 | if (tb[TCA_IPT_HOOK] == NULL) | 110 | if (tb[TCA_IPT_INDEX] != NULL) |
111 | return -EINVAL; | 111 | index = nla_get_u32(tb[TCA_IPT_INDEX]); |
112 | if (tb[TCA_IPT_TARG] == NULL) | 112 | |
113 | exists = tcf_hash_check(tn, index, a, bind); | ||
114 | if (exists && bind) | ||
115 | return 0; | ||
116 | |||
117 | if (tb[TCA_IPT_HOOK] == NULL || tb[TCA_IPT_TARG] == NULL) { | ||
118 | if (exists) | ||
119 | tcf_hash_release(a, bind); | ||
113 | return -EINVAL; | 120 | return -EINVAL; |
121 | } | ||
114 | 122 | ||
115 | td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); | 123 | td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); |
116 | if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) | 124 | if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) |
117 | return -EINVAL; | 125 | return -EINVAL; |
118 | 126 | ||
119 | if (tb[TCA_IPT_INDEX] != NULL) | ||
120 | index = nla_get_u32(tb[TCA_IPT_INDEX]); | ||
121 | |||
122 | if (!tcf_hash_check(tn, index, a, bind)) { | 127 | if (!tcf_hash_check(tn, index, a, bind)) { |
123 | ret = tcf_hash_create(tn, index, est, a, sizeof(*ipt), bind, | 128 | ret = tcf_hash_create(tn, index, est, a, sizeof(*ipt), bind, |
124 | false); | 129 | false); |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index e8a760cf7775..8f3948dd38b8 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
@@ -61,7 +61,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, | |||
61 | struct tc_mirred *parm; | 61 | struct tc_mirred *parm; |
62 | struct tcf_mirred *m; | 62 | struct tcf_mirred *m; |
63 | struct net_device *dev; | 63 | struct net_device *dev; |
64 | int ret, ok_push = 0; | 64 | int ret, ok_push = 0, exists = 0; |
65 | 65 | ||
66 | if (nla == NULL) | 66 | if (nla == NULL) |
67 | return -EINVAL; | 67 | return -EINVAL; |
@@ -71,17 +71,27 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, | |||
71 | if (tb[TCA_MIRRED_PARMS] == NULL) | 71 | if (tb[TCA_MIRRED_PARMS] == NULL) |
72 | return -EINVAL; | 72 | return -EINVAL; |
73 | parm = nla_data(tb[TCA_MIRRED_PARMS]); | 73 | parm = nla_data(tb[TCA_MIRRED_PARMS]); |
74 | |||
75 | exists = tcf_hash_check(tn, parm->index, a, bind); | ||
76 | if (exists && bind) | ||
77 | return 0; | ||
78 | |||
74 | switch (parm->eaction) { | 79 | switch (parm->eaction) { |
75 | case TCA_EGRESS_MIRROR: | 80 | case TCA_EGRESS_MIRROR: |
76 | case TCA_EGRESS_REDIR: | 81 | case TCA_EGRESS_REDIR: |
77 | break; | 82 | break; |
78 | default: | 83 | default: |
84 | if (exists) | ||
85 | tcf_hash_release(a, bind); | ||
79 | return -EINVAL; | 86 | return -EINVAL; |
80 | } | 87 | } |
81 | if (parm->ifindex) { | 88 | if (parm->ifindex) { |
82 | dev = __dev_get_by_index(net, parm->ifindex); | 89 | dev = __dev_get_by_index(net, parm->ifindex); |
83 | if (dev == NULL) | 90 | if (dev == NULL) { |
91 | if (exists) | ||
92 | tcf_hash_release(a, bind); | ||
84 | return -ENODEV; | 93 | return -ENODEV; |
94 | } | ||
85 | switch (dev->type) { | 95 | switch (dev->type) { |
86 | case ARPHRD_TUNNEL: | 96 | case ARPHRD_TUNNEL: |
87 | case ARPHRD_TUNNEL6: | 97 | case ARPHRD_TUNNEL6: |
@@ -99,7 +109,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, | |||
99 | dev = NULL; | 109 | dev = NULL; |
100 | } | 110 | } |
101 | 111 | ||
102 | if (!tcf_hash_check(tn, parm->index, a, bind)) { | 112 | if (!exists) { |
103 | if (dev == NULL) | 113 | if (dev == NULL) |
104 | return -EINVAL; | 114 | return -EINVAL; |
105 | ret = tcf_hash_create(tn, parm->index, est, a, | 115 | ret = tcf_hash_create(tn, parm->index, est, a, |
@@ -108,9 +118,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, | |||
108 | return ret; | 118 | return ret; |
109 | ret = ACT_P_CREATED; | 119 | ret = ACT_P_CREATED; |
110 | } else { | 120 | } else { |
111 | if (bind) | ||
112 | return 0; | ||
113 | |||
114 | tcf_hash_release(a, bind); | 121 | tcf_hash_release(a, bind); |
115 | if (!ovr) | 122 | if (!ovr) |
116 | return -EEXIST; | 123 | return -EEXIST; |
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 75b2be13fbcc..3a33fb648a6d 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c | |||
@@ -87,7 +87,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, | |||
87 | struct tc_defact *parm; | 87 | struct tc_defact *parm; |
88 | struct tcf_defact *d; | 88 | struct tcf_defact *d; |
89 | char *defdata; | 89 | char *defdata; |
90 | int ret = 0, err; | 90 | int ret = 0, err, exists = 0; |
91 | 91 | ||
92 | if (nla == NULL) | 92 | if (nla == NULL) |
93 | return -EINVAL; | 93 | return -EINVAL; |
@@ -99,13 +99,21 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, | |||
99 | if (tb[TCA_DEF_PARMS] == NULL) | 99 | if (tb[TCA_DEF_PARMS] == NULL) |
100 | return -EINVAL; | 100 | return -EINVAL; |
101 | 101 | ||
102 | if (tb[TCA_DEF_DATA] == NULL) | ||
103 | return -EINVAL; | ||
104 | 102 | ||
105 | parm = nla_data(tb[TCA_DEF_PARMS]); | 103 | parm = nla_data(tb[TCA_DEF_PARMS]); |
104 | exists = tcf_hash_check(tn, parm->index, a, bind); | ||
105 | if (exists && bind) | ||
106 | return 0; | ||
107 | |||
108 | if (tb[TCA_DEF_DATA] == NULL) { | ||
109 | if (exists) | ||
110 | tcf_hash_release(a, bind); | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | |||
106 | defdata = nla_data(tb[TCA_DEF_DATA]); | 114 | defdata = nla_data(tb[TCA_DEF_DATA]); |
107 | 115 | ||
108 | if (!tcf_hash_check(tn, parm->index, a, bind)) { | 116 | if (!exists) { |
109 | ret = tcf_hash_create(tn, parm->index, est, a, | 117 | ret = tcf_hash_create(tn, parm->index, est, a, |
110 | sizeof(*d), bind, false); | 118 | sizeof(*d), bind, false); |
111 | if (ret) | 119 | if (ret) |
@@ -122,8 +130,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, | |||
122 | } else { | 130 | } else { |
123 | d = to_defact(a); | 131 | d = to_defact(a); |
124 | 132 | ||
125 | if (bind) | ||
126 | return 0; | ||
127 | tcf_hash_release(a, bind); | 133 | tcf_hash_release(a, bind); |
128 | if (!ovr) | 134 | if (!ovr) |
129 | return -EEXIST; | 135 | return -EEXIST; |
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index cfcdbdc00c9b..69da5a8f0034 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c | |||
@@ -69,7 +69,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
69 | struct tcf_skbedit *d; | 69 | struct tcf_skbedit *d; |
70 | u32 flags = 0, *priority = NULL, *mark = NULL; | 70 | u32 flags = 0, *priority = NULL, *mark = NULL; |
71 | u16 *queue_mapping = NULL; | 71 | u16 *queue_mapping = NULL; |
72 | int ret = 0, err; | 72 | int ret = 0, err, exists = 0; |
73 | 73 | ||
74 | if (nla == NULL) | 74 | if (nla == NULL) |
75 | return -EINVAL; | 75 | return -EINVAL; |
@@ -96,12 +96,18 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
96 | mark = nla_data(tb[TCA_SKBEDIT_MARK]); | 96 | mark = nla_data(tb[TCA_SKBEDIT_MARK]); |
97 | } | 97 | } |
98 | 98 | ||
99 | if (!flags) | ||
100 | return -EINVAL; | ||
101 | |||
102 | parm = nla_data(tb[TCA_SKBEDIT_PARMS]); | 99 | parm = nla_data(tb[TCA_SKBEDIT_PARMS]); |
103 | 100 | ||
104 | if (!tcf_hash_check(tn, parm->index, a, bind)) { | 101 | exists = tcf_hash_check(tn, parm->index, a, bind); |
102 | if (exists && bind) | ||
103 | return 0; | ||
104 | |||
105 | if (!flags) { | ||
106 | tcf_hash_release(a, bind); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | if (!exists) { | ||
105 | ret = tcf_hash_create(tn, parm->index, est, a, | 111 | ret = tcf_hash_create(tn, parm->index, est, a, |
106 | sizeof(*d), bind, false); | 112 | sizeof(*d), bind, false); |
107 | if (ret) | 113 | if (ret) |
@@ -111,8 +117,6 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, | |||
111 | ret = ACT_P_CREATED; | 117 | ret = ACT_P_CREATED; |
112 | } else { | 118 | } else { |
113 | d = to_skbedit(a); | 119 | d = to_skbedit(a); |
114 | if (bind) | ||
115 | return 0; | ||
116 | tcf_hash_release(a, bind); | 120 | tcf_hash_release(a, bind); |
117 | if (!ovr) | 121 | if (!ovr) |
118 | return -EEXIST; | 122 | return -EEXIST; |
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index bab8ae0cefc0..c45f926dafb9 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c | |||
@@ -77,7 +77,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, | |||
77 | int action; | 77 | int action; |
78 | __be16 push_vid = 0; | 78 | __be16 push_vid = 0; |
79 | __be16 push_proto = 0; | 79 | __be16 push_proto = 0; |
80 | int ret = 0; | 80 | int ret = 0, exists = 0; |
81 | int err; | 81 | int err; |
82 | 82 | ||
83 | if (!nla) | 83 | if (!nla) |
@@ -90,15 +90,25 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, | |||
90 | if (!tb[TCA_VLAN_PARMS]) | 90 | if (!tb[TCA_VLAN_PARMS]) |
91 | return -EINVAL; | 91 | return -EINVAL; |
92 | parm = nla_data(tb[TCA_VLAN_PARMS]); | 92 | parm = nla_data(tb[TCA_VLAN_PARMS]); |
93 | exists = tcf_hash_check(tn, parm->index, a, bind); | ||
94 | if (exists && bind) | ||
95 | return 0; | ||
96 | |||
93 | switch (parm->v_action) { | 97 | switch (parm->v_action) { |
94 | case TCA_VLAN_ACT_POP: | 98 | case TCA_VLAN_ACT_POP: |
95 | break; | 99 | break; |
96 | case TCA_VLAN_ACT_PUSH: | 100 | case TCA_VLAN_ACT_PUSH: |
97 | if (!tb[TCA_VLAN_PUSH_VLAN_ID]) | 101 | if (!tb[TCA_VLAN_PUSH_VLAN_ID]) { |
102 | if (exists) | ||
103 | tcf_hash_release(a, bind); | ||
98 | return -EINVAL; | 104 | return -EINVAL; |
105 | } | ||
99 | push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); | 106 | push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); |
100 | if (push_vid >= VLAN_VID_MASK) | 107 | if (push_vid >= VLAN_VID_MASK) { |
108 | if (exists) | ||
109 | tcf_hash_release(a, bind); | ||
101 | return -ERANGE; | 110 | return -ERANGE; |
111 | } | ||
102 | 112 | ||
103 | if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { | 113 | if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { |
104 | push_proto = nla_get_be16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]); | 114 | push_proto = nla_get_be16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]); |
@@ -114,11 +124,13 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, | |||
114 | } | 124 | } |
115 | break; | 125 | break; |
116 | default: | 126 | default: |
127 | if (exists) | ||
128 | tcf_hash_release(a, bind); | ||
117 | return -EINVAL; | 129 | return -EINVAL; |
118 | } | 130 | } |
119 | action = parm->v_action; | 131 | action = parm->v_action; |
120 | 132 | ||
121 | if (!tcf_hash_check(tn, parm->index, a, bind)) { | 133 | if (!exists) { |
122 | ret = tcf_hash_create(tn, parm->index, est, a, | 134 | ret = tcf_hash_create(tn, parm->index, est, a, |
123 | sizeof(*v), bind, false); | 135 | sizeof(*v), bind, false); |
124 | if (ret) | 136 | if (ret) |
@@ -126,8 +138,6 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, | |||
126 | 138 | ||
127 | ret = ACT_P_CREATED; | 139 | ret = ACT_P_CREATED; |
128 | } else { | 140 | } else { |
129 | if (bind) | ||
130 | return 0; | ||
131 | tcf_hash_release(a, bind); | 141 | tcf_hash_release(a, bind); |
132 | if (!ovr) | 142 | if (!ovr) |
133 | return -EEXIST; | 143 | return -EEXIST; |