netfilter_netdev.h (4057B)
1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef _NETFILTER_NETDEV_H_ 3#define _NETFILTER_NETDEV_H_ 4 5#include <linux/netfilter.h> 6#include <linux/netdevice.h> 7 8#ifdef CONFIG_NETFILTER_INGRESS 9static inline bool nf_hook_ingress_active(const struct sk_buff *skb) 10{ 11#ifdef CONFIG_JUMP_LABEL 12 if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_INGRESS])) 13 return false; 14#endif 15 return rcu_access_pointer(skb->dev->nf_hooks_ingress); 16} 17 18/* caller must hold rcu_read_lock */ 19static inline int nf_hook_ingress(struct sk_buff *skb) 20{ 21 struct nf_hook_entries *e = rcu_dereference(skb->dev->nf_hooks_ingress); 22 struct nf_hook_state state; 23 int ret; 24 25 /* Must recheck the ingress hook head, in the event it became NULL 26 * after the check in nf_hook_ingress_active evaluated to true. 27 */ 28 if (unlikely(!e)) 29 return 0; 30 31 nf_hook_state_init(&state, NF_NETDEV_INGRESS, 32 NFPROTO_NETDEV, skb->dev, NULL, NULL, 33 dev_net(skb->dev), NULL); 34 ret = nf_hook_slow(skb, &state, e, 0); 35 if (ret == 0) 36 return -1; 37 38 return ret; 39} 40 41#else /* CONFIG_NETFILTER_INGRESS */ 42static inline int nf_hook_ingress_active(struct sk_buff *skb) 43{ 44 return 0; 45} 46 47static inline int nf_hook_ingress(struct sk_buff *skb) 48{ 49 return 0; 50} 51#endif /* CONFIG_NETFILTER_INGRESS */ 52 53#ifdef CONFIG_NETFILTER_EGRESS 54static inline bool nf_hook_egress_active(void) 55{ 56#ifdef CONFIG_JUMP_LABEL 57 if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_EGRESS])) 58 return false; 59#endif 60 return true; 61} 62 63/** 64 * nf_hook_egress - classify packets before transmission 65 * @skb: packet to be classified 66 * @rc: result code which shall be returned by __dev_queue_xmit() on failure 67 * @dev: netdev whose egress hooks shall be applied to @skb 68 * 69 * Returns @skb on success or %NULL if the packet was consumed or filtered. 70 * Caller must hold rcu_read_lock. 71 * 72 * On ingress, packets are classified first by tc, then by netfilter. 73 * On egress, the order is reversed for symmetry. Conceptually, tc and 74 * netfilter can be thought of as layers, with netfilter layered above tc: 75 * When tc redirects a packet to another interface, netfilter is not applied 76 * because the packet is on the tc layer. 77 * 78 * The nf_skip_egress flag controls whether netfilter is applied on egress. 79 * It is updated by __netif_receive_skb_core() and __dev_queue_xmit() when the 80 * packet passes through tc and netfilter. Because __dev_queue_xmit() may be 81 * called recursively by tunnel drivers such as vxlan, the flag is reverted to 82 * false after sch_handle_egress(). This ensures that netfilter is applied 83 * both on the overlay and underlying network. 84 */ 85static inline struct sk_buff *nf_hook_egress(struct sk_buff *skb, int *rc, 86 struct net_device *dev) 87{ 88 struct nf_hook_entries *e; 89 struct nf_hook_state state; 90 int ret; 91 92#ifdef CONFIG_NETFILTER_SKIP_EGRESS 93 if (skb->nf_skip_egress) 94 return skb; 95#endif 96 97 e = rcu_dereference_check(dev->nf_hooks_egress, rcu_read_lock_bh_held()); 98 if (!e) 99 return skb; 100 101 nf_hook_state_init(&state, NF_NETDEV_EGRESS, 102 NFPROTO_NETDEV, NULL, dev, NULL, 103 dev_net(dev), NULL); 104 105 /* nf assumes rcu_read_lock, not just read_lock_bh */ 106 rcu_read_lock(); 107 ret = nf_hook_slow(skb, &state, e, 0); 108 rcu_read_unlock(); 109 110 if (ret == 1) { 111 return skb; 112 } else if (ret < 0) { 113 *rc = NET_XMIT_DROP; 114 return NULL; 115 } else { /* ret == 0 */ 116 *rc = NET_XMIT_SUCCESS; 117 return NULL; 118 } 119} 120#else /* CONFIG_NETFILTER_EGRESS */ 121static inline bool nf_hook_egress_active(void) 122{ 123 return false; 124} 125 126static inline struct sk_buff *nf_hook_egress(struct sk_buff *skb, int *rc, 127 struct net_device *dev) 128{ 129 return skb; 130} 131#endif /* CONFIG_NETFILTER_EGRESS */ 132 133static inline void nf_skip_egress(struct sk_buff *skb, bool skip) 134{ 135#ifdef CONFIG_NETFILTER_SKIP_EGRESS 136 skb->nf_skip_egress = skip; 137#endif 138} 139 140static inline void nf_hook_netdev_init(struct net_device *dev) 141{ 142#ifdef CONFIG_NETFILTER_INGRESS 143 RCU_INIT_POINTER(dev->nf_hooks_ingress, NULL); 144#endif 145#ifdef CONFIG_NETFILTER_EGRESS 146 RCU_INIT_POINTER(dev->nf_hooks_egress, NULL); 147#endif 148} 149 150#endif /* _NETFILTER_NETDEV_H_ */