1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * net/sched/act_mirred.c packet mirroring and redirect actions 4 * 5 * Authors: Jamal Hadi Salim (2002-4) 6 * 7 * TODO: Add ingress support (and socket redirect support) 8 */ 9 10 #include <linux/types.h> 11 #include <linux/kernel.h> 12 #include <linux/string.h> 13 #include <linux/errno.h> 14 #include <linux/skbuff.h> 15 #include <linux/rtnetlink.h> 16 #include <linux/module.h> 17 #include <linux/init.h> 18 #include <linux/gfp.h> 19 #include <linux/if_arp.h> 20 #include <net/net_namespace.h> 21 #include <net/netlink.h> 22 #include <net/dst.h> 23 #include <net/pkt_sched.h> 24 #include <net/pkt_cls.h> 25 #include <linux/tc_act/tc_mirred.h> 26 #include <net/tc_act/tc_mirred.h> 27 #include <net/tc_wrapper.h> 28 29 #define MIRRED_DEFER_LIMIT 3 30 _Static_assert(MIRRED_DEFER_LIMIT <= 3, 31 "MIRRED_DEFER_LIMIT exceeds tc_depth bitfield width"); 32 33 static LIST_HEAD(mirred_list); 34 static DEFINE_SPINLOCK(mirred_list_lock); 35 36 static bool tcf_mirred_is_act_redirect(int action) 37 { 38 return action == TCA_EGRESS_REDIR || action == TCA_INGRESS_REDIR; 39 } 40 41 static bool tcf_mirred_act_wants_ingress(int action) 42 { 43 switch (action) { 44 case TCA_EGRESS_REDIR: 45 case TCA_EGRESS_MIRROR: 46 return false; 47 case TCA_INGRESS_REDIR: 48 case TCA_INGRESS_MIRROR: 49 return true; 50 default: 51 BUG(); 52 } 53 } 54 55 static bool tcf_mirred_can_reinsert(int action) 56 { 57 switch (action) { 58 case TC_ACT_SHOT: 59 case TC_ACT_STOLEN: 60 case TC_ACT_QUEUED: 61 case TC_ACT_TRAP: 62 return true; 63 } 64 return false; 65 } 66 67 static struct net_device *tcf_mirred_dev_dereference(struct tcf_mirred *m) 68 { 69 return rcu_dereference_protected(m->tcfm_dev, 70 lockdep_is_held(&m->tcf_lock)); 71 } 72 73 static void tcf_mirred_release(struct tc_action *a) 74 { 75 struct tcf_mirred *m = to_mirred(a); 76 struct net_device *dev; 77 78 spin_lock(&mirred_list_lock); 79 list_del(&m->tcfm_list); 80 spin_unlock(&mirred_list_lock); 81 82 /* last reference to action, no need to lock */ 83 dev = rcu_dereference_protected(m->tcfm_dev, 1); 84 netdev_put(dev, &m->tcfm_dev_tracker); 85 } 86 87 static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { 88 [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) }, 89 [TCA_MIRRED_BLOCKID] = NLA_POLICY_MIN(NLA_U32, 1), 90 }; 91 92 static struct tc_action_ops act_mirred_ops; 93 94 static void tcf_mirred_replace_dev(struct tcf_mirred *m, 95 struct net_device *ndev) 96 { 97 struct net_device *odev; 98 99 odev = rcu_replace_pointer(m->tcfm_dev, ndev, 100 lockdep_is_held(&m->tcf_lock)); 101 netdev_put(odev, &m->tcfm_dev_tracker); 102 } 103 104 static int tcf_mirred_init(struct net *net, struct nlattr *nla, 105 struct nlattr *est, struct tc_action **a, 106 struct tcf_proto *tp, 107 u32 flags, struct netlink_ext_ack *extack) 108 { 109 struct tc_action_net *tn = net_generic(net, act_mirred_ops.net_id); 110 bool bind = flags & TCA_ACT_FLAGS_BIND; 111 struct nlattr *tb[TCA_MIRRED_MAX + 1]; 112 struct tcf_chain *goto_ch = NULL; 113 bool mac_header_xmit = false; 114 struct tc_mirred *parm; 115 struct tcf_mirred *m; 116 bool exists = false; 117 int ret, err; 118 u32 index; 119 120 if (!nla) { 121 NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed"); 122 return -EINVAL; 123 } 124 ret = nla_parse_nested_deprecated(tb, TCA_MIRRED_MAX, nla, 125 mirred_policy, extack); 126 if (ret < 0) 127 return ret; 128 if (!tb[TCA_MIRRED_PARMS]) { 129 NL_SET_ERR_MSG_MOD(extack, "Missing required mirred parameters"); 130 return -EINVAL; 131 } 132 parm = nla_data(tb[TCA_MIRRED_PARMS]); 133 index = parm->index; 134 err = tcf_idr_check_alloc(tn, &index, a, bind); 135 if (err < 0) 136 return err; 137 exists = err; 138 if (exists && bind) 139 return ACT_P_BOUND; 140 141 if (tb[TCA_MIRRED_BLOCKID] && parm->ifindex) { 142 NL_SET_ERR_MSG_MOD(extack, 143 "Cannot specify Block ID and dev simultaneously"); 144 if (exists) 145 tcf_idr_release(*a, bind); 146 else 147 tcf_idr_cleanup(tn, index); 148 149 return -EINVAL; 150 } 151 152 switch (parm->eaction) { 153 case TCA_EGRESS_MIRROR: 154 case TCA_EGRESS_REDIR: 155 case TCA_INGRESS_REDIR: 156 case TCA_INGRESS_MIRROR: 157 break; 158 default: 159 if (exists) 160 tcf_idr_release(*a, bind); 161 else 162 tcf_idr_cleanup(tn, index); 163 NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option"); 164 return -EINVAL; 165 } 166 167 if (!exists) { 168 if (!parm->ifindex && !tb[TCA_MIRRED_BLOCKID]) { 169 tcf_idr_cleanup(tn, index); 170 NL_SET_ERR_MSG_MOD(extack, 171 "Must specify device or block"); 172 return -EINVAL; 173 } 174 ret = tcf_idr_create_from_flags(tn, index, est, a, 175 &act_mirred_ops, bind, flags); 176 if (ret) { 177 tcf_idr_cleanup(tn, index); 178 return ret; 179 } 180 ret = ACT_P_CREATED; 181 } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { 182 tcf_idr_release(*a, bind); 183 return -EEXIST; 184 } 185 186 m = to_mirred(*a); 187 if (ret == ACT_P_CREATED) 188 INIT_LIST_HEAD(&m->tcfm_list); 189 190 err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); 191 if (err < 0) 192 goto release_idr; 193 194 spin_lock_bh(&m->tcf_lock); 195 196 if (parm->ifindex) { 197 struct net_device *ndev; 198 199 ndev = dev_get_by_index(net, parm->ifindex); 200 if (!ndev) { 201 spin_unlock_bh(&m->tcf_lock); 202 err = -ENODEV; 203 goto put_chain; 204 } 205 mac_header_xmit = dev_is_mac_header_xmit(ndev); 206 tcf_mirred_replace_dev(m, ndev); 207 netdev_tracker_alloc(ndev, &m->tcfm_dev_tracker, GFP_ATOMIC); 208 m->tcfm_mac_header_xmit = mac_header_xmit; 209 m->tcfm_blockid = 0; 210 } else if (tb[TCA_MIRRED_BLOCKID]) { 211 tcf_mirred_replace_dev(m, NULL); 212 m->tcfm_mac_header_xmit = false; 213 m->tcfm_blockid = nla_get_u32(tb[TCA_MIRRED_BLOCKID]); 214 } 215 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); 216 m->tcfm_eaction = parm->eaction; 217 spin_unlock_bh(&m->tcf_lock); 218 if (goto_ch) 219 tcf_chain_put_by_act(goto_ch); 220 221 if (ret == ACT_P_CREATED) { 222 spin_lock(&mirred_list_lock); 223 list_add(&m->tcfm_list, &mirred_list); 224 spin_unlock(&mirred_list_lock); 225 } 226 227 return ret; 228 put_chain: 229 if (goto_ch) 230 tcf_chain_put_by_act(goto_ch); 231 release_idr: 232 tcf_idr_release(*a, bind); 233 return err; 234 } 235 236 static int 237 tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb) 238 { 239 int err; 240 241 if (!want_ingress) { 242 err = tcf_dev_queue_xmit(skb, dev_queue_xmit); 243 } else { 244 skb->tc_depth++; 245 if (!at_ingress) 246 err = netif_rx(skb); 247 else 248 err = netif_receive_skb(skb); 249 } 250 251 return err; 252 } 253 254 static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m, 255 struct net_device *dev, 256 const bool m_mac_header_xmit, int m_eaction, 257 int retval) 258 { 259 struct sk_buff *skb_to_send = skb; 260 bool want_ingress; 261 bool is_redirect; 262 bool expects_nh; 263 bool at_ingress; 264 bool dont_clone; 265 int mac_len; 266 bool at_nh; 267 int err; 268 269 is_redirect = tcf_mirred_is_act_redirect(m_eaction); 270 if (unlikely(!(dev->flags & IFF_UP)) || !netif_carrier_ok(dev)) { 271 net_notice_ratelimited("tc mirred to Houston: device %s is down\n", 272 dev->name); 273 goto err_cant_do; 274 } 275 276 want_ingress = tcf_mirred_act_wants_ingress(m_eaction); 277 278 at_ingress = skb_at_tc_ingress(skb); 279 if (dev == skb->dev && want_ingress == at_ingress) { 280 pr_notice_once("tc mirred: Loop (%s:%s --> %s:%s)\n", 281 netdev_name(skb->dev), 282 at_ingress ? "ingress" : "egress", 283 netdev_name(dev), 284 want_ingress ? "ingress" : "egress"); 285 goto err_cant_do; 286 } 287 288 /* we could easily avoid the clone only if called by ingress and clsact; 289 * since we can't easily detect the clsact caller, skip clone only for 290 * ingress - that covers the TC S/W datapath. 291 */ 292 dont_clone = skb_at_tc_ingress(skb) && is_redirect && 293 tcf_mirred_can_reinsert(retval); 294 if (!dont_clone) { 295 skb_to_send = skb_clone(skb, GFP_ATOMIC); 296 if (!skb_to_send) 297 goto err_cant_do; 298 } 299 300 /* All mirred/redirected skbs should clear previous ct info */ 301 nf_reset_ct(skb_to_send); 302 if (want_ingress && !at_ingress) /* drop dst for egress -> ingress */ 303 skb_dst_drop(skb_to_send); 304 305 expects_nh = want_ingress || !m_mac_header_xmit; 306 at_nh = skb->data == skb_network_header(skb); 307 if (at_nh != expects_nh) { 308 mac_len = at_ingress ? skb->mac_len : 309 skb_network_offset(skb); 310 if (expects_nh) { 311 /* target device/action expect data at nh */ 312 skb_pull_rcsum(skb_to_send, mac_len); 313 } else { 314 /* target device/action expect data at mac */ 315 skb_push_rcsum(skb_to_send, mac_len); 316 } 317 } 318 319 skb_to_send->skb_iif = skb->dev->ifindex; 320 skb_to_send->dev = dev; 321 322 if (is_redirect) { 323 if (skb == skb_to_send) 324 retval = TC_ACT_CONSUMED; 325 326 skb_set_redirected(skb_to_send, skb_to_send->tc_at_ingress); 327 328 err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send); 329 } else { 330 err = tcf_mirred_forward(at_ingress, want_ingress, skb_to_send); 331 } 332 if (err) 333 tcf_action_inc_overlimit_qstats(&m->common); 334 335 return retval; 336 337 err_cant_do: 338 if (is_redirect) 339 retval = TC_ACT_SHOT; 340 tcf_action_inc_overlimit_qstats(&m->common); 341 return retval; 342 } 343 344 static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m, 345 struct tcf_block *block, int m_eaction, 346 const u32 exception_ifindex, int retval) 347 { 348 struct net_device *dev_prev = NULL; 349 struct net_device *dev = NULL; 350 unsigned long index; 351 int mirred_eaction; 352 353 mirred_eaction = tcf_mirred_act_wants_ingress(m_eaction) ? 354 TCA_INGRESS_MIRROR : TCA_EGRESS_MIRROR; 355 356 xa_for_each(&block->ports, index, dev) { 357 if (index == exception_ifindex) 358 continue; 359 360 if (!dev_prev) 361 goto assign_prev; 362 363 tcf_mirred_to_dev(skb, m, dev_prev, 364 dev_is_mac_header_xmit(dev_prev), 365 mirred_eaction, retval); 366 assign_prev: 367 dev_prev = dev; 368 } 369 370 if (dev_prev) 371 return tcf_mirred_to_dev(skb, m, dev_prev, 372 dev_is_mac_header_xmit(dev_prev), 373 m_eaction, retval); 374 375 /* If the packet wasn't redirected, we have to register as a drop */ 376 return TC_ACT_SHOT; 377 } 378 379 static int tcf_blockcast_mirror(struct sk_buff *skb, struct tcf_mirred *m, 380 struct tcf_block *block, int m_eaction, 381 const u32 exception_ifindex, int retval) 382 { 383 struct net_device *dev = NULL; 384 unsigned long index; 385 386 xa_for_each(&block->ports, index, dev) { 387 if (index == exception_ifindex) 388 continue; 389 390 tcf_mirred_to_dev(skb, m, dev, 391 dev_is_mac_header_xmit(dev), 392 m_eaction, retval); 393 } 394 395 return retval; 396 } 397 398 static int tcf_blockcast(struct sk_buff *skb, struct tcf_mirred *m, 399 const u32 blockid, struct tcf_result *res, 400 int m_eaction, int retval) 401 { 402 const u32 exception_ifindex = skb->dev->ifindex; 403 struct tcf_block *block; 404 bool is_redirect; 405 406 is_redirect = tcf_mirred_is_act_redirect(m_eaction); 407 408 /* we are already under rcu protection, so can call block lookup 409 * directly. 410 */ 411 block = tcf_block_lookup(dev_net(skb->dev), blockid); 412 if (!block || xa_empty(&block->ports)) { 413 tcf_action_inc_overlimit_qstats(&m->common); 414 return is_redirect ? TC_ACT_SHOT : retval; 415 } 416 417 if (is_redirect) 418 return tcf_blockcast_redir(skb, m, block, m_eaction, 419 exception_ifindex, retval); 420 421 /* If it's not redirect, it is mirror */ 422 return tcf_blockcast_mirror(skb, m, block, m_eaction, exception_ifindex, 423 retval); 424 } 425 426 TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb, 427 const struct tc_action *a, 428 struct tcf_result *res) 429 { 430 struct tcf_mirred *m = to_mirred(a); 431 int retval = READ_ONCE(m->tcf_action); 432 bool m_mac_header_xmit, is_redirect; 433 struct netdev_xmit *xmit; 434 struct net_device *dev; 435 bool want_ingress; 436 int i, m_eaction; 437 u32 blockid; 438 439 #ifdef CONFIG_PREEMPT_RT 440 xmit = ¤t->net_xmit; 441 #else 442 xmit = this_cpu_ptr(&softnet_data.xmit); 443 #endif 444 if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT || 445 skb->tc_depth >= MIRRED_DEFER_LIMIT)) { 446 net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n", 447 netdev_name(skb->dev)); 448 return TC_ACT_SHOT; 449 } 450 451 tcf_lastuse_update(&m->tcf_tm); 452 tcf_action_update_bstats(&m->common, skb); 453 454 blockid = READ_ONCE(m->tcfm_blockid); 455 m_eaction = READ_ONCE(m->tcfm_eaction); 456 want_ingress = tcf_mirred_act_wants_ingress(m_eaction); 457 if (blockid) { 458 if (!want_ingress) 459 xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = NULL; 460 retval = tcf_blockcast(skb, m, blockid, res, m_eaction, retval); 461 if (!want_ingress) 462 xmit->sched_mirred_nest--; 463 return retval; 464 } 465 466 is_redirect = tcf_mirred_is_act_redirect(m_eaction); 467 468 dev = rcu_dereference_bh(m->tcfm_dev); 469 if (unlikely(!dev)) { 470 pr_notice_once("tc mirred: target device is gone\n"); 471 tcf_action_inc_overlimit_qstats(&m->common); 472 goto err_out; 473 } 474 475 if (!want_ingress) { 476 for (i = 0; i < xmit->sched_mirred_nest; i++) { 477 if (xmit->sched_mirred_dev[i] != dev) 478 continue; 479 pr_notice_once("tc mirred: loop on device %s\n", 480 netdev_name(dev)); 481 tcf_action_inc_overlimit_qstats(&m->common); 482 goto err_out; 483 } 484 xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev; 485 } 486 487 m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); 488 489 retval = tcf_mirred_to_dev(skb, m, dev, m_mac_header_xmit, m_eaction, 490 retval); 491 if (!want_ingress) 492 xmit->sched_mirred_nest--; 493 494 return retval; 495 496 err_out: 497 if (is_redirect) 498 retval = TC_ACT_SHOT; 499 return retval; 500 } 501 502 static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets, 503 u64 drops, u64 lastuse, bool hw) 504 { 505 struct tcf_mirred *m = to_mirred(a); 506 struct tcf_t *tm = &m->tcf_tm; 507 508 tcf_action_update_stats(a, bytes, packets, drops, hw); 509 tm->lastuse = max_t(u64, tm->lastuse, lastuse); 510 } 511 512 static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, 513 int ref) 514 { 515 unsigned char *b = skb_tail_pointer(skb); 516 struct tcf_mirred *m = to_mirred(a); 517 struct tc_mirred opt = { 518 .index = m->tcf_index, 519 .refcnt = refcount_read(&m->tcf_refcnt) - ref, 520 .bindcnt = atomic_read(&m->tcf_bindcnt) - bind, 521 }; 522 struct net_device *dev; 523 struct tcf_t t; 524 u32 blockid; 525 526 spin_lock_bh(&m->tcf_lock); 527 opt.action = m->tcf_action; 528 opt.eaction = m->tcfm_eaction; 529 dev = tcf_mirred_dev_dereference(m); 530 if (dev) 531 opt.ifindex = dev->ifindex; 532 533 if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt)) 534 goto nla_put_failure; 535 536 blockid = m->tcfm_blockid; 537 if (blockid && nla_put_u32(skb, TCA_MIRRED_BLOCKID, blockid)) 538 goto nla_put_failure; 539 540 tcf_tm_dump(&t, &m->tcf_tm); 541 if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD)) 542 goto nla_put_failure; 543 spin_unlock_bh(&m->tcf_lock); 544 545 return skb->len; 546 547 nla_put_failure: 548 spin_unlock_bh(&m->tcf_lock); 549 nlmsg_trim(skb, b); 550 return -1; 551 } 552 553 static int mirred_device_event(struct notifier_block *unused, 554 unsigned long event, void *ptr) 555 { 556 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 557 struct tcf_mirred *m; 558 559 ASSERT_RTNL(); 560 if (event == NETDEV_UNREGISTER) { 561 spin_lock(&mirred_list_lock); 562 list_for_each_entry(m, &mirred_list, tcfm_list) { 563 spin_lock_bh(&m->tcf_lock); 564 if (tcf_mirred_dev_dereference(m) == dev) { 565 netdev_put(dev, &m->tcfm_dev_tracker); 566 /* Note : no rcu grace period necessary, as 567 * net_device are already rcu protected. 568 */ 569 RCU_INIT_POINTER(m->tcfm_dev, NULL); 570 } 571 spin_unlock_bh(&m->tcf_lock); 572 } 573 spin_unlock(&mirred_list_lock); 574 } 575 576 return NOTIFY_DONE; 577 } 578 579 static struct notifier_block mirred_device_notifier = { 580 .notifier_call = mirred_device_event, 581 }; 582 583 static void tcf_mirred_dev_put(void *priv) 584 { 585 struct net_device *dev = priv; 586 587 dev_put(dev); 588 } 589 590 static struct net_device * 591 tcf_mirred_get_dev(const struct tc_action *a, 592 tc_action_priv_destructor *destructor) 593 { 594 struct tcf_mirred *m = to_mirred(a); 595 struct net_device *dev; 596 597 rcu_read_lock(); 598 dev = rcu_dereference(m->tcfm_dev); 599 if (dev) { 600 dev_hold(dev); 601 *destructor = tcf_mirred_dev_put; 602 } 603 rcu_read_unlock(); 604 605 return dev; 606 } 607 608 static size_t tcf_mirred_get_fill_size(const struct tc_action *act) 609 { 610 return nla_total_size(sizeof(struct tc_mirred)); 611 } 612 613 static void tcf_offload_mirred_get_dev(struct flow_action_entry *entry, 614 const struct tc_action *act) 615 { 616 entry->dev = act->ops->get_dev(act, &entry->destructor); 617 if (!entry->dev) 618 return; 619 entry->destructor_priv = entry->dev; 620 } 621 622 static int tcf_mirred_offload_act_setup(struct tc_action *act, void *entry_data, 623 u32 *index_inc, bool bind, 624 struct netlink_ext_ack *extack) 625 { 626 if (bind) { 627 struct flow_action_entry *entry = entry_data; 628 629 if (is_tcf_mirred_egress_redirect(act)) { 630 entry->id = FLOW_ACTION_REDIRECT; 631 tcf_offload_mirred_get_dev(entry, act); 632 } else if (is_tcf_mirred_egress_mirror(act)) { 633 entry->id = FLOW_ACTION_MIRRED; 634 tcf_offload_mirred_get_dev(entry, act); 635 } else if (is_tcf_mirred_ingress_redirect(act)) { 636 entry->id = FLOW_ACTION_REDIRECT_INGRESS; 637 tcf_offload_mirred_get_dev(entry, act); 638 } else if (is_tcf_mirred_ingress_mirror(act)) { 639 entry->id = FLOW_ACTION_MIRRED_INGRESS; 640 tcf_offload_mirred_get_dev(entry, act); 641 } else { 642 NL_SET_ERR_MSG_MOD(extack, "Unsupported mirred offload"); 643 return -EOPNOTSUPP; 644 } 645 *index_inc = 1; 646 } else { 647 struct flow_offload_action *fl_action = entry_data; 648 649 if (is_tcf_mirred_egress_redirect(act)) 650 fl_action->id = FLOW_ACTION_REDIRECT; 651 else if (is_tcf_mirred_egress_mirror(act)) 652 fl_action->id = FLOW_ACTION_MIRRED; 653 else if (is_tcf_mirred_ingress_redirect(act)) 654 fl_action->id = FLOW_ACTION_REDIRECT_INGRESS; 655 else if (is_tcf_mirred_ingress_mirror(act)) 656 fl_action->id = FLOW_ACTION_MIRRED_INGRESS; 657 else 658 return -EOPNOTSUPP; 659 } 660 661 return 0; 662 } 663 664 static struct tc_action_ops act_mirred_ops = { 665 .kind = "mirred", 666 .id = TCA_ID_MIRRED, 667 .owner = THIS_MODULE, 668 .act = tcf_mirred_act, 669 .stats_update = tcf_stats_update, 670 .dump = tcf_mirred_dump, 671 .cleanup = tcf_mirred_release, 672 .init = tcf_mirred_init, 673 .get_fill_size = tcf_mirred_get_fill_size, 674 .offload_act_setup = tcf_mirred_offload_act_setup, 675 .size = sizeof(struct tcf_mirred), 676 .get_dev = tcf_mirred_get_dev, 677 }; 678 MODULE_ALIAS_NET_ACT("mirred"); 679 680 static __net_init int mirred_init_net(struct net *net) 681 { 682 struct tc_action_net *tn = net_generic(net, act_mirred_ops.net_id); 683 684 return tc_action_net_init(net, tn, &act_mirred_ops); 685 } 686 687 static void __net_exit mirred_exit_net(struct list_head *net_list) 688 { 689 tc_action_net_exit(net_list, act_mirred_ops.net_id); 690 } 691 692 static struct pernet_operations mirred_net_ops = { 693 .init = mirred_init_net, 694 .exit_batch = mirred_exit_net, 695 .id = &act_mirred_ops.net_id, 696 .size = sizeof(struct tc_action_net), 697 }; 698 699 MODULE_AUTHOR("Jamal Hadi Salim(2002)"); 700 MODULE_DESCRIPTION("Device Mirror/redirect actions"); 701 MODULE_LICENSE("GPL"); 702 703 static int __init mirred_init_module(void) 704 { 705 int err = register_netdevice_notifier(&mirred_device_notifier); 706 if (err) 707 return err; 708 709 pr_info("Mirror/redirect action on\n"); 710 err = tcf_register_action(&act_mirred_ops, &mirred_net_ops); 711 if (err) 712 unregister_netdevice_notifier(&mirred_device_notifier); 713 714 return err; 715 } 716 717 static void __exit mirred_cleanup_module(void) 718 { 719 tcf_unregister_action(&act_mirred_ops, &mirred_net_ops); 720 unregister_netdevice_notifier(&mirred_device_notifier); 721 } 722 723 module_init(mirred_init_module); 724 module_exit(mirred_cleanup_module); 725