hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/net/sched/act_connmark.c
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * net/sched/act_connmark.c netfilter connmark retriever action
34 * skb mark is over-written
45 *
56 * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version.
117 */
128
139 #include <linux/module.h>
....@@ -21,6 +17,7 @@
2117 #include <net/netlink.h>
2218 #include <net/pkt_sched.h>
2319 #include <net/act_api.h>
20
+#include <net/pkt_cls.h>
2421 #include <uapi/linux/tc_act/tc_connmark.h>
2522 #include <net/tc_act/tc_connmark.h>
2623
....@@ -65,7 +62,7 @@
6562
6663 c = nf_ct_get(skb, &ctinfo);
6764 if (c) {
68
- skb->mark = c->mark;
65
+ skb->mark = READ_ONCE(c->mark);
6966 /* using overlimits stats to count how many packets marked */
7067 ca->tcf_qstats.overlimits++;
7168 goto out;
....@@ -85,7 +82,7 @@
8582 c = nf_ct_tuplehash_to_ctrack(thash);
8683 /* using overlimits stats to count how many packets marked */
8784 ca->tcf_qstats.overlimits++;
88
- skb->mark = c->mark;
85
+ skb->mark = READ_ONCE(c->mark);
8986 nf_ct_put(c);
9087
9188 out:
....@@ -100,20 +97,22 @@
10097 static int tcf_connmark_init(struct net *net, struct nlattr *nla,
10198 struct nlattr *est, struct tc_action **a,
10299 int ovr, int bind, bool rtnl_held,
100
+ struct tcf_proto *tp, u32 flags,
103101 struct netlink_ext_ack *extack)
104102 {
105103 struct tc_action_net *tn = net_generic(net, connmark_net_id);
106104 struct nlattr *tb[TCA_CONNMARK_MAX + 1];
105
+ struct tcf_chain *goto_ch = NULL;
107106 struct tcf_connmark_info *ci;
108107 struct tc_connmark *parm;
109
- int ret = 0;
108
+ int ret = 0, err;
110109 u32 index;
111110
112111 if (!nla)
113112 return -EINVAL;
114113
115
- ret = nla_parse_nested(tb, TCA_CONNMARK_MAX, nla, connmark_policy,
116
- NULL);
114
+ ret = nla_parse_nested_deprecated(tb, TCA_CONNMARK_MAX, nla,
115
+ connmark_policy, NULL);
117116 if (ret < 0)
118117 return ret;
119118
....@@ -125,18 +124,21 @@
125124 ret = tcf_idr_check_alloc(tn, &index, a, bind);
126125 if (!ret) {
127126 ret = tcf_idr_create(tn, index, est, a,
128
- &act_connmark_ops, bind, false);
127
+ &act_connmark_ops, bind, false, flags);
129128 if (ret) {
130129 tcf_idr_cleanup(tn, index);
131130 return ret;
132131 }
133132
134133 ci = to_connmark(*a);
135
- ci->tcf_action = parm->action;
134
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch,
135
+ extack);
136
+ if (err < 0)
137
+ goto release_idr;
138
+ tcf_action_set_ctrlact(*a, parm->action, goto_ch);
136139 ci->net = net;
137140 ci->zone = parm->zone;
138141
139
- tcf_idr_insert(tn, *a);
140142 ret = ACT_P_CREATED;
141143 } else if (ret > 0) {
142144 ci = to_connmark(*a);
....@@ -146,13 +148,24 @@
146148 tcf_idr_release(*a, bind);
147149 return -EEXIST;
148150 }
151
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch,
152
+ extack);
153
+ if (err < 0)
154
+ goto release_idr;
149155 /* replacing action and zone */
150
- ci->tcf_action = parm->action;
156
+ spin_lock_bh(&ci->tcf_lock);
157
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
151158 ci->zone = parm->zone;
159
+ spin_unlock_bh(&ci->tcf_lock);
160
+ if (goto_ch)
161
+ tcf_chain_put_by_act(goto_ch);
152162 ret = 0;
153163 }
154164
155165 return ret;
166
+release_idr:
167
+ tcf_idr_release(*a, bind);
168
+ return err;
156169 }
157170
158171 static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
....@@ -160,16 +173,16 @@
160173 {
161174 unsigned char *b = skb_tail_pointer(skb);
162175 struct tcf_connmark_info *ci = to_connmark(a);
163
-
164176 struct tc_connmark opt = {
165177 .index = ci->tcf_index,
166178 .refcnt = refcount_read(&ci->tcf_refcnt) - ref,
167179 .bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
168
- .action = ci->tcf_action,
169
- .zone = ci->zone,
170180 };
171181 struct tcf_t t;
172182
183
+ spin_lock_bh(&ci->tcf_lock);
184
+ opt.action = ci->tcf_action;
185
+ opt.zone = ci->zone;
173186 if (nla_put(skb, TCA_CONNMARK_PARMS, sizeof(opt), &opt))
174187 goto nla_put_failure;
175188
....@@ -177,9 +190,12 @@
177190 if (nla_put_64bit(skb, TCA_CONNMARK_TM, sizeof(t), &t,
178191 TCA_CONNMARK_PAD))
179192 goto nla_put_failure;
193
+ spin_unlock_bh(&ci->tcf_lock);
180194
181195 return skb->len;
196
+
182197 nla_put_failure:
198
+ spin_unlock_bh(&ci->tcf_lock);
183199 nlmsg_trim(skb, b);
184200 return -1;
185201 }
....@@ -194,8 +210,7 @@
194210 return tcf_generic_walker(tn, skb, cb, type, ops, extack);
195211 }
196212
197
-static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index,
198
- struct netlink_ext_ack *extack)
213
+static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index)
199214 {
200215 struct tc_action_net *tn = net_generic(net, connmark_net_id);
201216
....@@ -204,7 +219,7 @@
204219
205220 static struct tc_action_ops act_connmark_ops = {
206221 .kind = "connmark",
207
- .type = TCA_ACT_CONNMARK,
222
+ .id = TCA_ID_CONNMARK,
208223 .owner = THIS_MODULE,
209224 .act = tcf_connmark_act,
210225 .dump = tcf_connmark_dump,