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 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	*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
	struct net_device *(*get_dev)(const struct tc_action *a);
101 102 103
};

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

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

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

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

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

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

int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
		       struct netlink_callback *cb, int type,
143 144
		       const struct tc_action_ops *ops,
		       struct netlink_ext_ack *extack);
145 146
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,
147
		    int bind);
148 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_cleanup(struct tc_action *a, struct nlattr *est);
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 224 225 226
typedef int tc_setup_cb_t(enum tc_setup_type type,
			  void *type_data, void *cb_priv);

#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