act_api.h 6.7 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
L
Linus Torvalds 已提交
2 3 4 5
#ifndef __NET_ACT_API_H
#define __NET_ACT_API_H

/*
6 7
 * Public action API for classifiers/qdiscs
*/
L
Linus Torvalds 已提交
8

9
#include <linux/refcount.h>
L
Linus Torvalds 已提交
10 11
#include <net/sch_generic.h>
#include <net/pkt_sched.h>
12 13
#include <net/net_namespace.h>
#include <net/netns/generic.h>
L
Linus Torvalds 已提交
14

15 16 17
struct tcf_idrinfo {
	spinlock_t	lock;
	struct idr	action_idr;
18 19 20 21 22 23
};

struct tc_action_ops;

struct tc_action {
	const struct tc_action_ops	*ops;
24 25 26
	__u32				type; /* for backward compat(TCA_OLD_COMPAT) */
	__u32				order;
	struct list_head		list;
27
	struct tcf_idrinfo		*idrinfo;
28

29
	u32				tcfa_index;
30 31
	refcount_t			tcfa_refcnt;
	atomic_t			tcfa_bindcnt;
32 33 34 35 36
	u32				tcfa_capab;
	int				tcfa_action;
	struct tcf_t			tcfa_tm;
	struct gnet_stats_basic_packed	tcfa_bstats;
	struct gnet_stats_queue		tcfa_qstats;
37
	struct net_rate_estimator __rcu *tcfa_rate_est;
38
	spinlock_t			tcfa_lock;
39 40
	struct gnet_stats_basic_cpu __percpu *cpu_bstats;
	struct gnet_stats_queue __percpu *cpu_qstats;
41
	struct tc_cookie	__rcu *act_cookie;
42
	struct tcf_chain	*goto_chain;
43
};
44 45 46 47 48 49 50 51 52 53
#define tcf_index	common.tcfa_index
#define tcf_refcnt	common.tcfa_refcnt
#define tcf_bindcnt	common.tcfa_bindcnt
#define tcf_capab	common.tcfa_capab
#define tcf_action	common.tcfa_action
#define tcf_tm		common.tcfa_tm
#define tcf_bstats	common.tcfa_bstats
#define tcf_qstats	common.tcfa_qstats
#define tcf_rate_est	common.tcfa_rate_est
#define tcf_lock	common.tcfa_lock
54

55 56 57 58 59 60 61 62 63
/* Update lastuse only if needed, to avoid dirtying a cache line.
 * We use a temp variable to avoid fetching jiffies twice.
 */
static inline void tcf_lastuse_update(struct tcf_t *tm)
{
	unsigned long now = jiffies;

	if (tm->lastuse != now)
		tm->lastuse = now;
64 65
	if (unlikely(!tm->firstuse))
		tm->firstuse = now;
66 67
}

68 69 70 71 72 73 74 75
static inline void tcf_tm_dump(struct tcf_t *dtm, const struct tcf_t *stm)
{
	dtm->install = jiffies_to_clock_t(jiffies - stm->install);
	dtm->lastuse = jiffies_to_clock_t(jiffies - stm->lastuse);
	dtm->firstuse = jiffies_to_clock_t(jiffies - stm->firstuse);
	dtm->expires = jiffies_to_clock_t(stm->expires);
}

76 77 78 79 80
#ifdef CONFIG_NET_CLS_ACT

#define ACT_P_CREATED 1
#define ACT_P_DELETED 1

81
struct tc_action_ops {
82
	struct list_head head;
L
Linus Torvalds 已提交
83 84
	char    kind[IFNAMSIZ];
	__u32   type; /* TBD to match kind */
85
	size_t	size;
L
Linus Torvalds 已提交
86
	struct module		*owner;
87 88
	int     (*act)(struct sk_buff *, const struct tc_action *,
		       struct tcf_result *);
89
	int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
90
	void	(*cleanup)(struct tc_action *);
91 92
	int     (*lookup)(struct net *net, struct tc_action **a, u32 index,
			  struct netlink_ext_ack *extack);
93
	int     (*init)(struct net *net, struct nlattr *nla,
94
			struct nlattr *est, struct tc_action **act, int ovr,
95 96
			int bind, bool rtnl_held,
			struct netlink_ext_ack *extack);
97
	int     (*walk)(struct net *, struct sk_buff *,
98
			struct netlink_callback *, int,
99 100
			const struct tc_action_ops *,
			struct netlink_ext_ack *);
101
	void	(*stats_update)(struct tc_action *, u64, u32, u64);
102
	size_t  (*get_fill_size)(const struct tc_action *act);
103
	struct net_device *(*get_dev)(const struct tc_action *a);
104 105 106
};

