File Index
Files and directories
Sign in
FILE

nf_dup_netdev.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nf_dup_netdev.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
  4 */
  5
  6#include <linux/kernel.h>
  7#include <linux/init.h>
  8#include <linux/module.h>
  9#include <linux/netlink.h>
 10#include <linux/netfilter.h>
 11#include <linux/netfilter/nf_tables.h>
 12#include <net/netfilter/nf_tables.h>
 13#include <net/netfilter/nf_tables_offload.h>
 14#include <net/netfilter/nf_dup_netdev.h>
 15
 16#define NF_RECURSION_LIMIT	2
 17
 18#ifndef CONFIG_PREEMPT_RT
 19static u8 *nf_get_nf_dup_skb_recursion(void)
 20{
 21	return this_cpu_ptr(&softnet_data.xmit.nf_dup_skb_recursion);
 22}
 23#else
 24
 25static u8 *nf_get_nf_dup_skb_recursion(void)
 26{
 27	return &current->net_xmit.nf_dup_skb_recursion;
 28}
 29
 30#endif
 31
 32static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
 33				enum nf_dev_hooks hook)
 34{
 35	u8 *nf_dup_skb_recursion = nf_get_nf_dup_skb_recursion();
 36
 37	if (*nf_dup_skb_recursion > NF_RECURSION_LIMIT)
 38		goto err;
 39
 40	if (hook == NF_NETDEV_INGRESS && skb_mac_header_was_set(skb)) {
 41		if (skb_cow_head(skb, skb->mac_len))
 42			goto err;
 43
 44		skb_push(skb, skb->mac_len);
 45	}
 46
 47	skb->dev = dev;
 48	skb_clear_tstamp(skb);
 49	(*nf_dup_skb_recursion)++;
 50	dev_queue_xmit(skb);
 51	(*nf_dup_skb_recursion)--;
 52	return;
 53err:
 54	kfree_skb(skb);
 55}
 56
 57void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif)
 58{
 59	struct net_device *dev;
 60
 61	dev = dev_get_by_index_rcu(nft_net(pkt), oif);
 62	if (!dev) {
 63		kfree_skb(pkt->skb);
 64		return;
 65	}
 66
 67	nf_do_netdev_egress(pkt->skb, dev, nft_hook(pkt));
 68}
 69EXPORT_SYMBOL_GPL(nf_fwd_netdev_egress);
 70
 71void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif)
 72{
 73	struct net_device *dev;
 74	struct sk_buff *skb;
 75
 76	dev = dev_get_by_index_rcu(nft_net(pkt), oif);
 77	if (dev == NULL)
 78		return;
 79
 80	skb = skb_clone(pkt->skb, GFP_ATOMIC);
 81	if (skb)
 82		nf_do_netdev_egress(skb, dev, nft_hook(pkt));
 83}
 84EXPORT_SYMBOL_GPL(nf_dup_netdev_egress);
 85
 86int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx,
 87			       struct nft_flow_rule *flow,
 88			       enum flow_action_id id, int oif)
 89{
 90	struct flow_action_entry *entry;
 91	struct net_device *dev;
 92
 93	/* nft_flow_rule_destroy() releases the reference on this device. */
 94	dev = dev_get_by_index(ctx->net, oif);
 95	if (!dev)
 96		return -EOPNOTSUPP;
 97
 98	entry = &flow->rule->action.entries[ctx->num_actions++];
 99	entry->id = id;
100	entry->dev = dev;
101
102	return 0;
103}
104EXPORT_SYMBOL_GPL(nft_fwd_dup_netdev_offload);
105
106MODULE_LICENSE("GPL");
107MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
108MODULE_DESCRIPTION("Netfilter packet duplication support");
~/ Read-only file preview.