act_api.h 6.6 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 10

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

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

struct tc_action_ops;

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

28 29 30 31 32 33 34 35
	u32				tcfa_index;
	int				tcfa_refcnt;
	int				tcfa_bindcnt;
	u32				tcfa_capab;
	int				tcfa_action;
	struct tcf_t			tcfa_tm;
	struct gnet_stats_basic_packed	tcfa_bstats;
	struct gnet_stats_queue		tcfa_qstats;
36
	struct net_rate_estimator __rcu *tcfa_rate_est;
37
	spinlock_t			tcfa_lock;
38 39
	struct gnet_stats_basic_cpu __percpu *cpu_bstats;
	struct gnet_stats_queue __percpu *cpu_qstats;
40
	struct tc_cookie	__rcu *act_cookie;
41
	struct tcf_chain	*goto_chain;
42
};
43 44 45 46 47 48 49 50 51 52
#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
53

54 55 56 57 58 59 60 61 62
/* 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;
63 64
	if (unlikely(!tm->firstuse))
		tm->firstuse = now;
65 66
}

67 68 69 70 71 72 73 74
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);
}

75 76 77 78 79
#ifdef CONFIG_NET_CLS_ACT

#define ACT_P_CREATED 1
#define ACT_P_DELETED 1

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

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

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

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

124 125
void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
			 struct tcf_idrinfo *idrinfo);
126

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

132
	rtnl_lock();
133 134 135 136 137 138
	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);
	}
139
	rtnl_unlock();
140 141 142 143
}

int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
144 145
		       const struct tc_action_ops *ops,
		       struct netlink_ext_ack *extack);
146 147
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,
148
		    int bind);
149 150 151 152
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);
153

154
int __tcf_idr_release(struct tc_action *a, bool bind, bool strict);
155

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

161
int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
162 163
int tcf_unregister_action(struct tc_action_ops *a,
			  struct pernet_operations *ops);
164
int tcf_action_destroy(struct list_head *actions, int bind);
165 166
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
		    int nr_actions, struct tcf_result *res);
167 168
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
		    struct nlattr *est, char *name, int ovr, int bind,
169 170
		    struct list_head *actions, size_t *attr_size,
		    struct netlink_ext_ack *extack);
171 172
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
				    struct nlattr *nla, struct nlattr *est,
173 174
				    char *name, int ovr, int bind,
				    struct netlink_ext_ack *extack);
175
int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
176 177 178
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);
179

180
#endif /* CONFIG_NET_CLS_ACT */
181

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

	a->ops->stats_update(a, bytes, packets, lastuse);
190
#endif
191 192
}

193 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
#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 已提交
224
#endif