struct tc_action_net {
107
	struct tcf_idrinfo *idrinfo;
108
	const struct tc_action_ops *ops;
L
Linus Torvalds 已提交
109 110
};

111
static inline
112
int tc_action_net_init(struct tc_action_net *tn,
113
		       const struct tc_action_ops *ops)
114 115 116
{
	int err = 0;

117 118
	tn->idrinfo = kmalloc(sizeof(*tn->idrinfo), GFP_KERNEL);
	if (!tn->idrinfo)
119 120
		return -ENOMEM;
	tn->ops = ops;
121 122
	spin_lock_init(&tn->idrinfo->lock);
	idr_init(&tn->idrinfo->action_idr);
123 124 125
	return err;
}

126 127
void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
			 struct tcf_idrinfo *idrinfo);
128

129 130
static inline void tc_action_net_exit(struct list_head *net_list,
				      unsigned int id)
131
{
132 133
	struct net *net;

134
	rtnl_lock();
135 136 137 138 139 140
	list_for_each_entry(net, net_list, exit_list) {
		struct tc_action_net *tn = net_generic(net, id);

		tcf_idrinfo_destroy(tn->ops, tn->idrinfo);
		kfree(tn->idrinfo);
	}
141
	rtnl_unlock();
142 143 144 145
}

int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
146 147
		       const struct tc_action_ops *ops,
		       struct netlink_ext_ack *extack);
148 149
int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
150
		    int bind);
151 152 153 154
int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
		   struct tc_action **a, const struct tc_action_ops *ops,
		   int bind, bool cpustats);
void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);
155

156
int __tcf_idr_release(struct tc_action *a, bool bind, bool strict);
157

158
static inline int tcf_idr_release(struct tc_action *a, bool bind)
159
{
160
	return __tcf_idr_release(a, bind, false);
161 162
}

163
int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
164 165
int tcf_unregister_action(struct tc_action_ops *a,
			  struct pernet_operations *ops);
166
int tcf_action_destroy(struct list_head *actions, int bind);
167 168
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
		    int nr_actions, struct tcf_result *res);
169 170
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
		    struct nlattr *est, char *name, int ovr, int bind,
171
		    struct list_head *actions, size_t *attr_size,
172
		    bool rtnl_held, struct netlink_ext_ack *extack);
173 174
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
				    struct nlattr *nla, struct nlattr *est,
175
				    char *name, int ovr, int bind,
176
				    bool rtnl_held,
177
				    struct netlink_ext_ack *extack);
178
int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
179 180 181
int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
182

183
#endif /* CONFIG_NET_CLS_ACT */
184

185 186 187
static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes,
					   u64 packets, u64 lastuse)
{
188
#ifdef CONFIG_NET_CLS_ACT
189 190 191 192
	if (!a->ops->stats_update)
		return;

	a->ops->stats_update(a, bytes, packets, lastuse);
193
#endif
194 195
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
#ifdef CONFIG_NET_CLS_ACT
int tc_setup_cb_egdev_register(const struct net_device *dev,
			       tc_setup_cb_t *cb, void *cb_priv);
void tc_setup_cb_egdev_unregister(const struct net_device *dev,
				  tc_setup_cb_t *cb, void *cb_priv);
int tc_setup_cb_egdev_call(const struct net_device *dev,
			   enum tc_setup_type type, void *type_data,
			   bool err_stop);
#else
static inline
int tc_setup_cb_egdev_register(const struct net_device *dev,
			       tc_setup_cb_t *cb, void *cb_priv)
{
	return 0;
}

static inline
void tc_setup_cb_egdev_unregister(const struct net_device *dev,
				  tc_setup_cb_t *cb, void *cb_priv)
{
}

static inline
int tc_setup_cb_egdev_call(const struct net_device *dev,
			   enum tc_setup_type type, void *type_data,
			   bool err_stop)
{
	return 0;
}
#endif

L
Linus Torvalds 已提交
227
#endif