162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __NET_LWTUNNEL_H
362306a36Sopenharmony_ci#define __NET_LWTUNNEL_H 1
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/lwtunnel.h>
662306a36Sopenharmony_ci#include <linux/netdevice.h>
762306a36Sopenharmony_ci#include <linux/skbuff.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci#include <net/route.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define LWTUNNEL_HASH_BITS   7
1262306a36Sopenharmony_ci#define LWTUNNEL_HASH_SIZE   (1 << LWTUNNEL_HASH_BITS)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* lw tunnel state flags */
1562306a36Sopenharmony_ci#define LWTUNNEL_STATE_OUTPUT_REDIRECT	BIT(0)
1662306a36Sopenharmony_ci#define LWTUNNEL_STATE_INPUT_REDIRECT	BIT(1)
1762306a36Sopenharmony_ci#define LWTUNNEL_STATE_XMIT_REDIRECT	BIT(2)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* LWTUNNEL_XMIT_CONTINUE should be distinguishable from dst_output return
2062306a36Sopenharmony_ci * values (NET_XMIT_xxx and NETDEV_TX_xxx in linux/netdevice.h) for safety.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cienum {
2362306a36Sopenharmony_ci	LWTUNNEL_XMIT_DONE,
2462306a36Sopenharmony_ci	LWTUNNEL_XMIT_CONTINUE = 0x100,
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct lwtunnel_state {
2962306a36Sopenharmony_ci	__u16		type;
3062306a36Sopenharmony_ci	__u16		flags;
3162306a36Sopenharmony_ci	__u16		headroom;
3262306a36Sopenharmony_ci	atomic_t	refcnt;
3362306a36Sopenharmony_ci	int		(*orig_output)(struct net *net, struct sock *sk, struct sk_buff *skb);
3462306a36Sopenharmony_ci	int		(*orig_input)(struct sk_buff *);
3562306a36Sopenharmony_ci	struct		rcu_head rcu;
3662306a36Sopenharmony_ci	__u8            data[];
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct lwtunnel_encap_ops {
4062306a36Sopenharmony_ci	int (*build_state)(struct net *net, struct nlattr *encap,
4162306a36Sopenharmony_ci			   unsigned int family, const void *cfg,
4262306a36Sopenharmony_ci			   struct lwtunnel_state **ts,
4362306a36Sopenharmony_ci			   struct netlink_ext_ack *extack);
4462306a36Sopenharmony_ci	void (*destroy_state)(struct lwtunnel_state *lws);
4562306a36Sopenharmony_ci	int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
4662306a36Sopenharmony_ci	int (*input)(struct sk_buff *skb);
4762306a36Sopenharmony_ci	int (*fill_encap)(struct sk_buff *skb,
4862306a36Sopenharmony_ci			  struct lwtunnel_state *lwtstate);
4962306a36Sopenharmony_ci	int (*get_encap_size)(struct lwtunnel_state *lwtstate);
5062306a36Sopenharmony_ci	int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b);
5162306a36Sopenharmony_ci	int (*xmit)(struct sk_buff *skb);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	struct module *owner;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#ifdef CONFIG_LWTUNNEL
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(nf_hooks_lwtunnel_enabled);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_civoid lwtstate_free(struct lwtunnel_state *lws);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic inline struct lwtunnel_state *
6362306a36Sopenharmony_cilwtstate_get(struct lwtunnel_state *lws)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	if (lws)
6662306a36Sopenharmony_ci		atomic_inc(&lws->refcnt);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return lws;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic inline void lwtstate_put(struct lwtunnel_state *lws)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	if (!lws)
7462306a36Sopenharmony_ci		return;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (atomic_dec_and_test(&lws->refcnt))
7762306a36Sopenharmony_ci		lwtstate_free(lws);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_OUTPUT_REDIRECT))
8362306a36Sopenharmony_ci		return true;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return false;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_INPUT_REDIRECT))
9162306a36Sopenharmony_ci		return true;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return false;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_XMIT_REDIRECT))
9962306a36Sopenharmony_ci		return true;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return false;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate,
10562306a36Sopenharmony_ci					     unsigned int mtu)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	if ((lwtunnel_xmit_redirect(lwtstate) ||
10862306a36Sopenharmony_ci	     lwtunnel_output_redirect(lwtstate)) && lwtstate->headroom < mtu)
10962306a36Sopenharmony_ci		return lwtstate->headroom;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciint lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
11562306a36Sopenharmony_ci			   unsigned int num);
11662306a36Sopenharmony_ciint lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
11762306a36Sopenharmony_ci			   unsigned int num);
11862306a36Sopenharmony_ciint lwtunnel_valid_encap_type(u16 encap_type,
11962306a36Sopenharmony_ci			      struct netlink_ext_ack *extack);
12062306a36Sopenharmony_ciint lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
12162306a36Sopenharmony_ci				   struct netlink_ext_ack *extack);
12262306a36Sopenharmony_ciint lwtunnel_build_state(struct net *net, u16 encap_type,
12362306a36Sopenharmony_ci			 struct nlattr *encap,
12462306a36Sopenharmony_ci			 unsigned int family, const void *cfg,
12562306a36Sopenharmony_ci			 struct lwtunnel_state **lws,
12662306a36Sopenharmony_ci			 struct netlink_ext_ack *extack);
12762306a36Sopenharmony_ciint lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate,
12862306a36Sopenharmony_ci			int encap_attr, int encap_type_attr);
12962306a36Sopenharmony_ciint lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
13062306a36Sopenharmony_cistruct lwtunnel_state *lwtunnel_state_alloc(int hdr_len);
13162306a36Sopenharmony_ciint lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b);
13262306a36Sopenharmony_ciint lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb);
13362306a36Sopenharmony_ciint lwtunnel_input(struct sk_buff *skb);
13462306a36Sopenharmony_ciint lwtunnel_xmit(struct sk_buff *skb);
13562306a36Sopenharmony_ciint bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len,
13662306a36Sopenharmony_ci			  bool ingress);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic inline void lwtunnel_set_redirect(struct dst_entry *dst)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	if (lwtunnel_output_redirect(dst->lwtstate)) {
14162306a36Sopenharmony_ci		dst->lwtstate->orig_output = dst->output;
14262306a36Sopenharmony_ci		dst->output = lwtunnel_output;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	if (lwtunnel_input_redirect(dst->lwtstate)) {
14562306a36Sopenharmony_ci		dst->lwtstate->orig_input = dst->input;
14662306a36Sopenharmony_ci		dst->input = lwtunnel_input;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci#else
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic inline void lwtstate_free(struct lwtunnel_state *lws)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic inline struct lwtunnel_state *
15662306a36Sopenharmony_cilwtstate_get(struct lwtunnel_state *lws)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return lws;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic inline void lwtstate_put(struct lwtunnel_state *lws)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	return false;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	return false;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	return false;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic inline void lwtunnel_set_redirect(struct dst_entry *dst)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate,
18562306a36Sopenharmony_ci					     unsigned int mtu)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	return 0;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
19162306a36Sopenharmony_ci					 unsigned int num)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	return -EOPNOTSUPP;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
19862306a36Sopenharmony_ci					 unsigned int num)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	return -EOPNOTSUPP;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic inline int lwtunnel_valid_encap_type(u16 encap_type,
20462306a36Sopenharmony_ci					    struct netlink_ext_ack *extack)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	NL_SET_ERR_MSG(extack, "CONFIG_LWTUNNEL is not enabled in this kernel");
20762306a36Sopenharmony_ci	return -EOPNOTSUPP;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_cistatic inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
21062306a36Sopenharmony_ci						 struct netlink_ext_ack *extack)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	/* return 0 since we are not walking attr looking for
21362306a36Sopenharmony_ci	 * RTA_ENCAP_TYPE attribute on nexthops.
21462306a36Sopenharmony_ci	 */
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic inline int lwtunnel_build_state(struct net *net, u16 encap_type,
21962306a36Sopenharmony_ci				       struct nlattr *encap,
22062306a36Sopenharmony_ci				       unsigned int family, const void *cfg,
22162306a36Sopenharmony_ci				       struct lwtunnel_state **lws,
22262306a36Sopenharmony_ci				       struct netlink_ext_ack *extack)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	return -EOPNOTSUPP;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic inline int lwtunnel_fill_encap(struct sk_buff *skb,
22862306a36Sopenharmony_ci				      struct lwtunnel_state *lwtstate,
22962306a36Sopenharmony_ci				      int encap_attr, int encap_type_attr)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	return NULL;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline int lwtunnel_cmp_encap(struct lwtunnel_state *a,
24562306a36Sopenharmony_ci				     struct lwtunnel_state *b)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic inline int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	return -EOPNOTSUPP;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic inline int lwtunnel_input(struct sk_buff *skb)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	return -EOPNOTSUPP;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic inline int lwtunnel_xmit(struct sk_buff *skb)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	return -EOPNOTSUPP;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#endif /* CONFIG_LWTUNNEL */
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci#define MODULE_ALIAS_RTNL_LWT(encap_type) MODULE_ALIAS("rtnl-lwt-" __stringify(encap_type))
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#endif /* __NET_LWTUNNEL_H */
270