@@ -39,6 +39,7 @@ struct cls_bpf_prog {
39
39
struct list_head link ;
40
40
struct tcf_result res ;
41
41
bool exts_integrated ;
42
+ bool offloaded ;
42
43
struct tcf_exts exts ;
43
44
u32 handle ;
44
45
union {
@@ -138,6 +139,71 @@ static bool cls_bpf_is_ebpf(const struct cls_bpf_prog *prog)
138
139
return !prog -> bpf_ops ;
139
140
}
140
141
142
+ static int cls_bpf_offload_cmd (struct tcf_proto * tp , struct cls_bpf_prog * prog ,
143
+ enum tc_clsbpf_command cmd )
144
+ {
145
+ struct net_device * dev = tp -> q -> dev_queue -> dev ;
146
+ struct tc_cls_bpf_offload bpf_offload = {};
147
+ struct tc_to_netdev offload ;
148
+
149
+ offload .type = TC_SETUP_CLSBPF ;
150
+ offload .cls_bpf = & bpf_offload ;
151
+
152
+ bpf_offload .command = cmd ;
153
+ bpf_offload .exts = & prog -> exts ;
154
+ bpf_offload .prog = prog -> filter ;
155
+ bpf_offload .name = prog -> bpf_name ;
156
+ bpf_offload .exts_integrated = prog -> exts_integrated ;
157
+
158
+ return dev -> netdev_ops -> ndo_setup_tc (dev , tp -> q -> handle ,
159
+ tp -> protocol , & offload );
160
+ }
161
+
162
+ static void cls_bpf_offload (struct tcf_proto * tp , struct cls_bpf_prog * prog ,
163
+ struct cls_bpf_prog * oldprog )
164
+ {
165
+ struct net_device * dev = tp -> q -> dev_queue -> dev ;
166
+ struct cls_bpf_prog * obj = prog ;
167
+ enum tc_clsbpf_command cmd ;
168
+
169
+ if (oldprog && oldprog -> offloaded ) {
170
+ if (tc_should_offload (dev , tp , 0 )) {
171
+ cmd = TC_CLSBPF_REPLACE ;
172
+ } else {
173
+ obj = oldprog ;
174
+ cmd = TC_CLSBPF_DESTROY ;
175
+ }
176
+ } else {
177
+ if (!tc_should_offload (dev , tp , 0 ))
178
+ return ;
179
+ cmd = TC_CLSBPF_ADD ;
180
+ }
181
+
182
+ if (cls_bpf_offload_cmd (tp , obj , cmd ))
183
+ return ;
184
+
185
+ obj -> offloaded = true;
186
+ if (oldprog )
187
+ oldprog -> offloaded = false;
188
+ }
189
+
190
+ static void cls_bpf_stop_offload (struct tcf_proto * tp ,
191
+ struct cls_bpf_prog * prog )
192
+ {
193
+ int err ;
194
+
195
+ if (!prog -> offloaded )
196
+ return ;
197
+
198
+ err = cls_bpf_offload_cmd (tp , prog , TC_CLSBPF_DESTROY );
199
+ if (err ) {
200
+ pr_err ("Stopping hardware offload failed: %d\n" , err );
201
+ return ;
202
+ }
203
+
204
+ prog -> offloaded = false;
205
+ }
206
+
141
207
static int cls_bpf_init (struct tcf_proto * tp )
142
208
{
143
209
struct cls_bpf_head * head ;
@@ -177,6 +243,7 @@ static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg)
177
243
{
178
244
struct cls_bpf_prog * prog = (struct cls_bpf_prog * ) arg ;
179
245
246
+ cls_bpf_stop_offload (tp , prog );
180
247
list_del_rcu (& prog -> link );
181
248
tcf_unbind_filter (tp , & prog -> res );
182
249
call_rcu (& prog -> rcu , __cls_bpf_delete_prog );
@@ -193,6 +260,7 @@ static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
193
260
return false;
194
261
195
262
list_for_each_entry_safe (prog , tmp , & head -> plist , link ) {
263
+ cls_bpf_stop_offload (tp , prog );
196
264
list_del_rcu (& prog -> link );
197
265
tcf_unbind_filter (tp , & prog -> res );
198
266
call_rcu (& prog -> rcu , __cls_bpf_delete_prog );
@@ -415,6 +483,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
415
483
if (ret < 0 )
416
484
goto errout ;
417
485
486
+ cls_bpf_offload (tp , prog , oldprog );
487
+
418
488
if (oldprog ) {
419
489
list_replace_rcu (& oldprog -> link , & prog -> link );
420
490
tcf_unbind_filter (tp , & oldprog -> res );
0 commit comments