.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * net/sched/act_connmark.c netfilter connmark retriever action |
---|
3 | 4 | * skb mark is over-written |
---|
4 | 5 | * |
---|
5 | 6 | * 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. |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
21 | 17 | #include <net/netlink.h> |
---|
22 | 18 | #include <net/pkt_sched.h> |
---|
23 | 19 | #include <net/act_api.h> |
---|
| 20 | +#include <net/pkt_cls.h> |
---|
24 | 21 | #include <uapi/linux/tc_act/tc_connmark.h> |
---|
25 | 22 | #include <net/tc_act/tc_connmark.h> |
---|
26 | 23 | |
---|
.. | .. |
---|
65 | 62 | |
---|
66 | 63 | c = nf_ct_get(skb, &ctinfo); |
---|
67 | 64 | if (c) { |
---|
68 | | - skb->mark = c->mark; |
---|
| 65 | + skb->mark = READ_ONCE(c->mark); |
---|
69 | 66 | /* using overlimits stats to count how many packets marked */ |
---|
70 | 67 | ca->tcf_qstats.overlimits++; |
---|
71 | 68 | goto out; |
---|
.. | .. |
---|
85 | 82 | c = nf_ct_tuplehash_to_ctrack(thash); |
---|
86 | 83 | /* using overlimits stats to count how many packets marked */ |
---|
87 | 84 | ca->tcf_qstats.overlimits++; |
---|
88 | | - skb->mark = c->mark; |
---|
| 85 | + skb->mark = READ_ONCE(c->mark); |
---|
89 | 86 | nf_ct_put(c); |
---|
90 | 87 | |
---|
91 | 88 | out: |
---|
.. | .. |
---|
100 | 97 | static int tcf_connmark_init(struct net *net, struct nlattr *nla, |
---|
101 | 98 | struct nlattr *est, struct tc_action **a, |
---|
102 | 99 | int ovr, int bind, bool rtnl_held, |
---|
| 100 | + struct tcf_proto *tp, u32 flags, |
---|
103 | 101 | struct netlink_ext_ack *extack) |
---|
104 | 102 | { |
---|
105 | 103 | struct tc_action_net *tn = net_generic(net, connmark_net_id); |
---|
106 | 104 | struct nlattr *tb[TCA_CONNMARK_MAX + 1]; |
---|
| 105 | + struct tcf_chain *goto_ch = NULL; |
---|
107 | 106 | struct tcf_connmark_info *ci; |
---|
108 | 107 | struct tc_connmark *parm; |
---|
109 | | - int ret = 0; |
---|
| 108 | + int ret = 0, err; |
---|
110 | 109 | u32 index; |
---|
111 | 110 | |
---|
112 | 111 | if (!nla) |
---|
113 | 112 | return -EINVAL; |
---|
114 | 113 | |
---|
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); |
---|
117 | 116 | if (ret < 0) |
---|
118 | 117 | return ret; |
---|
119 | 118 | |
---|
.. | .. |
---|
125 | 124 | ret = tcf_idr_check_alloc(tn, &index, a, bind); |
---|
126 | 125 | if (!ret) { |
---|
127 | 126 | ret = tcf_idr_create(tn, index, est, a, |
---|
128 | | - &act_connmark_ops, bind, false); |
---|
| 127 | + &act_connmark_ops, bind, false, flags); |
---|
129 | 128 | if (ret) { |
---|
130 | 129 | tcf_idr_cleanup(tn, index); |
---|
131 | 130 | return ret; |
---|
132 | 131 | } |
---|
133 | 132 | |
---|
134 | 133 | 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); |
---|
136 | 139 | ci->net = net; |
---|
137 | 140 | ci->zone = parm->zone; |
---|
138 | 141 | |
---|
139 | | - tcf_idr_insert(tn, *a); |
---|
140 | 142 | ret = ACT_P_CREATED; |
---|
141 | 143 | } else if (ret > 0) { |
---|
142 | 144 | ci = to_connmark(*a); |
---|
.. | .. |
---|
146 | 148 | tcf_idr_release(*a, bind); |
---|
147 | 149 | return -EEXIST; |
---|
148 | 150 | } |
---|
| 151 | + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, |
---|
| 152 | + extack); |
---|
| 153 | + if (err < 0) |
---|
| 154 | + goto release_idr; |
---|
149 | 155 | /* 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); |
---|
151 | 158 | ci->zone = parm->zone; |
---|
| 159 | + spin_unlock_bh(&ci->tcf_lock); |
---|
| 160 | + if (goto_ch) |
---|
| 161 | + tcf_chain_put_by_act(goto_ch); |
---|
152 | 162 | ret = 0; |
---|
153 | 163 | } |
---|
154 | 164 | |
---|
155 | 165 | return ret; |
---|
| 166 | +release_idr: |
---|
| 167 | + tcf_idr_release(*a, bind); |
---|
| 168 | + return err; |
---|
156 | 169 | } |
---|
157 | 170 | |
---|
158 | 171 | static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a, |
---|
.. | .. |
---|
160 | 173 | { |
---|
161 | 174 | unsigned char *b = skb_tail_pointer(skb); |
---|
162 | 175 | struct tcf_connmark_info *ci = to_connmark(a); |
---|
163 | | - |
---|
164 | 176 | struct tc_connmark opt = { |
---|
165 | 177 | .index = ci->tcf_index, |
---|
166 | 178 | .refcnt = refcount_read(&ci->tcf_refcnt) - ref, |
---|
167 | 179 | .bindcnt = atomic_read(&ci->tcf_bindcnt) - bind, |
---|
168 | | - .action = ci->tcf_action, |
---|
169 | | - .zone = ci->zone, |
---|
170 | 180 | }; |
---|
171 | 181 | struct tcf_t t; |
---|
172 | 182 | |
---|
| 183 | + spin_lock_bh(&ci->tcf_lock); |
---|
| 184 | + opt.action = ci->tcf_action; |
---|
| 185 | + opt.zone = ci->zone; |
---|
173 | 186 | if (nla_put(skb, TCA_CONNMARK_PARMS, sizeof(opt), &opt)) |
---|
174 | 187 | goto nla_put_failure; |
---|
175 | 188 | |
---|
.. | .. |
---|
177 | 190 | if (nla_put_64bit(skb, TCA_CONNMARK_TM, sizeof(t), &t, |
---|
178 | 191 | TCA_CONNMARK_PAD)) |
---|
179 | 192 | goto nla_put_failure; |
---|
| 193 | + spin_unlock_bh(&ci->tcf_lock); |
---|
180 | 194 | |
---|
181 | 195 | return skb->len; |
---|
| 196 | + |
---|
182 | 197 | nla_put_failure: |
---|
| 198 | + spin_unlock_bh(&ci->tcf_lock); |
---|
183 | 199 | nlmsg_trim(skb, b); |
---|
184 | 200 | return -1; |
---|
185 | 201 | } |
---|
.. | .. |
---|
194 | 210 | return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
---|
195 | 211 | } |
---|
196 | 212 | |
---|
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) |
---|
199 | 214 | { |
---|
200 | 215 | struct tc_action_net *tn = net_generic(net, connmark_net_id); |
---|
201 | 216 | |
---|
.. | .. |
---|
204 | 219 | |
---|
205 | 220 | static struct tc_action_ops act_connmark_ops = { |
---|
206 | 221 | .kind = "connmark", |
---|
207 | | - .type = TCA_ACT_CONNMARK, |
---|
| 222 | + .id = TCA_ID_CONNMARK, |
---|
208 | 223 | .owner = THIS_MODULE, |
---|
209 | 224 | .act = tcf_connmark_act, |
---|
210 | 225 | .dump = tcf_connmark_dump, |
---|