| 1 | |
| 2 | |
| 3 | * net/sched/act_api.c Packet action API.
|
| 4 | *
|
| 5 | * Author: Jamal Hadi Salim
|
| 6 |
|
| 7 |
|
| 8 | #include <linux/types.h>
|
| 9 | #include <linux/kernel.h>
|
| 10 | #include <linux/string.h>
|
| 11 | #include <linux/errno.h>
|
| 12 | #include <linux/slab.h>
|
| 13 | #include <linux/skbuff.h>
|
| 14 | #include <linux/init.h>
|
| 15 | #include <linux/kmod.h>
|
| 16 | #include <linux/err.h>
|
| 17 | #include <linux/module.h>
|
| 18 | #include <net/net_namespace.h>
|
| 19 | #include <net/sock.h>
|
| 20 | #include <net/sch_generic.h>
|
| 21 | #include <net/pkt_cls.h>
|
| 22 | #include <net/tc_act/tc_pedit.h>
|
| 23 | #include <net/act_api.h>
|
| 24 | #include <net/netlink.h>
|
| 25 | #include <net/flow_offload.h>
|
| 26 | #include <net/tc_wrapper.h>
|
| 27 |
|
| 28 | #ifdef CONFIG_INET
|
| 29 | DEFINE_STATIC_KEY_FALSE(tcf_frag_xmit_count);
|
| 30 | EXPORT_SYMBOL_GPL(tcf_frag_xmit_count);
|
| 31 | #endif
|
| 32 |
|
| 33 | int tcf_dev_queue_xmit(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb))
|
| 34 | {
|
| 35 | #ifdef CONFIG_INET
|
| 36 | if (static_branch_unlikely(&tcf_frag_xmit_count))
|
| 37 | return sch_frag_xmit_hook(skb, xmit);
|
| 38 | #endif
|
| 39 |
|
| 40 | return xmit(skb);
|
| 41 | }
|
| 42 | EXPORT_SYMBOL_GPL(tcf_dev_queue_xmit);
|
| 43 |
|
| 44 | static void tcf_action_goto_chain_exec(const struct tcf_chain *chain,
|
| 45 | struct tcf_result *res)
|
| 46 | {
|
| 47 | res->goto_tp = rcu_dereference_bh(chain->filter_chain);
|
| 48 | }
|
| 49 |
|
| 50 | static void tcf_free_cookie_rcu(struct rcu_head *p)
|
| 51 | {
|
| 52 | struct tc_cookie *cookie = container_of(p, struct tc_cookie, rcu);
|
| 53 |
|
| 54 | kfree(cookie->data);
|
| 55 | kfree(cookie);
|
| 56 | }
|
| 57 |
|
| 58 | static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie,
|
| 59 | struct tc_cookie *new_cookie)
|
| 60 | {
|
| 61 | struct tc_cookie *old;
|
| 62 |
|
| 63 | old = unrcu_pointer(xchg(old_cookie, RCU_INITIALIZER(new_cookie)));
|
| 64 | if (old)
|
| 65 | call_rcu(&old->rcu, tcf_free_cookie_rcu);
|
| 66 | }
|
| 67 |
|
| 68 | int tcf_action_check_ctrlact(int action, struct tcf_proto *tp,
|
| 69 | struct tcf_chain **newchain,
|
| 70 | struct netlink_ext_ack *extack)
|
| 71 | {
|
| 72 | int opcode = TC_ACT_EXT_OPCODE(action), ret = -EINVAL;
|
| 73 | u32 chain_index;
|
| 74 |
|
| 75 | if (!opcode)
|
| 76 | ret = action > TC_ACT_VALUE_MAX ? -EINVAL : 0;
|
| 77 | else if (opcode <= TC_ACT_EXT_OPCODE_MAX || action == TC_ACT_UNSPEC)
|
| 78 | ret = 0;
|
| 79 | if (ret) {
|
| 80 | NL_SET_ERR_MSG(extack, "invalid control action");
|
| 81 | goto end;
|
| 82 | }
|
| 83 |
|
| 84 | if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN)) {
|
| 85 | chain_index = action & TC_ACT_EXT_VAL_MASK;
|
| 86 | if (!tp || !newchain) {
|
| 87 | ret = -EINVAL;
|
| 88 | NL_SET_ERR_MSG(extack,
|
| 89 | "can't goto NULL proto/chain");
|
| 90 | goto end;
|
| 91 | }
|
| 92 | *newchain = tcf_chain_get_by_act(tp->chain->block, chain_index);
|
| 93 | if (!*newchain) {
|
| 94 | ret = -ENOMEM;
|
| 95 | NL_SET_ERR_MSG(extack,
|
| 96 | "can't allocate goto_chain");
|
| 97 | }
|
| 98 | }
|
| 99 | end:
|
| 100 | return ret;
|
| 101 | }
|
| 102 | EXPORT_SYMBOL(tcf_action_check_ctrlact);
|
| 103 |
|
| 104 | struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action,
|
| 105 | struct tcf_chain *goto_chain)
|
| 106 | {
|
| 107 | a->tcfa_action = action;
|
| 108 | goto_chain = rcu_replace_pointer(a->goto_chain, goto_chain, 1);
|
| 109 | return goto_chain;
|
| 110 | }
|
| 111 | EXPORT_SYMBOL(tcf_action_set_ctrlact);
|
| 112 |
|
| 113 | static void free_tcf(struct tc_action *p)
|
| 114 | {
|
| 115 | struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1);
|
| 116 |
|
| 117 | free_percpu(p->cpu_bstats);
|
| 118 | free_percpu(p->cpu_bstats_hw);
|
| 119 | free_percpu(p->cpu_qstats);
|
| 120 |
|
| 121 | tcf_set_action_cookie(&p->user_cookie, NULL);
|
| 122 | if (chain)
|
| 123 | tcf_chain_put_by_act(chain);
|
| 124 |
|
| 125 | kfree_rcu(p, tcfa_rcu);
|
| 126 | }
|
| 127 |
|
| 128 | static void offload_action_hw_count_set(struct tc_action *act,
|
| 129 | u32 hw_count)
|
| 130 | {
|
| 131 | act->in_hw_count = hw_count;
|
| 132 | }
|
| 133 |
|
| 134 | static void offload_action_hw_count_inc(struct tc_action *act,
|
| 135 | u32 hw_count)
|
| 136 | {
|
| 137 | act->in_hw_count += hw_count;
|
| 138 | }
|
| 139 |
|
| 140 | static void offload_action_hw_count_dec(struct tc_action *act,
|
| 141 | u32 hw_count)
|
| 142 | {
|
| 143 | act->in_hw_count = act->in_hw_count > hw_count ?
|
| 144 | act->in_hw_count - hw_count : 0;
|
| 145 | }
|
| 146 |
|
| 147 | static unsigned int tcf_offload_act_num_actions_single(struct tc_action *act)
|
| 148 | {
|
| 149 | unsigned int count;
|
| 150 |
|
| 151 | if (is_tcf_pedit(act)) {
|
| 152 | spin_lock_bh(&act->tcfa_lock);
|
| 153 | count = tcf_pedit_nkeys_locked(act);
|
| 154 | spin_unlock_bh(&act->tcfa_lock);
|
| 155 | return count;
|
| 156 | }
|
| 157 | return 1;
|
| 158 | }
|
| 159 |
|
| 160 | static bool tc_act_skip_hw(u32 flags)
|
| 161 | {
|
| 162 | return (flags & TCA_ACT_FLAGS_SKIP_HW) ? true : false;
|
| 163 | }
|
| 164 |
|
| 165 | static bool tc_act_skip_sw(u32 flags)
|
| 166 | {
|
| 167 | return (flags & TCA_ACT_FLAGS_SKIP_SW) ? true : false;
|
| 168 | }
|
| 169 |
|
| 170 |
|
| 171 | static bool tc_act_flags_valid(u32 flags)
|
| 172 | {
|
| 173 | flags &= TCA_ACT_FLAGS_SKIP_HW | TCA_ACT_FLAGS_SKIP_SW;
|
| 174 |
|
| 175 | return flags ^ (TCA_ACT_FLAGS_SKIP_HW | TCA_ACT_FLAGS_SKIP_SW);
|
| 176 | }
|
| 177 |
|
| 178 | static int offload_action_init(struct flow_offload_action *fl_action,
|
| 179 | struct tc_action *act,
|
| 180 | enum offload_act_command cmd,
|
| 181 | struct netlink_ext_ack *extack)
|
| 182 | {
|
| 183 | int err;
|
| 184 |
|
| 185 | fl_action->extack = extack;
|
| 186 | fl_action->command = cmd;
|
| 187 | fl_action->index = act->tcfa_index;
|
| 188 | fl_action->cookie = (unsigned long)act;
|
| 189 |
|
| 190 | if (act->ops->offload_act_setup) {
|
| 191 | spin_lock_bh(&act->tcfa_lock);
|
| 192 | err = act->ops->offload_act_setup(act, fl_action, NULL,
|
| 193 | false, extack);
|
| 194 | spin_unlock_bh(&act->tcfa_lock);
|
| 195 | return err;
|
| 196 | }
|
| 197 |
|
| 198 | return -EOPNOTSUPP;
|
| 199 | }
|
| 200 |
|
| 201 | static int tcf_action_offload_cmd_ex(struct flow_offload_action *fl_act,
|
| 202 | u32 *hw_count)
|
| 203 | {
|
| 204 | int err;
|
| 205 |
|
| 206 | err = flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT,
|
| 207 | fl_act, NULL, NULL);
|
| 208 | if (err < 0)
|
| 209 | return err;
|
| 210 |
|
| 211 | if (hw_count)
|
| 212 | *hw_count = err;
|
| 213 |
|
| 214 | return 0;
|
| 215 | }
|
| 216 |
|
| 217 | static int tcf_action_offload_cmd_cb_ex(struct flow_offload_action *fl_act,
|
| 218 | u32 *hw_count,
|
| 219 | flow_indr_block_bind_cb_t *cb,
|
| 220 | void *cb_priv)
|
| 221 | {
|
| 222 | int err;
|
| 223 |
|
| 224 | err = cb(NULL, NULL, cb_priv, TC_SETUP_ACT, NULL, fl_act, NULL);
|
| 225 | if (err < 0)
|
| 226 | return err;
|
| 227 |
|
| 228 | if (hw_count)
|
| 229 | *hw_count = 1;
|
| 230 |
|
| 231 | return 0;
|
| 232 | }
|
| 233 |
|
| 234 | static int tcf_action_offload_cmd(struct flow_offload_action *fl_act,
|
| 235 | u32 *hw_count,
|
| 236 | flow_indr_block_bind_cb_t *cb,
|
| 237 | void *cb_priv)
|
| 238 | {
|
| 239 | return cb ? tcf_action_offload_cmd_cb_ex(fl_act, hw_count,
|
| 240 | cb, cb_priv) :
|
| 241 | tcf_action_offload_cmd_ex(fl_act, hw_count);
|
| 242 | }
|
| 243 |
|
| 244 | static int tcf_action_offload_add_ex(struct tc_action *action,
|
| 245 | struct netlink_ext_ack *extack,
|
| 246 | flow_indr_block_bind_cb_t *cb,
|
| 247 | void *cb_priv)
|
| 248 | {
|
| 249 | bool skip_sw = tc_act_skip_sw(action->tcfa_flags);
|
| 250 | struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
|
| 251 | [0] = action,
|
| 252 | };
|
| 253 | struct flow_offload_action *fl_action;
|
| 254 | u32 in_hw_count = 0;
|
| 255 | int num, err = 0;
|
| 256 |
|
| 257 | if (tc_act_skip_hw(action->tcfa_flags))
|
| 258 | return 0;
|
| 259 |
|
| 260 | num = tcf_offload_act_num_actions_single(action);
|
| 261 | fl_action = offload_action_alloc(num);
|
| 262 | if (!fl_action)
|
| 263 | return -ENOMEM;
|
| 264 |
|
| 265 | err = offload_action_init(fl_action, action, FLOW_ACT_REPLACE, extack);
|
| 266 | if (err)
|
| 267 | goto fl_err;
|
| 268 |
|
| 269 | err = tc_setup_action(&fl_action->action, actions, 0, extack);
|
| 270 | if (err) {
|
| 271 | NL_SET_ERR_MSG_MOD(extack,
|
| 272 | "Failed to setup tc actions for offload");
|
| 273 | goto fl_err;
|
| 274 | }
|
| 275 |
|
| 276 | err = tcf_action_offload_cmd(fl_action, &in_hw_count, cb, cb_priv);
|
| 277 | if (!err)
|
| 278 | cb ? offload_action_hw_count_inc(action, in_hw_count) :
|
| 279 | offload_action_hw_count_set(action, in_hw_count);
|
| 280 |
|
| 281 | if (skip_sw && !tc_act_in_hw(action))
|
| 282 | err = -EINVAL;
|
| 283 |
|
| 284 | tc_cleanup_offload_action(&fl_action->action);
|
| 285 |
|
| 286 | fl_err:
|
| 287 | kfree(fl_action);
|
| 288 |
|
| 289 | return err;
|
| 290 | }
|
| 291 |
|
| 292 |
|
| 293 | static int tcf_action_offload_add(struct tc_action *action,
|
| 294 | struct netlink_ext_ack *extack)
|
| 295 | {
|
| 296 | return tcf_action_offload_add_ex(action, extack, NULL, NULL);
|
| 297 | }
|
| 298 |
|
| 299 | int tcf_action_update_hw_stats(struct tc_action *action)
|
| 300 | {
|
| 301 | struct flow_offload_action fl_act = {};
|
| 302 | int err;
|
| 303 |
|
| 304 | err = offload_action_init(&fl_act, action, FLOW_ACT_STATS, NULL);
|
| 305 | if (err)
|
| 306 | return err;
|
| 307 |
|
| 308 | err = tcf_action_offload_cmd(&fl_act, NULL, NULL, NULL);
|
| 309 | if (!err) {
|
| 310 | preempt_disable();
|
| 311 | tcf_action_stats_update(action, fl_act.stats.bytes,
|
| 312 | fl_act.stats.pkts,
|
| 313 | fl_act.stats.drops,
|
| 314 | fl_act.stats.lastused,
|
| 315 | true);
|
| 316 | preempt_enable();
|
| 317 | action->used_hw_stats = fl_act.stats.used_hw_stats;
|
| 318 | action->used_hw_stats_valid = true;
|
| 319 | } else {
|
| 320 | return -EOPNOTSUPP;
|
| 321 | }
|
| 322 |
|
| 323 | return 0;
|
| 324 | }
|
| 325 | EXPORT_SYMBOL(tcf_action_update_hw_stats);
|
| 326 |
|
| 327 | static int tcf_action_offload_del_ex(struct tc_action *action,
|
| 328 | flow_indr_block_bind_cb_t *cb,
|
| 329 | void *cb_priv)
|
| 330 | {
|
| 331 | struct flow_offload_action fl_act = {};
|
| 332 | u32 in_hw_count = 0;
|
| 333 | int err = 0;
|
| 334 |
|
| 335 | if (!tc_act_in_hw(action))
|
| 336 | return 0;
|
| 337 |
|
| 338 | err = offload_action_init(&fl_act, action, FLOW_ACT_DESTROY, NULL);
|
| 339 | if (err)
|
| 340 | return err;
|
| 341 |
|
| 342 | err = tcf_action_offload_cmd(&fl_act, &in_hw_count, cb, cb_priv);
|
| 343 | if (err < 0)
|
| 344 | return err;
|
| 345 |
|
| 346 | if (!cb && action->in_hw_count != in_hw_count)
|
| 347 | return -EINVAL;
|
| 348 |
|
| 349 |
|
| 350 | if (cb && in_hw_count)
|
| 351 | offload_action_hw_count_dec(action, in_hw_count);
|
| 352 |
|
| 353 | return 0;
|
| 354 | }
|
| 355 |
|
| 356 | static int tcf_action_offload_del(struct tc_action *action)
|
| 357 | {
|
| 358 | return tcf_action_offload_del_ex(action, NULL, NULL);
|
| 359 | }
|
| 360 |
|
| 361 | static void tcf_action_cleanup(struct tc_action *p)
|
| 362 | {
|
| 363 | tcf_action_offload_del(p);
|
| 364 | if (p->ops->cleanup)
|
| 365 | p->ops->cleanup(p);
|
| 366 |
|
| 367 | gen_kill_estimator(&p->tcfa_rate_est);
|
| 368 | free_tcf(p);
|
| 369 | }
|
| 370 |
|
| 371 | static int __tcf_action_put(struct tc_action *p, bool bind)
|
| 372 | {
|
| 373 | struct tcf_idrinfo *idrinfo = p->idrinfo;
|
| 374 |
|
| 375 | mutex_lock(&idrinfo->lock);
|
| 376 | if (bind)
|
| 377 | atomic_dec(&p->tcfa_bindcnt);
|
| 378 | if (refcount_dec_and_test(&p->tcfa_refcnt)) {
|
| 379 | idr_remove(&idrinfo->action_idr, p->tcfa_index);
|
| 380 | mutex_unlock(&idrinfo->lock);
|
| 381 |
|
| 382 | tcf_action_cleanup(p);
|
| 383 | return 1;
|
| 384 | }
|
| 385 |
|
| 386 | mutex_unlock(&idrinfo->lock);
|
| 387 | return 0;
|
| 388 | }
|
| 389 |
|
| 390 | static int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)
|
| 391 | {
|
| 392 | int ret = 0;
|
| 393 |
|
| 394 | |
| 395 | * interface (classifiers always bind). Only case when action with
|
| 396 | * positive reference count and zero bind count can exist is when it was
|
| 397 | * also created with act API (unbinding last classifier will destroy the
|
| 398 | * action if it was created by classifier). So only case when bind count
|
| 399 | * can be changed after initial check is when unbound action is
|
| 400 | * destroyed by act API while classifier binds to action with same id
|
| 401 | * concurrently. This result either creation of new action(same behavior
|
| 402 | * as before), or reusing existing action if concurrent process
|
| 403 | * increments reference count before action is deleted. Both scenarios
|
| 404 | * are acceptable.
|
| 405 |
|
| 406 | if (p) {
|
| 407 | if (!bind && strict && atomic_read(&p->tcfa_bindcnt) > 0)
|
| 408 | return -EPERM;
|
| 409 |
|
| 410 | if (__tcf_action_put(p, bind))
|
| 411 | ret = ACT_P_DELETED;
|
| 412 | }
|
| 413 |
|
| 414 | return ret;
|
| 415 | }
|
| 416 |
|
| 417 | int tcf_idr_release(struct tc_action *a, bool bind)
|
| 418 | {
|
| 419 | const struct tc_action_ops *ops = a->ops;
|
| 420 | int ret;
|
| 421 |
|
| 422 | ret = __tcf_idr_release(a, bind, false);
|
| 423 | if (ret == ACT_P_DELETED)
|
| 424 | module_put(ops->owner);
|
| 425 | return ret;
|
| 426 | }
|
| 427 | EXPORT_SYMBOL(tcf_idr_release);
|
| 428 |
|
| 429 | static size_t tcf_action_shared_attrs_size(const struct tc_action *act)
|
| 430 | {
|
| 431 | struct tc_cookie *user_cookie;
|
| 432 | u32 cookie_len = 0;
|
| 433 |
|
| 434 | rcu_read_lock();
|
| 435 | user_cookie = rcu_dereference(act->user_cookie);
|
| 436 |
|
| 437 | if (user_cookie)
|
| 438 | cookie_len = nla_total_size(user_cookie->len);
|
| 439 | rcu_read_unlock();
|
| 440 |
|
| 441 | return nla_total_size(0)
|
| 442 | + nla_total_size(IFNAMSIZ)
|
| 443 | + cookie_len
|
| 444 | + nla_total_size(sizeof(struct nla_bitfield32))
|
| 445 |
|
| 446 | + nla_total_size(sizeof(struct nla_bitfield32))
|
| 447 | + nla_total_size(sizeof(u32))
|
| 448 | + nla_total_size(0)
|
| 449 | + nla_total_size(sizeof(struct nla_bitfield32))
|
| 450 |
|
| 451 | + nla_total_size_64bit(sizeof(struct gnet_stats_basic))
|
| 452 |
|
| 453 | + nla_total_size_64bit(sizeof(struct gnet_stats_basic))
|
| 454 |
|
| 455 | + 2 * nla_total_size_64bit(sizeof(u64))
|
| 456 |
|
| 457 | + nla_total_size_64bit(sizeof(struct gnet_stats_rate_est))
|
| 458 |
|
| 459 | + nla_total_size_64bit(sizeof(struct gnet_stats_rate_est64))
|
| 460 |
|
| 461 | + nla_total_size_64bit(sizeof(struct gnet_stats_queue))
|
| 462 | + nla_total_size(0)
|
| 463 | |
| 464 | * which may emit an extra NLA_PAD attribute.
|
| 465 |
|
| 466 | + nla_total_size_64bit(sizeof(struct tcf_t));
|
| 467 | }
|
| 468 |
|
| 469 | static size_t tcf_action_full_attrs_size(size_t sz)
|
| 470 | {
|
| 471 | return NLMSG_HDRLEN
|
| 472 | + sizeof(struct tcamsg)
|
| 473 | + nla_total_size(0)
|
| 474 | + sz;
|
| 475 | }
|
| 476 |
|
| 477 | static size_t tcf_action_fill_size(const struct tc_action *act)
|
| 478 | {
|
| 479 | size_t sz = tcf_action_shared_attrs_size(act);
|
| 480 |
|
| 481 | if (act->ops->get_fill_size)
|
| 482 | return act->ops->get_fill_size(act) + sz;
|
| 483 | return sz;
|
| 484 | }
|
| 485 |
|
| 486 | static int
|
| 487 | tcf_action_dump_terse(struct sk_buff *skb, struct tc_action *a, bool from_act)
|
| 488 | {
|
| 489 | unsigned char *b = skb_tail_pointer(skb);
|
| 490 | struct tc_cookie *cookie;
|
| 491 |
|
| 492 | if (nla_put_string(skb, TCA_ACT_KIND, a->ops->kind))
|
| 493 | goto nla_put_failure;
|
| 494 | if (tcf_action_copy_stats(skb, a, 0))
|
| 495 | goto nla_put_failure;
|
| 496 | if (from_act && nla_put_u32(skb, TCA_ACT_INDEX, a->tcfa_index))
|
| 497 | goto nla_put_failure;
|
| 498 |
|
| 499 | rcu_read_lock();
|
| 500 | cookie = rcu_dereference(a->user_cookie);
|
| 501 | if (cookie) {
|
| 502 | if (nla_put(skb, TCA_ACT_COOKIE, cookie->len, cookie->data)) {
|
| 503 | rcu_read_unlock();
|
| 504 | goto nla_put_failure;
|
| 505 | }
|
| 506 | }
|
| 507 | rcu_read_unlock();
|
| 508 |
|
| 509 | return 0;
|
| 510 |
|
| 511 | nla_put_failure:
|
| 512 | nlmsg_trim(skb, b);
|
| 513 | return -1;
|
| 514 | }
|
| 515 |
|
| 516 | static int
|
| 517 | tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
|
| 518 | {
|
| 519 | unsigned char *b = skb_tail_pointer(skb);
|
| 520 | struct nlattr *nest;
|
| 521 | int err = -EINVAL;
|
| 522 | u32 flags;
|
| 523 |
|
| 524 | if (tcf_action_dump_terse(skb, a, false))
|
| 525 | goto nla_put_failure;
|
| 526 |
|
| 527 | if (a->hw_stats != TCA_ACT_HW_STATS_ANY &&
|
| 528 | nla_put_bitfield32(skb, TCA_ACT_HW_STATS,
|
| 529 | a->hw_stats, TCA_ACT_HW_STATS_ANY))
|
| 530 | goto nla_put_failure;
|
| 531 |
|
| 532 | if (a->used_hw_stats_valid &&
|
| 533 | nla_put_bitfield32(skb, TCA_ACT_USED_HW_STATS,
|
| 534 | a->used_hw_stats, TCA_ACT_HW_STATS_ANY))
|
| 535 | goto nla_put_failure;
|
| 536 |
|
| 537 | flags = a->tcfa_flags & TCA_ACT_FLAGS_USER_MASK;
|
| 538 | if (flags &&
|
| 539 | nla_put_bitfield32(skb, TCA_ACT_FLAGS,
|
| 540 | flags, flags))
|
| 541 | goto nla_put_failure;
|
| 542 |
|
| 543 | if (nla_put_u32(skb, TCA_ACT_IN_HW_COUNT, a->in_hw_count))
|
| 544 | goto nla_put_failure;
|
| 545 |
|
| 546 | nest = nla_nest_start_noflag(skb, TCA_ACT_OPTIONS);
|
| 547 | if (nest == NULL)
|
| 548 | goto nla_put_failure;
|
| 549 | err = tcf_action_dump_old(skb, a, bind, ref);
|
| 550 | if (err > 0) {
|
| 551 | nla_nest_end(skb, nest);
|
| 552 | return err;
|
| 553 | }
|
| 554 |
|
| 555 | nla_put_failure:
|
| 556 | nlmsg_trim(skb, b);
|
| 557 | return -1;
|
| 558 | }
|
| 559 |
|
| 560 | static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
|
| 561 | struct netlink_callback *cb)
|
| 562 | {
|
| 563 | int err = 0, index = -1, s_i = 0, n_i = 0;
|
| 564 | u32 act_flags = cb->args[2];
|
| 565 | unsigned long jiffy_since = cb->args[3];
|
| 566 | struct nlattr *nest;
|
| 567 | struct idr *idr = &idrinfo->action_idr;
|
| 568 | struct tc_action *p;
|
| 569 | unsigned long id = 1;
|
| 570 | unsigned long tmp;
|
| 571 |
|
| 572 | mutex_lock(&idrinfo->lock);
|
| 573 |
|
| 574 | s_i = cb->args[0];
|
| 575 |
|
| 576 | idr_for_each_entry_ul(idr, p, tmp, id) {
|
| 577 | index++;
|
| 578 | if (index < s_i)
|
| 579 | continue;
|
| 580 | if (IS_ERR(p))
|
| 581 | continue;
|
| 582 |
|
| 583 | if (jiffy_since &&
|
| 584 | time_after(jiffy_since,
|
| 585 | (unsigned long)p->tcfa_tm.lastuse))
|
| 586 | continue;
|
| 587 |
|
| 588 | tcf_action_update_hw_stats(p);
|
| 589 |
|
| 590 | nest = nla_nest_start_noflag(skb, n_i);
|
| 591 | if (!nest) {
|
| 592 | index--;
|
| 593 | goto nla_put_failure;
|
| 594 | }
|
| 595 | err = (act_flags & TCA_ACT_FLAG_TERSE_DUMP) ?
|
| 596 | tcf_action_dump_terse(skb, p, true) :
|
| 597 | tcf_action_dump_1(skb, p, 0, 0);
|
| 598 | if (err < 0) {
|
| 599 | index--;
|
| 600 | nlmsg_trim(skb, nest);
|
| 601 | goto done;
|
| 602 | }
|
| 603 | nla_nest_end(skb, nest);
|
| 604 | n_i++;
|
| 605 | if (!(act_flags & TCA_ACT_FLAG_LARGE_DUMP_ON) &&
|
| 606 | n_i >= TCA_ACT_MAX_PRIO)
|
| 607 | goto done;
|
| 608 | }
|
| 609 | done:
|
| 610 | if (index >= 0)
|
| 611 | cb->args[0] = index + 1;
|
| 612 |
|
| 613 | mutex_unlock(&idrinfo->lock);
|
| 614 | if (n_i) {
|
| 615 | if (act_flags & TCA_ACT_FLAG_LARGE_DUMP_ON)
|
| 616 | cb->args[1] = n_i;
|
| 617 | }
|
| 618 | return n_i;
|
| 619 |
|
| 620 | nla_put_failure:
|
| 621 | nla_nest_cancel(skb, nest);
|
| 622 | goto done;
|
| 623 | }
|
| 624 |
|
| 625 | static int tcf_idr_release_unsafe(struct tc_action *p)
|
| 626 | {
|
| 627 | if (atomic_read(&p->tcfa_bindcnt) > 0)
|
| 628 | return -EPERM;
|
| 629 |
|
| 630 | if (refcount_dec_and_test(&p->tcfa_refcnt)) {
|
| 631 | idr_remove(&p->idrinfo->action_idr, p->tcfa_index);
|
| 632 | tcf_action_cleanup(p);
|
| 633 | return ACT_P_DELETED;
|
| 634 | }
|
| 635 |
|
| 636 | return 0;
|
| 637 | }
|
| 638 |
|
| 639 | static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
|
| 640 | const struct tc_action_ops *ops,
|
| 641 | struct netlink_ext_ack *extack)
|
| 642 | {
|
| 643 | struct nlattr *nest;
|
| 644 | int n_i = 0;
|
| 645 | int ret = -EINVAL;
|
| 646 | struct idr *idr = &idrinfo->action_idr;
|
| 647 | struct tc_action *p;
|
| 648 | unsigned long id = 1;
|
| 649 | unsigned long tmp;
|
| 650 |
|
| 651 | nest = nla_nest_start_noflag(skb, 0);
|
| 652 | if (nest == NULL)
|
| 653 | goto nla_put_failure;
|
| 654 | if (nla_put_string(skb, TCA_ACT_KIND, ops->kind))
|
| 655 | goto nla_put_failure;
|
| 656 |
|
| 657 | ret = 0;
|
| 658 | mutex_lock(&idrinfo->lock);
|
| 659 | idr_for_each_entry_ul(idr, p, tmp, id) {
|
| 660 | if (IS_ERR(p))
|
| 661 | continue;
|
| 662 | ret = tcf_idr_release_unsafe(p);
|
| 663 | if (ret == ACT_P_DELETED)
|
| 664 | module_put(ops->owner);
|
| 665 | else if (ret < 0)
|
| 666 | break;
|
| 667 | n_i++;
|
| 668 | }
|
| 669 | mutex_unlock(&idrinfo->lock);
|
| 670 | if (ret < 0) {
|
| 671 | if (n_i)
|
| 672 | NL_SET_ERR_MSG(extack, "Unable to flush all TC actions");
|
| 673 | else
|
| 674 | goto nla_put_failure;
|
| 675 | }
|
| 676 |
|
| 677 | ret = nla_put_u32(skb, TCA_FCNT, n_i);
|
| 678 | if (ret)
|
| 679 | goto nla_put_failure;
|
| 680 | nla_nest_end(skb, nest);
|
| 681 |
|
| 682 | return n_i;
|
| 683 | nla_put_failure:
|
| 684 | nla_nest_cancel(skb, nest);
|
| 685 | return ret;
|
| 686 | }
|
| 687 |
|
| 688 | int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
|
| 689 | struct netlink_callback *cb, int type,
|
| 690 | const struct tc_action_ops *ops,
|
| 691 | struct netlink_ext_ack *extack)
|
| 692 | {
|
| 693 | struct tcf_idrinfo *idrinfo = tn->idrinfo;
|
| 694 |
|
| 695 | if (type == RTM_DELACTION) {
|
| 696 | return tcf_del_walker(idrinfo, skb, ops, extack);
|
| 697 | } else if (type == RTM_GETACTION) {
|
| 698 | return tcf_dump_walker(idrinfo, skb, cb);
|
| 699 | } else {
|
| 700 | WARN(1, "tcf_generic_walker: unknown command %d\n", type);
|
| 701 | NL_SET_ERR_MSG(extack, "tcf_generic_walker: unknown command");
|
| 702 | return -EINVAL;
|
| 703 | }
|
| 704 | }
|
| 705 | EXPORT_SYMBOL(tcf_generic_walker);
|
| 706 |
|
| 707 | int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
|
| 708 | {
|
| 709 | struct tcf_idrinfo *idrinfo = tn->idrinfo;
|
| 710 | struct tc_action *p;
|
| 711 |
|
| 712 | mutex_lock(&idrinfo->lock);
|
| 713 | p = idr_find(&idrinfo->action_idr, index);
|
| 714 | if (IS_ERR(p))
|
| 715 | p = NULL;
|
| 716 | else if (p)
|
| 717 | refcount_inc(&p->tcfa_refcnt);
|
| 718 | mutex_unlock(&idrinfo->lock);
|
| 719 |
|
| 720 | if (p) {
|
| 721 | *a = p;
|
| 722 | return true;
|
| 723 | }
|
| 724 | return false;
|
| 725 | }
|
| 726 | EXPORT_SYMBOL(tcf_idr_search);
|
| 727 |
|
| 728 | static int __tcf_generic_walker(struct net *net, struct sk_buff *skb,
|
| 729 | struct netlink_callback *cb, int type,
|
| 730 | const struct tc_action_ops *ops,
|
| 731 | struct netlink_ext_ack *extack)
|
| 732 | {
|
| 733 | struct tc_action_net *tn = net_generic(net, ops->net_id);
|
| 734 |
|
| 735 | if (unlikely(ops->walk))
|
| 736 | return ops->walk(net, skb, cb, type, ops, extack);
|
| 737 |
|
| 738 | return tcf_generic_walker(tn, skb, cb, type, ops, extack);
|
| 739 | }
|
| 740 |
|
| 741 | static int __tcf_idr_search(struct net *net,
|
| 742 | const struct tc_action_ops *ops,
|
| 743 | struct tc_action **a, u32 index)
|
| 744 | {
|
| 745 | struct tc_action_net *tn = net_generic(net, ops->net_id);
|
| 746 |
|
| 747 | if (unlikely(ops->lookup))
|
| 748 | return ops->lookup(net, a, index);
|
| 749 |
|
| 750 | return tcf_idr_search(tn, a, index);
|
| 751 | }
|
| 752 |
|
| 753 | static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index)
|
| 754 | {
|
| 755 | struct tc_action *p;
|
| 756 | int ret = 0;
|
| 757 |
|
| 758 | mutex_lock(&idrinfo->lock);
|
| 759 | p = idr_find(&idrinfo->action_idr, index);
|
| 760 | if (IS_ERR_OR_NULL(p)) {
|
| 761 | mutex_unlock(&idrinfo->lock);
|
| 762 | return -ENOENT;
|
| 763 | }
|
| 764 |
|
| 765 | if (!atomic_read(&p->tcfa_bindcnt)) {
|
| 766 | if (refcount_dec_and_test(&p->tcfa_refcnt)) {
|
| 767 | struct module *owner = p->ops->owner;
|
| 768 |
|
| 769 | WARN_ON(p != idr_remove(&idrinfo->action_idr,
|
| 770 | p->tcfa_index));
|
| 771 | mutex_unlock(&idrinfo->lock);
|
| 772 |
|
| 773 | tcf_action_cleanup(p);
|
| 774 | module_put(owner);
|
| 775 | return 0;
|
| 776 | }
|
| 777 | ret = 0;
|
| 778 | } else {
|
| 779 | ret = -EPERM;
|
| 780 | }
|
| 781 |
|
| 782 | mutex_unlock(&idrinfo->lock);
|
| 783 | return ret;
|
| 784 | }
|
| 785 |
|
| 786 | int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
|
| 787 | struct tc_action **a, const struct tc_action_ops *ops,
|
| 788 | int bind, bool cpustats, u32 flags)
|
| 789 | {
|
| 790 | struct tc_action *p = kzalloc(ops->size, GFP_KERNEL);
|
| 791 | struct tcf_idrinfo *idrinfo = tn->idrinfo;
|
| 792 | int err = -ENOMEM;
|
| 793 |
|
| 794 | if (unlikely(!p))
|
| 795 | return -ENOMEM;
|
| 796 | refcount_set(&p->tcfa_refcnt, 1);
|
| 797 | if (bind)
|
| 798 | atomic_set(&p->tcfa_bindcnt, 1);
|
| 799 |
|
| 800 | if (cpustats) {
|
| 801 | p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_sync);
|
| 802 | if (!p->cpu_bstats)
|
| 803 | goto err1;
|
| 804 | p->cpu_bstats_hw = netdev_alloc_pcpu_stats(struct gnet_stats_basic_sync);
|
| 805 | if (!p->cpu_bstats_hw)
|
| 806 | goto err2;
|
| 807 | p->cpu_qstats = alloc_percpu(struct gnet_stats_queue);
|
| 808 | if (!p->cpu_qstats)
|
| 809 | goto err3;
|
| 810 | }
|
| 811 | gnet_stats_basic_sync_init(&p->tcfa_bstats);
|
| 812 | gnet_stats_basic_sync_init(&p->tcfa_bstats_hw);
|
| 813 | spin_lock_init(&p->tcfa_lock);
|
| 814 | p->tcfa_index = index;
|
| 815 | p->tcfa_tm.install = jiffies;
|
| 816 | p->tcfa_tm.lastuse = jiffies;
|
| 817 | p->tcfa_tm.firstuse = 0;
|
| 818 | p->tcfa_flags = flags;
|
| 819 | if (est) {
|
| 820 | err = gen_new_estimator(&p->tcfa_bstats, p->cpu_bstats,
|
| 821 | &p->tcfa_rate_est,
|
| 822 | &p->tcfa_lock, false, est);
|
| 823 | if (err)
|
| 824 | goto err4;
|
| 825 | }
|
| 826 |
|
| 827 | p->idrinfo = idrinfo;
|
| 828 | __module_get(ops->owner);
|
| 829 | p->ops = ops;
|
| 830 | *a = p;
|
| 831 | return 0;
|
| 832 | err4:
|
| 833 | free_percpu(p->cpu_qstats);
|
| 834 | err3:
|
| 835 | free_percpu(p->cpu_bstats_hw);
|
| 836 | err2:
|
| 837 | free_percpu(p->cpu_bstats);
|
| 838 | err1:
|
| 839 | kfree(p);
|
| 840 | return err;
|
| 841 | }
|
| 842 | EXPORT_SYMBOL(tcf_idr_create);
|
| 843 |
|
| 844 | int tcf_idr_create_from_flags(struct tc_action_net *tn, u32 index,
|
| 845 | struct nlattr *est, struct tc_action **a,
|
| 846 | const struct tc_action_ops *ops, int bind,
|
| 847 | u32 flags)
|
| 848 | {
|
| 849 |
|
| 850 | return tcf_idr_create(tn, index, est, a, ops, bind,
|
| 851 | !(flags & TCA_ACT_FLAGS_NO_PERCPU_STATS), flags);
|
| 852 | }
|
| 853 | EXPORT_SYMBOL(tcf_idr_create_from_flags);
|
| 854 |
|
| 855 |
|
| 856 |
|
| 857 | void tcf_idr_cleanup(struct tc_action_net *tn, u32 index)
|
| 858 | {
|
| 859 | struct tcf_idrinfo *idrinfo = tn->idrinfo;
|
| 860 |
|
| 861 | mutex_lock(&idrinfo->lock);
|
| 862 |
|
| 863 | WARN_ON(!IS_ERR(idr_remove(&idrinfo->action_idr, index)));
|
| 864 | mutex_unlock(&idrinfo->lock);
|
| 865 | }
|
| 866 | EXPORT_SYMBOL(tcf_idr_cleanup);
|
| 867 |
|
| 868 | |
| 869 | * its reference and bind counters, and return 1. Otherwise insert temporary
|
| 870 | * error pointer (to prevent concurrent users from inserting actions with same
|
| 871 | * index) and return 0.
|
| 872 | *
|
| 873 | * May return -EAGAIN for binding actions in case of a parallel add/delete on
|
| 874 | * the requested index.
|
| 875 |
|
| 876 |
|
| 877 | int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index,
|
| 878 | struct tc_action **a, int bind)
|
| 879 | {
|
| 880 | struct tcf_idrinfo *idrinfo = tn->idrinfo;
|
| 881 | struct tc_action *p;
|
| 882 | int ret;
|
| 883 | u32 max;
|
| 884 |
|
| 885 | if (*index) {
|
| 886 | rcu_read_lock();
|
| 887 | p = idr_find(&idrinfo->action_idr, *index);
|
| 888 |
|
| 889 | if (IS_ERR(p)) {
|
| 890 | |
| 891 | * index but did not assign the pointer yet.
|
| 892 |
|
| 893 | rcu_read_unlock();
|
| 894 | return -EAGAIN;
|
| 895 | }
|
| 896 |
|
| 897 | if (!p) {
|
| 898 |
|
| 899 | max = *index;
|
| 900 | rcu_read_unlock();
|
| 901 | goto new;
|
| 902 | }
|
| 903 |
|
| 904 | if (!refcount_inc_not_zero(&p->tcfa_refcnt)) {
|
| 905 |
|
| 906 | rcu_read_unlock();
|
| 907 | return -EAGAIN;
|
| 908 | }
|
| 909 |
|
| 910 | if (bind)
|
| 911 | atomic_inc(&p->tcfa_bindcnt);
|
| 912 | *a = p;
|
| 913 |
|
| 914 | rcu_read_unlock();
|
| 915 |
|
| 916 | return 1;
|
| 917 | } else {
|
| 918 |
|
| 919 | *index = 1;
|
| 920 | max = UINT_MAX;
|
| 921 | }
|
| 922 |
|
| 923 | new:
|
| 924 | *a = NULL;
|
| 925 |
|
| 926 | mutex_lock(&idrinfo->lock);
|
| 927 | ret = idr_alloc_u32(&idrinfo->action_idr, ERR_PTR(-EBUSY), index, max,
|
| 928 | GFP_KERNEL);
|
| 929 | mutex_unlock(&idrinfo->lock);
|
| 930 |
|
| 931 | |
| 932 | * retry for all the ones that failed.
|
| 933 |
|
| 934 | if (ret == -ENOSPC && *index == max)
|
| 935 | ret = -EAGAIN;
|
| 936 |
|
| 937 | return ret;
|
| 938 | }
|
| 939 | EXPORT_SYMBOL(tcf_idr_check_alloc);
|
| 940 |
|
| 941 | void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
|
| 942 | struct tcf_idrinfo *idrinfo)
|
| 943 | {
|
| 944 | struct idr *idr = &idrinfo->action_idr;
|
| 945 | bool mutex_taken = false;
|
| 946 | struct tc_action *p;
|
| 947 | unsigned long id = 1;
|
| 948 | unsigned long tmp;
|
| 949 | int ret;
|
| 950 |
|
| 951 | idr_for_each_entry_ul(idr, p, tmp, id) {
|
| 952 | if (IS_ERR(p))
|
| 953 | continue;
|
| 954 | if (tc_act_in_hw(p) && !mutex_taken) {
|
| 955 | rtnl_lock();
|
| 956 | mutex_taken = true;
|
| 957 | }
|
| 958 | ret = __tcf_idr_release(p, false, true);
|
| 959 | if (ret == ACT_P_DELETED)
|
| 960 | module_put(ops->owner);
|
| 961 | else if (ret < 0)
|
| 962 | return;
|
| 963 | }
|
| 964 | if (mutex_taken)
|
| 965 | rtnl_unlock();
|
| 966 | idr_destroy(&idrinfo->action_idr);
|
| 967 | }
|
| 968 | EXPORT_SYMBOL(tcf_idrinfo_destroy);
|
| 969 |
|
| 970 | static LIST_HEAD(act_base);
|
| 971 | static DEFINE_RWLOCK(act_mod_lock);
|
| 972 | |
| 973 | * then there is no way to walk through only all the action
|
| 974 | * subsystem, so we keep tc action pernet ops id for
|
| 975 | * reoffload to walk through.
|
| 976 |
|
| 977 | static LIST_HEAD(act_pernet_id_list);
|
| 978 | static DEFINE_MUTEX(act_id_mutex);
|
| 979 | struct tc_act_pernet_id {
|
| 980 | struct list_head list;
|
| 981 | unsigned int id;
|
| 982 | };
|
| 983 |
|
| 984 | static int tcf_pernet_add_id_list(unsigned int id)
|
| 985 | {
|
| 986 | struct tc_act_pernet_id *id_ptr;
|
| 987 | int ret = 0;
|
| 988 |
|
| 989 | mutex_lock(&act_id_mutex);
|
| 990 | list_for_each_entry(id_ptr, &act_pernet_id_list, list) {
|
| 991 | if (id_ptr->id == id) {
|
| 992 | ret = -EEXIST;
|
| 993 | goto err_out;
|
| 994 | }
|
| 995 | }
|
| 996 |
|
| 997 | id_ptr = kzalloc_obj(*id_ptr);
|
| 998 | if (!id_ptr) {
|
| 999 | ret = -ENOMEM;
|
| 1000 | goto err_out;
|
| 1001 | }
|
| 1002 | id_ptr->id = id;
|
| 1003 |
|
| 1004 | list_add_tail(&id_ptr->list, &act_pernet_id_list);
|
| 1005 |
|
| 1006 | err_out:
|
| 1007 | mutex_unlock(&act_id_mutex);
|
| 1008 | return ret;
|
| 1009 | }
|
| 1010 |
|
| 1011 | static void tcf_pernet_del_id_list(unsigned int id)
|
| 1012 | {
|
| 1013 | struct tc_act_pernet_id *id_ptr;
|
| 1014 |
|
| 1015 | mutex_lock(&act_id_mutex);
|
| 1016 | list_for_each_entry(id_ptr, &act_pernet_id_list, list) {
|
| 1017 | if (id_ptr->id == id) {
|
| 1018 | list_del(&id_ptr->list);
|
| 1019 | kfree(id_ptr);
|
| 1020 | break;
|
| 1021 | }
|
| 1022 | }
|
| 1023 | mutex_unlock(&act_id_mutex);
|
| 1024 | }
|
| 1025 |
|
| 1026 | int tcf_register_action(struct tc_action_ops *act,
|
| 1027 | struct pernet_operations *ops)
|
| 1028 | {
|
| 1029 | struct tc_action_ops *a;
|
| 1030 | int ret;
|
| 1031 |
|
| 1032 | if (!act->act || !act->dump || !act->init)
|
| 1033 | return -EINVAL;
|
| 1034 |
|
| 1035 | |
| 1036 | * otherwise tcf_action_init_1() could get a partially initialized
|
| 1037 | * netns.
|
| 1038 |
|
| 1039 | ret = register_pernet_subsys(ops);
|
| 1040 | if (ret)
|
| 1041 | return ret;
|
| 1042 |
|
| 1043 | if (ops->id) {
|
| 1044 | ret = tcf_pernet_add_id_list(*ops->id);
|
| 1045 | if (ret)
|
| 1046 | goto err_id;
|
| 1047 | }
|
| 1048 |
|
| 1049 | write_lock(&act_mod_lock);
|
| 1050 | list_for_each_entry(a, &act_base, head) {
|
| 1051 | if (act->id == a->id || (strcmp(act->kind, a->kind) == 0)) {
|
| 1052 | ret = -EEXIST;
|
| 1053 | goto err_out;
|
| 1054 | }
|
| 1055 | }
|
| 1056 | list_add_tail(&act->head, &act_base);
|
| 1057 | write_unlock(&act_mod_lock);
|
| 1058 |
|
| 1059 | return 0;
|
| 1060 |
|
| 1061 | err_out:
|
| 1062 | write_unlock(&act_mod_lock);
|
| 1063 | if (ops->id)
|
| 1064 | tcf_pernet_del_id_list(*ops->id);
|
| 1065 | err_id:
|
| 1066 | unregister_pernet_subsys(ops);
|
| 1067 | return ret;
|
| 1068 | }
|
| 1069 | EXPORT_SYMBOL(tcf_register_action);
|
| 1070 |
|
| 1071 | int tcf_unregister_action(struct tc_action_ops *act,
|
| 1072 | struct pernet_operations *ops)
|
| 1073 | {
|
| 1074 | struct tc_action_ops *a;
|
| 1075 | int err = -ENOENT;
|
| 1076 |
|
| 1077 | write_lock(&act_mod_lock);
|
| 1078 | list_for_each_entry(a, &act_base, head) {
|
| 1079 | if (a == act) {
|
| 1080 | list_del(&act->head);
|
| 1081 | err = 0;
|
| 1082 | break;
|
| 1083 | }
|
| 1084 | }
|
| 1085 | write_unlock(&act_mod_lock);
|
| 1086 | if (!err) {
|
| 1087 | unregister_pernet_subsys(ops);
|
| 1088 | if (ops->id)
|
| 1089 | tcf_pernet_del_id_list(*ops->id);
|
| 1090 | }
|
| 1091 | return err;
|
| 1092 | }
|
| 1093 | EXPORT_SYMBOL(tcf_unregister_action);
|
| 1094 |
|
| 1095 |
|
| 1096 | static struct tc_action_ops *tc_lookup_action_n(char *kind)
|
| 1097 | {
|
| 1098 | struct tc_action_ops *a, *res = NULL;
|
| 1099 |
|
| 1100 | if (kind) {
|
| 1101 | read_lock(&act_mod_lock);
|
| 1102 | list_for_each_entry(a, &act_base, head) {
|
| 1103 | if (strcmp(kind, a->kind) == 0) {
|
| 1104 | if (try_module_get(a->owner))
|
| 1105 | res = a;
|
| 1106 | break;
|
| 1107 | }
|
| 1108 | }
|
| 1109 | read_unlock(&act_mod_lock);
|
| 1110 | }
|
| 1111 | return res;
|
| 1112 | }
|
| 1113 |
|
| 1114 |
|
| 1115 | static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
|
| 1116 | {
|
| 1117 | struct tc_action_ops *a, *res = NULL;
|
| 1118 |
|
| 1119 | if (kind) {
|
| 1120 | read_lock(&act_mod_lock);
|
| 1121 | list_for_each_entry(a, &act_base, head) {
|
| 1122 | if (nla_strcmp(kind, a->kind) == 0) {
|
| 1123 | if (try_module_get(a->owner))
|
| 1124 | res = a;
|
| 1125 | break;
|
| 1126 | }
|
| 1127 | }
|
| 1128 | read_unlock(&act_mod_lock);
|
| 1129 | }
|
| 1130 | return res;
|
| 1131 | }
|
| 1132 |
|
| 1133 |
|
| 1134 | #define TCA_ACT_MAX_PRIO_MASK 0x1FF
|
| 1135 | int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
|
| 1136 | int nr_actions, struct tcf_result *res)
|
| 1137 | {
|
| 1138 | u32 jmp_prgcnt = 0;
|
| 1139 | u32 jmp_ttl = TCA_ACT_MAX_PRIO;
|
| 1140 | int i;
|
| 1141 | int ret = TC_ACT_OK;
|
| 1142 |
|
| 1143 | if (skb_skip_tc_classify(skb))
|
| 1144 | return TC_ACT_OK;
|
| 1145 |
|
| 1146 | restart_act_graph:
|
| 1147 | for (i = 0; i < nr_actions; i++) {
|
| 1148 | const struct tc_action *a = actions[i];
|
| 1149 | int repeat_ttl;
|
| 1150 |
|
| 1151 | if (jmp_prgcnt > 0) {
|
| 1152 | jmp_prgcnt -= 1;
|
| 1153 | continue;
|
| 1154 | }
|
| 1155 |
|
| 1156 | if (tc_act_skip_sw(a->tcfa_flags))
|
| 1157 | continue;
|
| 1158 |
|
| 1159 | repeat_ttl = 32;
|
| 1160 | repeat:
|
| 1161 | ret = tc_act(skb, a, res);
|
| 1162 | if (unlikely(ret == TC_ACT_REPEAT)) {
|
| 1163 | if (--repeat_ttl != 0)
|
| 1164 | goto repeat;
|
| 1165 |
|
| 1166 | net_warn_ratelimited("TC_ACT_REPEAT abuse ?\n");
|
| 1167 | return TC_ACT_OK;
|
| 1168 | }
|
| 1169 | if (TC_ACT_EXT_CMP(ret, TC_ACT_JUMP)) {
|
| 1170 | jmp_prgcnt = ret & TCA_ACT_MAX_PRIO_MASK;
|
| 1171 | if (!jmp_prgcnt || (jmp_prgcnt > nr_actions)) {
|
| 1172 |
|
| 1173 | return TC_ACT_OK;
|
| 1174 | } else {
|
| 1175 | jmp_ttl -= 1;
|
| 1176 | if (jmp_ttl > 0)
|
| 1177 | goto restart_act_graph;
|
| 1178 | else
|
| 1179 | return TC_ACT_OK;
|
| 1180 | }
|
| 1181 | } else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
|
| 1182 | struct tcf_chain *chain = rcu_dereference_bh(a->goto_chain);
|
| 1183 |
|
| 1184 | if (unlikely(!chain)) {
|
| 1185 | tcf_set_drop_reason(skb,
|
| 1186 | SKB_DROP_REASON_TC_CHAIN_NOTFOUND);
|
| 1187 | return TC_ACT_SHOT;
|
| 1188 | }
|
| 1189 | tcf_action_goto_chain_exec(chain, res);
|
| 1190 | }
|
| 1191 |
|
| 1192 | if (ret != TC_ACT_PIPE)
|
| 1193 | break;
|
| 1194 | }
|
| 1195 |
|
| 1196 | return ret;
|
| 1197 | }
|
| 1198 | EXPORT_SYMBOL(tcf_action_exec);
|
| 1199 |
|
| 1200 | int tcf_action_destroy(struct tc_action *actions[], int bind)
|
| 1201 | {
|
| 1202 | struct tc_action *a;
|
| 1203 | int ret = 0, i;
|
| 1204 |
|
| 1205 | tcf_act_for_each_action(i, a, actions) {
|
| 1206 | actions[i] = NULL;
|
| 1207 |
|
| 1208 | ret = tcf_idr_release(a, bind);
|
| 1209 | }
|
| 1210 | return ret;
|
| 1211 | }
|
| 1212 |
|
| 1213 | static int tcf_action_put(struct tc_action *p)
|
| 1214 | {
|
| 1215 | return __tcf_action_put(p, false);
|
| 1216 | }
|
| 1217 |
|
| 1218 | static void tcf_action_put_many(struct tc_action *actions[])
|
| 1219 | {
|
| 1220 | int i;
|
| 1221 |
|
| 1222 |
|
| 1223 | for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
|
| 1224 | struct tc_action *a = actions[i];
|
| 1225 | const struct tc_action_ops *ops;
|
| 1226 |
|
| 1227 | if (!a)
|
| 1228 | continue;
|
| 1229 | ops = a->ops;
|
| 1230 | if (tcf_action_put(a))
|
| 1231 | module_put(ops->owner);
|
| 1232 | }
|
| 1233 | }
|
| 1234 |
|
| 1235 | static void tca_put_bound_many(struct tc_action *actions[], int init_res[])
|
| 1236 | {
|
| 1237 | struct tc_action *a;
|
| 1238 | int i;
|
| 1239 |
|
| 1240 | tcf_act_for_each_action(i, a, actions) {
|
| 1241 | const struct tc_action_ops *ops = a->ops;
|
| 1242 |
|
| 1243 | if (init_res[i] == ACT_P_CREATED)
|
| 1244 | continue;
|
| 1245 |
|
| 1246 | if (tcf_action_put(a))
|
| 1247 | module_put(ops->owner);
|
| 1248 | }
|
| 1249 | }
|
| 1250 |
|
| 1251 | int
|
| 1252 | tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
|
| 1253 | {
|
| 1254 | return a->ops->dump(skb, a, bind, ref);
|
| 1255 | }
|
| 1256 |
|
| 1257 | int tcf_action_dump(struct sk_buff *skb, struct tc_action *actions[],
|
| 1258 | int bind, int ref, bool terse)
|
| 1259 | {
|
| 1260 | struct tc_action *a;
|
| 1261 | int err = -EINVAL, i;
|
| 1262 | struct nlattr *nest;
|
| 1263 |
|
| 1264 | tcf_act_for_each_action(i, a, actions) {
|
| 1265 | nest = nla_nest_start_noflag(skb, i + 1);
|
| 1266 | if (nest == NULL)
|
| 1267 | goto nla_put_failure;
|
| 1268 | err = terse ? tcf_action_dump_terse(skb, a, false) :
|
| 1269 | tcf_action_dump_1(skb, a, bind, ref);
|
| 1270 | if (err < 0)
|
| 1271 | goto errout;
|
| 1272 | nla_nest_end(skb, nest);
|
| 1273 | }
|
| 1274 |
|
| 1275 | return 0;
|
| 1276 |
|
| 1277 | nla_put_failure:
|
| 1278 | err = -EINVAL;
|
| 1279 | errout:
|
| 1280 | nla_nest_cancel(skb, nest);
|
| 1281 | return err;
|
| 1282 | }
|
| 1283 |
|
| 1284 | static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
|
| 1285 | {
|
| 1286 | struct tc_cookie *c = kzalloc_obj(*c);
|
| 1287 | if (!c)
|
| 1288 | return NULL;
|
| 1289 |
|
| 1290 | c->data = nla_memdup(tb[TCA_ACT_COOKIE], GFP_KERNEL);
|
| 1291 | if (!c->data) {
|
| 1292 | kfree(c);
|
| 1293 | return NULL;
|
| 1294 | }
|
| 1295 | c->len = nla_len(tb[TCA_ACT_COOKIE]);
|
| 1296 |
|
| 1297 | return c;
|
| 1298 | }
|
| 1299 |
|
| 1300 | static u8 tcf_action_hw_stats_get(struct nlattr *hw_stats_attr)
|
| 1301 | {
|
| 1302 | struct nla_bitfield32 hw_stats_bf;
|
| 1303 |
|
| 1304 | |
| 1305 | * not care about the type. Return "any" in that case
|
| 1306 | * which is setting on all supported types.
|
| 1307 |
|
| 1308 | if (!hw_stats_attr)
|
| 1309 | return TCA_ACT_HW_STATS_ANY;
|
| 1310 | hw_stats_bf = nla_get_bitfield32(hw_stats_attr);
|
| 1311 | return hw_stats_bf.value;
|
| 1312 | }
|
| 1313 |
|
| 1314 | static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
|
| 1315 | [TCA_ACT_KIND] = { .type = NLA_STRING },
|
| 1316 | [TCA_ACT_INDEX] = { .type = NLA_U32 },
|
| 1317 | [TCA_ACT_COOKIE] = { .type = NLA_BINARY,
|
| 1318 | .len = TC_COOKIE_MAX_SIZE },
|
| 1319 | [TCA_ACT_OPTIONS] = { .type = NLA_NESTED },
|
| 1320 | [TCA_ACT_FLAGS] = NLA_POLICY_BITFIELD32(TCA_ACT_FLAGS_NO_PERCPU_STATS |
|
| 1321 | TCA_ACT_FLAGS_SKIP_HW |
|
| 1322 | TCA_ACT_FLAGS_SKIP_SW),
|
| 1323 | [TCA_ACT_HW_STATS] = NLA_POLICY_BITFIELD32(TCA_ACT_HW_STATS_ANY),
|
| 1324 | };
|
| 1325 |
|
| 1326 | void tcf_idr_insert_many(struct tc_action *actions[], int init_res[])
|
| 1327 | {
|
| 1328 | struct tc_action *a;
|
| 1329 | int i;
|
| 1330 |
|
| 1331 | tcf_act_for_each_action(i, a, actions) {
|
| 1332 | struct tcf_idrinfo *idrinfo;
|
| 1333 |
|
| 1334 | if (init_res[i] == ACT_P_BOUND)
|
| 1335 | continue;
|
| 1336 |
|
| 1337 | idrinfo = a->idrinfo;
|
| 1338 | mutex_lock(&idrinfo->lock);
|
| 1339 |
|
| 1340 | idr_replace(&idrinfo->action_idr, a, a->tcfa_index);
|
| 1341 | mutex_unlock(&idrinfo->lock);
|
| 1342 | }
|
| 1343 | }
|
| 1344 |
|
| 1345 | struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, u32 flags,
|
| 1346 | struct netlink_ext_ack *extack)
|
| 1347 | {
|
| 1348 | bool police = flags & TCA_ACT_FLAGS_POLICE;
|
| 1349 | struct nlattr *tb[TCA_ACT_MAX + 1];
|
| 1350 | struct tc_action_ops *a_o;
|
| 1351 | char act_name[IFNAMSIZ];
|
| 1352 | struct nlattr *kind;
|
| 1353 | int err;
|
| 1354 |
|
| 1355 | if (!police) {
|
| 1356 | err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
|
| 1357 | tcf_action_policy, extack);
|
| 1358 | if (err < 0)
|
| 1359 | return ERR_PTR(err);
|
| 1360 | err = -EINVAL;
|
| 1361 | kind = tb[TCA_ACT_KIND];
|
| 1362 | if (!kind) {
|
| 1363 | NL_SET_ERR_MSG(extack, "TC action kind must be specified");
|
| 1364 | return ERR_PTR(err);
|
| 1365 | }
|
| 1366 | if (nla_strscpy(act_name, kind, IFNAMSIZ) < 0) {
|
| 1367 | NL_SET_ERR_MSG(extack, "TC action name too long");
|
| 1368 | return ERR_PTR(err);
|
| 1369 | }
|
| 1370 | } else {
|
| 1371 | if (strscpy(act_name, "police", IFNAMSIZ) < 0) {
|
| 1372 | NL_SET_ERR_MSG(extack, "TC action name too long");
|
| 1373 | return ERR_PTR(-EINVAL);
|
| 1374 | }
|
| 1375 | }
|
| 1376 |
|
| 1377 | a_o = tc_lookup_action_n(act_name);
|
| 1378 | if (a_o == NULL) {
|
| 1379 | #ifdef CONFIG_MODULES
|
| 1380 | bool rtnl_held = !(flags & TCA_ACT_FLAGS_NO_RTNL);
|
| 1381 |
|
| 1382 | if (rtnl_held)
|
| 1383 | rtnl_unlock();
|
| 1384 | request_module(NET_ACT_ALIAS_PREFIX "%s", act_name);
|
| 1385 | if (rtnl_held)
|
| 1386 | rtnl_lock();
|
| 1387 |
|
| 1388 | a_o = tc_lookup_action_n(act_name);
|
| 1389 |
|
| 1390 | |
| 1391 | * perform the module load. So, even if we
|
| 1392 | * succeeded in loading the module we have to
|
| 1393 | * tell the caller to replay the request. We
|
| 1394 | * indicate this using -EAGAIN.
|
| 1395 |
|
| 1396 | if (a_o != NULL) {
|
| 1397 | module_put(a_o->owner);
|
| 1398 | return ERR_PTR(-EAGAIN);
|
| 1399 | }
|
| 1400 | #endif
|
| 1401 | NL_SET_ERR_MSG(extack, "Failed to load TC action module");
|
| 1402 | return ERR_PTR(-ENOENT);
|
| 1403 | }
|
| 1404 |
|
| 1405 | return a_o;
|
| 1406 | }
|
| 1407 |
|
| 1408 | struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
| 1409 | struct nlattr *nla, struct nlattr *est,
|
| 1410 | struct tc_action_ops *a_o, int *init_res,
|
| 1411 | u32 flags, struct netlink_ext_ack *extack)
|
| 1412 | {
|
| 1413 | bool police = flags & TCA_ACT_FLAGS_POLICE;
|
| 1414 | struct nla_bitfield32 userflags = { 0, 0 };
|
| 1415 | struct tc_cookie *user_cookie = NULL;
|
| 1416 | u8 hw_stats = TCA_ACT_HW_STATS_ANY;
|
| 1417 | struct nlattr *tb[TCA_ACT_MAX + 1];
|
| 1418 | struct tc_action *a;
|
| 1419 | int err;
|
| 1420 |
|
| 1421 |
|
| 1422 | if (!police) {
|
| 1423 | err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
|
| 1424 | tcf_action_policy, extack);
|
| 1425 | if (err < 0)
|
| 1426 | return ERR_PTR(err);
|
| 1427 | if (tb[TCA_ACT_COOKIE]) {
|
| 1428 | user_cookie = nla_memdup_cookie(tb);
|
| 1429 | if (!user_cookie) {
|
| 1430 | NL_SET_ERR_MSG(extack, "No memory to generate TC cookie");
|
| 1431 | err = -ENOMEM;
|
| 1432 | goto err_out;
|
| 1433 | }
|
| 1434 | }
|
| 1435 | hw_stats = tcf_action_hw_stats_get(tb[TCA_ACT_HW_STATS]);
|
| 1436 | if (tb[TCA_ACT_FLAGS]) {
|
| 1437 | userflags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
|
| 1438 | if (!tc_act_flags_valid(userflags.value)) {
|
| 1439 | err = -EINVAL;
|
| 1440 | goto err_out;
|
| 1441 | }
|
| 1442 | }
|
| 1443 |
|
| 1444 | err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp,
|
| 1445 | userflags.value | flags, extack);
|
| 1446 | } else {
|
| 1447 | err = a_o->init(net, nla, est, &a, tp, userflags.value | flags,
|
| 1448 | extack);
|
| 1449 | }
|
| 1450 | if (err < 0)
|
| 1451 | goto err_out;
|
| 1452 | *init_res = err;
|
| 1453 |
|
| 1454 | if (!police && tb[TCA_ACT_COOKIE])
|
| 1455 | tcf_set_action_cookie(&a->user_cookie, user_cookie);
|
| 1456 |
|
| 1457 | if (!police)
|
| 1458 | a->hw_stats = hw_stats;
|
| 1459 |
|
| 1460 | return a;
|
| 1461 |
|
| 1462 | err_out:
|
| 1463 | if (user_cookie) {
|
| 1464 | kfree(user_cookie->data);
|
| 1465 | kfree(user_cookie);
|
| 1466 | }
|
| 1467 | return ERR_PTR(err);
|
| 1468 | }
|
| 1469 |
|
| 1470 | static bool tc_act_bind(u32 flags)
|
| 1471 | {
|
| 1472 | return !!(flags & TCA_ACT_FLAGS_BIND);
|
| 1473 | }
|
| 1474 |
|
| 1475 |
|
| 1476 |
|
| 1477 | int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
|
| 1478 | struct nlattr *est, struct tc_action *actions[],
|
| 1479 | int init_res[], size_t *attr_size,
|
| 1480 | u32 flags, u32 fl_flags,
|
| 1481 | struct netlink_ext_ack *extack)
|
| 1482 | {
|
| 1483 | struct tc_action_ops *ops[TCA_ACT_MAX_PRIO] = {};
|
| 1484 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 2];
|
| 1485 | struct tc_action *act;
|
| 1486 | size_t sz = 0;
|
| 1487 | int err;
|
| 1488 | int i;
|
| 1489 |
|
| 1490 | err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX_PRIO + 1, nla, NULL,
|
| 1491 | extack);
|
| 1492 | if (err < 0)
|
| 1493 | return err;
|
| 1494 |
|
| 1495 | |
| 1496 | * array of actions. So we parse one more than we can handle, and return
|
| 1497 | * an error if the last one is set (as that indicates that the request
|
| 1498 | * contained more than the maximum number of actions).
|
| 1499 |
|
| 1500 | if (tb[TCA_ACT_MAX_PRIO + 1]) {
|
| 1501 | NL_SET_ERR_MSG_FMT(extack,
|
| 1502 | "Only %d actions supported per filter",
|
| 1503 | TCA_ACT_MAX_PRIO);
|
| 1504 | return -EINVAL;
|
| 1505 | }
|
| 1506 |
|
| 1507 | for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
|
| 1508 | struct tc_action_ops *a_o;
|
| 1509 |
|
| 1510 | a_o = tc_action_load_ops(tb[i], flags, extack);
|
| 1511 | if (IS_ERR(a_o)) {
|
| 1512 | err = PTR_ERR(a_o);
|
| 1513 | goto err_mod;
|
| 1514 | }
|
| 1515 | ops[i - 1] = a_o;
|
| 1516 | }
|
| 1517 |
|
| 1518 | for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
|
| 1519 | act = tcf_action_init_1(net, tp, tb[i], est, ops[i - 1],
|
| 1520 | &init_res[i - 1], flags, extack);
|
| 1521 | if (IS_ERR(act)) {
|
| 1522 | err = PTR_ERR(act);
|
| 1523 | goto err;
|
| 1524 | }
|
| 1525 | sz += tcf_action_fill_size(act);
|
| 1526 |
|
| 1527 | actions[i - 1] = act;
|
| 1528 | if (tc_act_bind(flags)) {
|
| 1529 | bool skip_sw = tc_skip_sw(fl_flags);
|
| 1530 | bool skip_hw = tc_skip_hw(fl_flags);
|
| 1531 |
|
| 1532 | if (tc_act_bind(act->tcfa_flags)) {
|
| 1533 | |
| 1534 | * standalone. Check that the user did not set
|
| 1535 | * any action flags different than the
|
| 1536 | * classifier flags, and inherit the flags from
|
| 1537 | * the classifier for the compatibility case
|
| 1538 | * where no flags were specified at all.
|
| 1539 |
|
| 1540 | if ((tc_act_skip_sw(act->tcfa_flags) && !skip_sw) ||
|
| 1541 | (tc_act_skip_hw(act->tcfa_flags) && !skip_hw)) {
|
| 1542 | NL_SET_ERR_MSG(extack,
|
| 1543 | "Mismatch between action and filter offload flags");
|
| 1544 | err = -EINVAL;
|
| 1545 | goto err;
|
| 1546 | }
|
| 1547 | if (skip_sw)
|
| 1548 | act->tcfa_flags |= TCA_ACT_FLAGS_SKIP_SW;
|
| 1549 | if (skip_hw)
|
| 1550 | act->tcfa_flags |= TCA_ACT_FLAGS_SKIP_HW;
|
| 1551 | continue;
|
| 1552 | }
|
| 1553 |
|
| 1554 |
|
| 1555 | if (skip_sw != tc_act_skip_sw(act->tcfa_flags) ||
|
| 1556 | skip_hw != tc_act_skip_hw(act->tcfa_flags)) {
|
| 1557 | NL_SET_ERR_MSG(extack,
|
| 1558 | "Mismatch between action and filter offload flags");
|
| 1559 | err = -EINVAL;
|
| 1560 | goto err;
|
| 1561 | }
|
| 1562 | } else {
|
| 1563 | err = tcf_action_offload_add(act, extack);
|
| 1564 | if (tc_act_skip_sw(act->tcfa_flags) && err)
|
| 1565 | goto err;
|
| 1566 | }
|
| 1567 | }
|
| 1568 |
|
| 1569 | |
| 1570 | * between, we could not handle the failure gracefully.
|
| 1571 |
|
| 1572 | tcf_idr_insert_many(actions, init_res);
|
| 1573 |
|
| 1574 | *attr_size = tcf_action_full_attrs_size(sz);
|
| 1575 | err = i - 1;
|
| 1576 | goto err_mod;
|
| 1577 |
|
| 1578 | err:
|
| 1579 | tcf_action_destroy(actions, flags & TCA_ACT_FLAGS_BIND);
|
| 1580 | err_mod:
|
| 1581 | for (i = 0; i < TCA_ACT_MAX_PRIO && ops[i]; i++)
|
| 1582 | module_put(ops[i]->owner);
|
| 1583 | return err;
|
| 1584 | }
|
| 1585 |
|
| 1586 | void tcf_action_update_stats(struct tc_action *a, u64 bytes, u64 packets,
|
| 1587 | u64 drops, bool hw)
|
| 1588 | {
|
| 1589 | if (a->cpu_bstats) {
|
| 1590 | _bstats_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
|
| 1591 |
|
| 1592 | this_cpu_add(a->cpu_qstats->drops, drops);
|
| 1593 |
|
| 1594 | if (hw)
|
| 1595 | _bstats_update(this_cpu_ptr(a->cpu_bstats_hw),
|
| 1596 | bytes, packets);
|
| 1597 | return;
|
| 1598 | }
|
| 1599 |
|
| 1600 | _bstats_update(&a->tcfa_bstats, bytes, packets);
|
| 1601 | atomic_add(drops, &a->tcfa_drops);
|
| 1602 | if (hw)
|
| 1603 | _bstats_update(&a->tcfa_bstats_hw, bytes, packets);
|
| 1604 | }
|
| 1605 | EXPORT_SYMBOL(tcf_action_update_stats);
|
| 1606 |
|
| 1607 | int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
|
| 1608 | int compat_mode)
|
| 1609 | {
|
| 1610 | struct gnet_stats_queue qstats = {0};
|
| 1611 | struct gnet_dump d;
|
| 1612 | int err = 0;
|
| 1613 |
|
| 1614 | if (p == NULL)
|
| 1615 | goto errout;
|
| 1616 |
|
| 1617 | |
| 1618 | * to add additional backward compatibility statistic TLVs.
|
| 1619 |
|
| 1620 | if (compat_mode) {
|
| 1621 | if (p->type == TCA_OLD_COMPAT)
|
| 1622 | err = gnet_stats_start_copy_compat(skb, 0,
|
| 1623 | TCA_STATS,
|
| 1624 | TCA_XSTATS,
|
| 1625 | &p->tcfa_lock, &d,
|
| 1626 | TCA_PAD);
|
| 1627 | else
|
| 1628 | return 0;
|
| 1629 | } else
|
| 1630 | err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
|
| 1631 | &p->tcfa_lock, &d, TCA_ACT_PAD);
|
| 1632 |
|
| 1633 | if (err < 0)
|
| 1634 | goto errout;
|
| 1635 |
|
| 1636 | qstats.drops = atomic_read(&p->tcfa_drops);
|
| 1637 | qstats.overlimits = atomic_read(&p->tcfa_overlimits);
|
| 1638 |
|
| 1639 | if (gnet_stats_copy_basic(&d, p->cpu_bstats,
|
| 1640 | &p->tcfa_bstats, false) < 0 ||
|
| 1641 | gnet_stats_copy_basic_hw(&d, p->cpu_bstats_hw,
|
| 1642 | &p->tcfa_bstats_hw, false) < 0 ||
|
| 1643 | gnet_stats_copy_rate_est(&d, &p->tcfa_rate_est) < 0 ||
|
| 1644 | gnet_stats_copy_queue(&d, p->cpu_qstats,
|
| 1645 | &qstats,
|
| 1646 | qstats.qlen) < 0)
|
| 1647 | goto errout;
|
| 1648 |
|
| 1649 | if (gnet_stats_finish_copy(&d) < 0)
|
| 1650 | goto errout;
|
| 1651 |
|
| 1652 | return 0;
|
| 1653 |
|
| 1654 | errout:
|
| 1655 | return -1;
|
| 1656 | }
|
| 1657 |
|
| 1658 | static int tca_get_fill(struct sk_buff *skb, struct tc_action *actions[],
|
| 1659 | u32 portid, u32 seq, u16 flags, int event, int bind,
|
| 1660 | int ref, struct netlink_ext_ack *extack)
|
| 1661 | {
|
| 1662 | struct tcamsg *t;
|
| 1663 | struct nlmsghdr *nlh;
|
| 1664 | unsigned char *b = skb_tail_pointer(skb);
|
| 1665 | struct nlattr *nest;
|
| 1666 |
|
| 1667 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags);
|
| 1668 | if (!nlh)
|
| 1669 | goto out_nlmsg_trim;
|
| 1670 | t = nlmsg_data(nlh);
|
| 1671 | t->tca_family = AF_UNSPEC;
|
| 1672 | t->tca__pad1 = 0;
|
| 1673 | t->tca__pad2 = 0;
|
| 1674 |
|
| 1675 | if (extack && extack->_msg &&
|
| 1676 | nla_put_string(skb, TCA_ROOT_EXT_WARN_MSG, extack->_msg))
|
| 1677 | goto out_nlmsg_trim;
|
| 1678 |
|
| 1679 | nest = nla_nest_start_noflag(skb, TCA_ACT_TAB);
|
| 1680 | if (!nest)
|
| 1681 | goto out_nlmsg_trim;
|
| 1682 |
|
| 1683 | if (tcf_action_dump(skb, actions, bind, ref, false) < 0)
|
| 1684 | goto out_nlmsg_trim;
|
| 1685 |
|
| 1686 | nla_nest_end(skb, nest);
|
| 1687 |
|
| 1688 | nlh->nlmsg_len = skb_tail_pointer(skb) - b;
|
| 1689 |
|
| 1690 | return skb->len;
|
| 1691 |
|
| 1692 | out_nlmsg_trim:
|
| 1693 | nlmsg_trim(skb, b);
|
| 1694 | return -1;
|
| 1695 | }
|
| 1696 |
|
| 1697 | static int
|
| 1698 | tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
|
| 1699 | struct tc_action *actions[], size_t attr_size, int event,
|
| 1700 | struct netlink_ext_ack *extack)
|
| 1701 | {
|
| 1702 | struct sk_buff *skb;
|
| 1703 |
|
| 1704 | skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
|
| 1705 | if (!skb)
|
| 1706 | return -ENOBUFS;
|
| 1707 | if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event,
|
| 1708 | 0, 1, NULL) <= 0) {
|
| 1709 | NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action");
|
| 1710 | kfree_skb(skb);
|
| 1711 | return -EINVAL;
|
| 1712 | }
|
| 1713 |
|
| 1714 | return rtnl_unicast(skb, net, portid);
|
| 1715 | }
|
| 1716 |
|
| 1717 | static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
|
| 1718 | struct nlmsghdr *n, u32 portid,
|
| 1719 | struct netlink_ext_ack *extack)
|
| 1720 | {
|
| 1721 | struct nlattr *tb[TCA_ACT_MAX + 1];
|
| 1722 | const struct tc_action_ops *ops;
|
| 1723 | struct tc_action *a;
|
| 1724 | int index;
|
| 1725 | int err;
|
| 1726 |
|
| 1727 | err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
|
| 1728 | tcf_action_policy, extack);
|
| 1729 | if (err < 0)
|
| 1730 | goto err_out;
|
| 1731 |
|
| 1732 | err = -EINVAL;
|
| 1733 | if (tb[TCA_ACT_INDEX] == NULL ||
|
| 1734 | nla_len(tb[TCA_ACT_INDEX]) < sizeof(index)) {
|
| 1735 | NL_SET_ERR_MSG(extack, "Invalid TC action index value");
|
| 1736 | goto err_out;
|
| 1737 | }
|
| 1738 | index = nla_get_u32(tb[TCA_ACT_INDEX]);
|
| 1739 |
|
| 1740 | err = -EINVAL;
|
| 1741 | ops = tc_lookup_action(tb[TCA_ACT_KIND]);
|
| 1742 | if (!ops) {
|
| 1743 | NL_SET_ERR_MSG(extack, "Specified TC action kind not found");
|
| 1744 | goto err_out;
|
| 1745 | }
|
| 1746 | err = -ENOENT;
|
| 1747 | if (__tcf_idr_search(net, ops, &a, index) == 0) {
|
| 1748 | NL_SET_ERR_MSG(extack, "TC action with specified index not found");
|
| 1749 | goto err_mod;
|
| 1750 | }
|
| 1751 |
|
| 1752 | module_put(ops->owner);
|
| 1753 | return a;
|
| 1754 |
|
| 1755 | err_mod:
|
| 1756 | module_put(ops->owner);
|
| 1757 | err_out:
|
| 1758 | return ERR_PTR(err);
|
| 1759 | }
|
| 1760 |
|
| 1761 | static int tca_action_flush(struct net *net, struct nlattr *nla,
|
| 1762 | struct nlmsghdr *n, u32 portid,
|
| 1763 | struct netlink_ext_ack *extack)
|
| 1764 | {
|
| 1765 | struct sk_buff *skb;
|
| 1766 | unsigned char *b;
|
| 1767 | struct nlmsghdr *nlh;
|
| 1768 | struct tcamsg *t;
|
| 1769 | struct netlink_callback dcb;
|
| 1770 | struct nlattr *nest;
|
| 1771 | struct nlattr *tb[TCA_ACT_MAX + 1];
|
| 1772 | const struct tc_action_ops *ops;
|
| 1773 | struct nlattr *kind;
|
| 1774 | int err = -ENOMEM;
|
| 1775 |
|
| 1776 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
|
| 1777 | if (!skb)
|
| 1778 | return err;
|
| 1779 |
|
| 1780 | b = skb_tail_pointer(skb);
|
| 1781 |
|
| 1782 | err = nla_parse_nested_deprecated(tb, TCA_ACT_MAX, nla,
|
| 1783 | tcf_action_policy, extack);
|
| 1784 | if (err < 0)
|
| 1785 | goto err_out;
|
| 1786 |
|
| 1787 | err = -EINVAL;
|
| 1788 | kind = tb[TCA_ACT_KIND];
|
| 1789 | ops = tc_lookup_action(kind);
|
| 1790 | if (!ops) {
|
| 1791 | NL_SET_ERR_MSG(extack, "Cannot flush unknown TC action");
|
| 1792 | goto err_out;
|
| 1793 | }
|
| 1794 |
|
| 1795 | nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION,
|
| 1796 | sizeof(*t), 0);
|
| 1797 | if (!nlh) {
|
| 1798 | NL_SET_ERR_MSG(extack, "Failed to create TC action flush notification");
|
| 1799 | goto out_module_put;
|
| 1800 | }
|
| 1801 | t = nlmsg_data(nlh);
|
| 1802 | t->tca_family = AF_UNSPEC;
|
| 1803 | t->tca__pad1 = 0;
|
| 1804 | t->tca__pad2 = 0;
|
| 1805 |
|
| 1806 | nest = nla_nest_start_noflag(skb, TCA_ACT_TAB);
|
| 1807 | if (!nest) {
|
| 1808 | NL_SET_ERR_MSG(extack, "Failed to add new netlink message");
|
| 1809 | goto out_module_put;
|
| 1810 | }
|
| 1811 |
|
| 1812 | err = __tcf_generic_walker(net, skb, &dcb, RTM_DELACTION, ops, extack);
|
| 1813 | if (err <= 0) {
|
| 1814 | nla_nest_cancel(skb, nest);
|
| 1815 | goto out_module_put;
|
| 1816 | }
|
| 1817 |
|
| 1818 | nla_nest_end(skb, nest);
|
| 1819 |
|
| 1820 | nlh->nlmsg_len = skb_tail_pointer(skb) - b;
|
| 1821 | nlh->nlmsg_flags |= NLM_F_ROOT;
|
| 1822 | module_put(ops->owner);
|
| 1823 | err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
|
| 1824 | n->nlmsg_flags & NLM_F_ECHO);
|
| 1825 | if (err < 0)
|
| 1826 | NL_SET_ERR_MSG(extack, "Failed to send TC action flush notification");
|
| 1827 |
|
| 1828 | return err;
|
| 1829 |
|
| 1830 | out_module_put:
|
| 1831 | module_put(ops->owner);
|
| 1832 | err_out:
|
| 1833 | kfree_skb(skb);
|
| 1834 | return err;
|
| 1835 | }
|
| 1836 |
|
| 1837 | static int tcf_action_delete(struct net *net, struct tc_action *actions[])
|
| 1838 | {
|
| 1839 | struct tc_action *a;
|
| 1840 | int i;
|
| 1841 |
|
| 1842 | tcf_act_for_each_action(i, a, actions) {
|
| 1843 | const struct tc_action_ops *ops = a->ops;
|
| 1844 | |
| 1845 | * type and id to search again after reference is released.
|
| 1846 |
|
| 1847 | struct tcf_idrinfo *idrinfo = a->idrinfo;
|
| 1848 | u32 act_index = a->tcfa_index;
|
| 1849 |
|
| 1850 | actions[i] = NULL;
|
| 1851 | if (tcf_action_put(a)) {
|
| 1852 |
|
| 1853 | module_put(ops->owner);
|
| 1854 | } else {
|
| 1855 | int ret;
|
| 1856 |
|
| 1857 |
|
| 1858 | ret = tcf_idr_delete_index(idrinfo, act_index);
|
| 1859 | if (ret < 0)
|
| 1860 | return ret;
|
| 1861 | }
|
| 1862 | }
|
| 1863 | return 0;
|
| 1864 | }
|
| 1865 |
|
| 1866 | static struct sk_buff *tcf_reoffload_del_notify_msg(struct net *net,
|
| 1867 | struct tc_action *action)
|
| 1868 | {
|
| 1869 | struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
|
| 1870 | [0] = action,
|
| 1871 | };
|
| 1872 | struct sk_buff *skb;
|
| 1873 | size_t attr_size;
|
| 1874 |
|
| 1875 | attr_size = tcf_action_full_attrs_size(tcf_action_fill_size(action));
|
| 1876 |
|
| 1877 | skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
|
| 1878 | if (!skb)
|
| 1879 | return ERR_PTR(-ENOBUFS);
|
| 1880 |
|
| 1881 | if (tca_get_fill(skb, actions, 0, 0, 0, RTM_DELACTION, 0, 1, NULL) <= 0) {
|
| 1882 | kfree_skb(skb);
|
| 1883 | return ERR_PTR(-EINVAL);
|
| 1884 | }
|
| 1885 |
|
| 1886 | return skb;
|
| 1887 | }
|
| 1888 |
|
| 1889 | static int tcf_reoffload_del_notify(struct net *net, struct tc_action *action)
|
| 1890 | {
|
| 1891 | const struct tc_action_ops *ops = action->ops;
|
| 1892 | struct sk_buff *skb = NULL;
|
| 1893 | int ret;
|
| 1894 |
|
| 1895 | if (rtnl_notify_needed(net, 0, RTNLGRP_TC)) {
|
| 1896 | skb = tcf_reoffload_del_notify_msg(net, action);
|
| 1897 | |
| 1898 | * skip_sw, so it must be released whether or not the
|
| 1899 | * notification can be built. Drop the notification rather
|
| 1900 | * than leave an action behind that processes no packets.
|
| 1901 |
|
| 1902 | if (IS_ERR(skb))
|
| 1903 | skb = NULL;
|
| 1904 | }
|
| 1905 |
|
| 1906 | ret = tcf_idr_release_unsafe(action);
|
| 1907 | if (ret == ACT_P_DELETED) {
|
| 1908 | module_put(ops->owner);
|
| 1909 | ret = rtnetlink_maybe_send(skb, net, 0, RTNLGRP_TC, 0);
|
| 1910 | } else {
|
| 1911 | kfree_skb(skb);
|
| 1912 | }
|
| 1913 |
|
| 1914 | return ret;
|
| 1915 | }
|
| 1916 |
|
| 1917 | int tcf_action_reoffload_cb(flow_indr_block_bind_cb_t *cb,
|
| 1918 | void *cb_priv, bool add)
|
| 1919 | {
|
| 1920 | struct tc_act_pernet_id *id_ptr;
|
| 1921 | struct tcf_idrinfo *idrinfo;
|
| 1922 | struct tc_action_net *tn;
|
| 1923 | struct tc_action *p;
|
| 1924 | unsigned int act_id;
|
| 1925 | unsigned long tmp;
|
| 1926 | unsigned long id;
|
| 1927 | struct idr *idr;
|
| 1928 | struct net *net;
|
| 1929 | int ret;
|
| 1930 |
|
| 1931 | if (!cb)
|
| 1932 | return -EINVAL;
|
| 1933 |
|
| 1934 | down_read(&net_rwsem);
|
| 1935 | mutex_lock(&act_id_mutex);
|
| 1936 |
|
| 1937 | for_each_net(net) {
|
| 1938 | list_for_each_entry(id_ptr, &act_pernet_id_list, list) {
|
| 1939 | act_id = id_ptr->id;
|
| 1940 | tn = net_generic(net, act_id);
|
| 1941 | if (!tn)
|
| 1942 | continue;
|
| 1943 | idrinfo = tn->idrinfo;
|
| 1944 | if (!idrinfo)
|
| 1945 | continue;
|
| 1946 |
|
| 1947 | mutex_lock(&idrinfo->lock);
|
| 1948 | idr = &idrinfo->action_idr;
|
| 1949 | idr_for_each_entry_ul(idr, p, tmp, id) {
|
| 1950 | if (IS_ERR(p) || tc_act_bind(p->tcfa_flags))
|
| 1951 | continue;
|
| 1952 | if (add) {
|
| 1953 | tcf_action_offload_add_ex(p, NULL, cb,
|
| 1954 | cb_priv);
|
| 1955 | continue;
|
| 1956 | }
|
| 1957 |
|
| 1958 |
|
| 1959 | ret = tcf_action_offload_del_ex(p, cb, cb_priv);
|
| 1960 | if (ret < 0)
|
| 1961 | continue;
|
| 1962 | if (tc_act_skip_sw(p->tcfa_flags) &&
|
| 1963 | !tc_act_in_hw(p))
|
| 1964 | tcf_reoffload_del_notify(net, p);
|
| 1965 | }
|
| 1966 | mutex_unlock(&idrinfo->lock);
|
| 1967 | }
|
| 1968 | }
|
| 1969 | mutex_unlock(&act_id_mutex);
|
| 1970 | up_read(&net_rwsem);
|
| 1971 |
|
| 1972 | return 0;
|
| 1973 | }
|
| 1974 |
|
| 1975 | static struct sk_buff *tcf_del_notify_msg(struct net *net, struct nlmsghdr *n,
|
| 1976 | struct tc_action *actions[],
|
| 1977 | u32 portid, size_t attr_size,
|
| 1978 | struct netlink_ext_ack *extack)
|
| 1979 | {
|
| 1980 | struct sk_buff *skb;
|
| 1981 |
|
| 1982 | skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
|
| 1983 | if (!skb)
|
| 1984 | return ERR_PTR(-ENOBUFS);
|
| 1985 |
|
| 1986 | if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
|
| 1987 | 0, 2, extack) <= 0) {
|
| 1988 | NL_SET_ERR_MSG(extack, "Failed to fill netlink TC action attributes");
|
| 1989 | kfree_skb(skb);
|
| 1990 | return ERR_PTR(-EINVAL);
|
| 1991 | }
|
| 1992 |
|
| 1993 | return skb;
|
| 1994 | }
|
| 1995 |
|
| 1996 | static int tcf_del_notify(struct net *net, struct nlmsghdr *n,
|
| 1997 | struct tc_action *actions[], u32 portid,
|
| 1998 | size_t attr_size, struct netlink_ext_ack *extack)
|
| 1999 | {
|
| 2000 | struct sk_buff *skb;
|
| 2001 | int ret;
|
| 2002 |
|
| 2003 | if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC)) {
|
| 2004 | skb = NULL;
|
| 2005 | } else {
|
| 2006 | skb = tcf_del_notify_msg(net, n, actions, portid, attr_size,
|
| 2007 | extack);
|
| 2008 | if (IS_ERR(skb))
|
| 2009 | return PTR_ERR(skb);
|
| 2010 | }
|
| 2011 |
|
| 2012 |
|
| 2013 | ret = tcf_action_delete(net, actions);
|
| 2014 | if (ret < 0) {
|
| 2015 | NL_SET_ERR_MSG(extack, "Failed to delete TC action");
|
| 2016 | kfree_skb(skb);
|
| 2017 | return ret;
|
| 2018 | }
|
| 2019 |
|
| 2020 | return rtnetlink_maybe_send(skb, net, portid, RTNLGRP_TC,
|
| 2021 | n->nlmsg_flags & NLM_F_ECHO);
|
| 2022 | }
|
| 2023 |
|
| 2024 | static int
|
| 2025 | tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
|
| 2026 | u32 portid, int event, struct netlink_ext_ack *extack)
|
| 2027 | {
|
| 2028 | int i, ret;
|
| 2029 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
|
| 2030 | struct tc_action *act;
|
| 2031 | size_t attr_size = 0;
|
| 2032 | struct tc_action *actions[TCA_ACT_MAX_PRIO] = {};
|
| 2033 |
|
| 2034 | ret = nla_parse_nested_deprecated(tb, TCA_ACT_MAX_PRIO, nla, NULL,
|
| 2035 | extack);
|
| 2036 | if (ret < 0)
|
| 2037 | return ret;
|
| 2038 |
|
| 2039 | if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) {
|
| 2040 | if (tb[1])
|
| 2041 | return tca_action_flush(net, tb[1], n, portid, extack);
|
| 2042 |
|
| 2043 | NL_SET_ERR_MSG(extack, "Invalid netlink attributes while flushing TC action");
|
| 2044 | return -EINVAL;
|
| 2045 | }
|
| 2046 |
|
| 2047 | for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
|
| 2048 | act = tcf_action_get_1(net, tb[i], n, portid, extack);
|
| 2049 | if (IS_ERR(act)) {
|
| 2050 | ret = PTR_ERR(act);
|
| 2051 | goto err;
|
| 2052 | }
|
| 2053 | attr_size += tcf_action_fill_size(act);
|
| 2054 | actions[i - 1] = act;
|
| 2055 | }
|
| 2056 |
|
| 2057 | attr_size = tcf_action_full_attrs_size(attr_size);
|
| 2058 |
|
| 2059 | if (event == RTM_GETACTION)
|
| 2060 | ret = tcf_get_notify(net, portid, n, actions, attr_size, event,
|
| 2061 | extack);
|
| 2062 | else {
|
| 2063 | ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
|
| 2064 | if (ret)
|
| 2065 | goto err;
|
| 2066 | return 0;
|
| 2067 | }
|
| 2068 | err:
|
| 2069 | tcf_action_put_many(actions);
|
| 2070 | return ret;
|
| 2071 | }
|
| 2072 |
|
| 2073 | static struct sk_buff *tcf_add_notify_msg(struct net *net, struct nlmsghdr *n,
|
| 2074 | struct tc_action *actions[],
|
| 2075 | u32 portid, size_t attr_size,
|
| 2076 | struct netlink_ext_ack *extack)
|
| 2077 | {
|
| 2078 | struct sk_buff *skb;
|
| 2079 |
|
| 2080 | skb = alloc_skb(max(attr_size, NLMSG_GOODSIZE), GFP_KERNEL);
|
| 2081 | if (!skb)
|
| 2082 | return ERR_PTR(-ENOBUFS);
|
| 2083 |
|
| 2084 | if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
|
| 2085 | RTM_NEWACTION, 0, 0, extack) <= 0) {
|
| 2086 | NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action");
|
| 2087 | kfree_skb(skb);
|
| 2088 | return ERR_PTR(-EINVAL);
|
| 2089 | }
|
| 2090 |
|
| 2091 | return skb;
|
| 2092 | }
|
| 2093 |
|
| 2094 | static int tcf_add_notify(struct net *net, struct nlmsghdr *n,
|
| 2095 | struct tc_action *actions[], u32 portid,
|
| 2096 | size_t attr_size, struct netlink_ext_ack *extack)
|
| 2097 | {
|
| 2098 | struct sk_buff *skb;
|
| 2099 |
|
| 2100 | if (!rtnl_notify_needed(net, n->nlmsg_flags, RTNLGRP_TC)) {
|
| 2101 | skb = NULL;
|
| 2102 | } else {
|
| 2103 | skb = tcf_add_notify_msg(net, n, actions, portid, attr_size,
|
| 2104 | extack);
|
| 2105 | if (IS_ERR(skb))
|
| 2106 | return PTR_ERR(skb);
|
| 2107 | }
|
| 2108 |
|
| 2109 | return rtnetlink_maybe_send(skb, net, portid, RTNLGRP_TC,
|
| 2110 | n->nlmsg_flags & NLM_F_ECHO);
|
| 2111 | }
|
| 2112 |
|
| 2113 | static int tcf_action_add(struct net *net, struct nlattr *nla,
|
| 2114 | struct nlmsghdr *n, u32 portid, u32 flags,
|
| 2115 | struct netlink_ext_ack *extack)
|
| 2116 | {
|
| 2117 | size_t attr_size = 0;
|
| 2118 | int loop, ret;
|
| 2119 | struct tc_action *actions[TCA_ACT_MAX_PRIO] = {};
|
| 2120 | int init_res[TCA_ACT_MAX_PRIO] = {};
|
| 2121 |
|
| 2122 | for (loop = 0; loop < 10; loop++) {
|
| 2123 | ret = tcf_action_init(net, NULL, nla, NULL, actions, init_res,
|
| 2124 | &attr_size, flags, 0, extack);
|
| 2125 | if (ret != -EAGAIN)
|
| 2126 | break;
|
| 2127 | }
|
| 2128 |
|
| 2129 | if (ret < 0)
|
| 2130 | return ret;
|
| 2131 |
|
| 2132 | ret = tcf_add_notify(net, n, actions, portid, attr_size, extack);
|
| 2133 |
|
| 2134 |
|
| 2135 | tca_put_bound_many(actions, init_res);
|
| 2136 |
|
| 2137 | return ret;
|
| 2138 | }
|
| 2139 |
|
| 2140 | static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
| 2141 | [TCA_ROOT_FLAGS] = NLA_POLICY_BITFIELD32(TCA_ACT_FLAG_LARGE_DUMP_ON |
|
| 2142 | TCA_ACT_FLAG_TERSE_DUMP),
|
| 2143 | [TCA_ROOT_TIME_DELTA] = { .type = NLA_U32 },
|
| 2144 | };
|
| 2145 |
|
| 2146 | static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
|
| 2147 | struct netlink_ext_ack *extack)
|
| 2148 | {
|
| 2149 | struct net *net = sock_net(skb->sk);
|
| 2150 | struct nlattr *tca[TCA_ROOT_MAX + 1];
|
| 2151 | u32 portid = NETLINK_CB(skb).portid;
|
| 2152 | u32 flags = 0;
|
| 2153 | int ret = 0;
|
| 2154 |
|
| 2155 | if ((n->nlmsg_type != RTM_GETACTION) &&
|
| 2156 | !netlink_capable(skb, CAP_NET_ADMIN))
|
| 2157 | return -EPERM;
|
| 2158 |
|
| 2159 | ret = nlmsg_parse_deprecated(n, sizeof(struct tcamsg), tca,
|
| 2160 | TCA_ROOT_MAX, NULL, extack);
|
| 2161 | if (ret < 0)
|
| 2162 | return ret;
|
| 2163 |
|
| 2164 | if (tca[TCA_ACT_TAB] == NULL) {
|
| 2165 | NL_SET_ERR_MSG(extack, "Netlink action attributes missing");
|
| 2166 | return -EINVAL;
|
| 2167 | }
|
| 2168 |
|
| 2169 |
|
| 2170 | switch (n->nlmsg_type) {
|
| 2171 | case RTM_NEWACTION:
|
| 2172 | |
| 2173 | * imply create only if it doesn't exist
|
| 2174 | * Note that CREATE | EXCL implies that
|
| 2175 | * but since we want avoid ambiguity (eg when flags
|
| 2176 | * is zero) then just set this
|
| 2177 |
|
| 2178 | if (n->nlmsg_flags & NLM_F_REPLACE)
|
| 2179 | flags = TCA_ACT_FLAGS_REPLACE;
|
| 2180 | ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, flags,
|
| 2181 | extack);
|
| 2182 | break;
|
| 2183 | case RTM_DELACTION:
|
| 2184 | ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
|
| 2185 | portid, RTM_DELACTION, extack);
|
| 2186 | break;
|
| 2187 | case RTM_GETACTION:
|
| 2188 | ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
|
| 2189 | portid, RTM_GETACTION, extack);
|
| 2190 | break;
|
| 2191 | default:
|
| 2192 | BUG();
|
| 2193 | }
|
| 2194 |
|
| 2195 | return ret;
|
| 2196 | }
|
| 2197 |
|
| 2198 | static struct nlattr *find_dump_kind(struct nlattr **nla)
|
| 2199 | {
|
| 2200 | struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
|
| 2201 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
|
| 2202 | struct nlattr *kind;
|
| 2203 |
|
| 2204 | tb1 = nla[TCA_ACT_TAB];
|
| 2205 | if (tb1 == NULL)
|
| 2206 | return NULL;
|
| 2207 |
|
| 2208 | if (nla_parse_deprecated(tb, TCA_ACT_MAX_PRIO, nla_data(tb1), NLMSG_ALIGN(nla_len(tb1)), NULL, NULL) < 0)
|
| 2209 | return NULL;
|
| 2210 |
|
| 2211 | if (tb[1] == NULL)
|
| 2212 | return NULL;
|
| 2213 | if (nla_parse_nested_deprecated(tb2, TCA_ACT_MAX, tb[1], tcf_action_policy, NULL) < 0)
|
| 2214 | return NULL;
|
| 2215 | kind = tb2[TCA_ACT_KIND];
|
| 2216 |
|
| 2217 | return kind;
|
| 2218 | }
|
| 2219 |
|
| 2220 | static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
|
| 2221 | {
|
| 2222 | struct net *net = sock_net(skb->sk);
|
| 2223 | struct nlmsghdr *nlh;
|
| 2224 | unsigned char *b = skb_tail_pointer(skb);
|
| 2225 | struct nlattr *nest;
|
| 2226 | struct tc_action_ops *a_o;
|
| 2227 | int ret = 0;
|
| 2228 | struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
|
| 2229 | struct nlattr *tb[TCA_ROOT_MAX + 1];
|
| 2230 | struct nlattr *count_attr = NULL;
|
| 2231 | unsigned long jiffy_since = 0;
|
| 2232 | struct nlattr *kind = NULL;
|
| 2233 | struct nla_bitfield32 bf;
|
| 2234 | u32 msecs_since = 0;
|
| 2235 | u32 act_count = 0;
|
| 2236 |
|
| 2237 | ret = nlmsg_parse_deprecated(cb->nlh, sizeof(struct tcamsg), tb,
|
| 2238 | TCA_ROOT_MAX, tcaa_policy, cb->extack);
|
| 2239 | if (ret < 0)
|
| 2240 | return ret;
|
| 2241 |
|
| 2242 | kind = find_dump_kind(tb);
|
| 2243 | if (kind == NULL) {
|
| 2244 | pr_info("tc_dump_action: action bad kind\n");
|
| 2245 | return 0;
|
| 2246 | }
|
| 2247 |
|
| 2248 | a_o = tc_lookup_action(kind);
|
| 2249 | if (a_o == NULL)
|
| 2250 | return 0;
|
| 2251 |
|
| 2252 | cb->args[2] = 0;
|
| 2253 | if (tb[TCA_ROOT_FLAGS]) {
|
| 2254 | bf = nla_get_bitfield32(tb[TCA_ROOT_FLAGS]);
|
| 2255 | cb->args[2] = bf.value;
|
| 2256 | }
|
| 2257 |
|
| 2258 | if (tb[TCA_ROOT_TIME_DELTA]) {
|
| 2259 | msecs_since = nla_get_u32(tb[TCA_ROOT_TIME_DELTA]);
|
| 2260 | }
|
| 2261 |
|
| 2262 | nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
| 2263 | cb->nlh->nlmsg_type, sizeof(*t), 0);
|
| 2264 | if (!nlh)
|
| 2265 | goto out_module_put;
|
| 2266 |
|
| 2267 | if (msecs_since)
|
| 2268 | jiffy_since = jiffies - msecs_to_jiffies(msecs_since);
|
| 2269 |
|
| 2270 | t = nlmsg_data(nlh);
|
| 2271 | t->tca_family = AF_UNSPEC;
|
| 2272 | t->tca__pad1 = 0;
|
| 2273 | t->tca__pad2 = 0;
|
| 2274 | cb->args[3] = jiffy_since;
|
| 2275 | count_attr = nla_reserve(skb, TCA_ROOT_COUNT, sizeof(u32));
|
| 2276 | if (!count_attr)
|
| 2277 | goto out_module_put;
|
| 2278 |
|
| 2279 | nest = nla_nest_start_noflag(skb, TCA_ACT_TAB);
|
| 2280 | if (nest == NULL)
|
| 2281 | goto out_module_put;
|
| 2282 |
|
| 2283 | ret = __tcf_generic_walker(net, skb, cb, RTM_GETACTION, a_o, NULL);
|
| 2284 | if (ret < 0)
|
| 2285 | goto out_module_put;
|
| 2286 |
|
| 2287 | if (ret > 0) {
|
| 2288 | nla_nest_end(skb, nest);
|
| 2289 | ret = skb->len;
|
| 2290 | act_count = cb->args[1];
|
| 2291 | memcpy(nla_data(count_attr), &act_count, sizeof(u32));
|
| 2292 | cb->args[1] = 0;
|
| 2293 | } else
|
| 2294 | nlmsg_trim(skb, b);
|
| 2295 |
|
| 2296 | nlh->nlmsg_len = skb_tail_pointer(skb) - b;
|
| 2297 | if (NETLINK_CB(cb->skb).portid && ret)
|
| 2298 | nlh->nlmsg_flags |= NLM_F_MULTI;
|
| 2299 | module_put(a_o->owner);
|
| 2300 | return skb->len;
|
| 2301 |
|
| 2302 | out_module_put:
|
| 2303 | module_put(a_o->owner);
|
| 2304 | nlmsg_trim(skb, b);
|
| 2305 | return skb->len;
|
| 2306 | }
|
| 2307 |
|
| 2308 | static const struct rtnl_msg_handler tc_action_rtnl_msg_handlers[] __initconst = {
|
| 2309 | {.msgtype = RTM_NEWACTION, .doit = tc_ctl_action},
|
| 2310 | {.msgtype = RTM_DELACTION, .doit = tc_ctl_action},
|
| 2311 | {.msgtype = RTM_GETACTION, .doit = tc_ctl_action,
|
| 2312 | .dumpit = tc_dump_action},
|
| 2313 | };
|
| 2314 |
|
| 2315 | static int __init tc_action_init(void)
|
| 2316 | {
|
| 2317 | rtnl_register_many(tc_action_rtnl_msg_handlers);
|
| 2318 | return 0;
|
| 2319 | }
|
| 2320 |
|
| 2321 | subsys_initcall(tc_action_init);
|