18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __NET_LWTUNNEL_H
38c2ecf20Sopenharmony_ci#define __NET_LWTUNNEL_H 1
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/lwtunnel.h>
68c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
78c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
88c2ecf20Sopenharmony_ci#include <linux/types.h>
98c2ecf20Sopenharmony_ci#include <net/route.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define LWTUNNEL_HASH_BITS   7
128c2ecf20Sopenharmony_ci#define LWTUNNEL_HASH_SIZE   (1 << LWTUNNEL_HASH_BITS)
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* lw tunnel state flags */
158c2ecf20Sopenharmony_ci#define LWTUNNEL_STATE_OUTPUT_REDIRECT	BIT(0)
168c2ecf20Sopenharmony_ci#define LWTUNNEL_STATE_INPUT_REDIRECT	BIT(1)
178c2ecf20Sopenharmony_ci#define LWTUNNEL_STATE_XMIT_REDIRECT	BIT(2)
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* LWTUNNEL_XMIT_CONTINUE should be distinguishable from dst_output return
208c2ecf20Sopenharmony_ci * values (NET_XMIT_xxx and NETDEV_TX_xxx in linux/netdevice.h) for safety.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cienum {
238c2ecf20Sopenharmony_ci	LWTUNNEL_XMIT_DONE,
248c2ecf20Sopenharmony_ci	LWTUNNEL_XMIT_CONTINUE = 0x100,
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct lwtunnel_state {
298c2ecf20Sopenharmony_ci	__u16		type;
308c2ecf20Sopenharmony_ci	__u16		flags;
318c2ecf20Sopenharmony_ci	__u16		headroom;
328c2ecf20Sopenharmony_ci	atomic_t	refcnt;
338c2ecf20Sopenharmony_ci	int		(*orig_output)(struct net *net, struct sock *sk, struct sk_buff *skb);
348c2ecf20Sopenharmony_ci	int		(*orig_input)(struct sk_buff *);
358c2ecf20Sopenharmony_ci	struct		rcu_head rcu;
368c2ecf20Sopenharmony_ci	__u8            data[];
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct lwtunnel_encap_ops {
408c2ecf20Sopenharmony_ci	int (*build_state)(struct net *net, struct nlattr *encap,
418c2ecf20Sopenharmony_ci			   unsigned int family, const void *cfg,
428c2ecf20Sopenharmony_ci			   struct lwtunnel_state **ts,
438c2ecf20Sopenharmony_ci			   struct netlink_ext_ack *extack);
448c2ecf20Sopenharmony_ci	void (*destroy_state)(struct lwtunnel_state *lws);
458c2ecf20Sopenharmony_ci	int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
468c2ecf20Sopenharmony_ci	int (*input)(struct sk_buff *skb);
478c2ecf20Sopenharmony_ci	int (*fill_encap)(struct sk_buff *skb,
488c2ecf20Sopenharmony_ci			  struct lwtunnel_state *lwtstate);
498c2ecf20Sopenharmony_ci	int (*get_encap_size)(struct lwtunnel_state *lwtstate);
508c2ecf20Sopenharmony_ci	int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b);
518c2ecf20Sopenharmony_ci	int (*xmit)(struct sk_buff *skb);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	struct module *owner;
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#ifdef CONFIG_LWTUNNEL
578c2ecf20Sopenharmony_civoid lwtstate_free(struct lwtunnel_state *lws);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline struct lwtunnel_state *
608c2ecf20Sopenharmony_cilwtstate_get(struct lwtunnel_state *lws)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	if (lws)
638c2ecf20Sopenharmony_ci		atomic_inc(&lws->refcnt);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return lws;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline void lwtstate_put(struct lwtunnel_state *lws)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	if (!lws)
718c2ecf20Sopenharmony_ci		return;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&lws->refcnt))
748c2ecf20Sopenharmony_ci		lwtstate_free(lws);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_OUTPUT_REDIRECT))
808c2ecf20Sopenharmony_ci		return true;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return false;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_INPUT_REDIRECT))
888c2ecf20Sopenharmony_ci		return true;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return false;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_XMIT_REDIRECT))
968c2ecf20Sopenharmony_ci		return true;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return false;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate,
1028c2ecf20Sopenharmony_ci					     unsigned int mtu)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	if ((lwtunnel_xmit_redirect(lwtstate) ||
1058c2ecf20Sopenharmony_ci	     lwtunnel_output_redirect(lwtstate)) && lwtstate->headroom < mtu)
1068c2ecf20Sopenharmony_ci		return lwtstate->headroom;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ciint lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
1128c2ecf20Sopenharmony_ci			   unsigned int num);
1138c2ecf20Sopenharmony_ciint lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
1148c2ecf20Sopenharmony_ci			   unsigned int num);
1158c2ecf20Sopenharmony_ciint lwtunnel_valid_encap_type(u16 encap_type,
1168c2ecf20Sopenharmony_ci			      struct netlink_ext_ack *extack);
1178c2ecf20Sopenharmony_ciint lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
1188c2ecf20Sopenharmony_ci				   struct netlink_ext_ack *extack);
1198c2ecf20Sopenharmony_ciint lwtunnel_build_state(struct net *net, u16 encap_type,
1208c2ecf20Sopenharmony_ci			 struct nlattr *encap,
1218c2ecf20Sopenharmony_ci			 unsigned int family, const void *cfg,
1228c2ecf20Sopenharmony_ci			 struct lwtunnel_state **lws,
1238c2ecf20Sopenharmony_ci			 struct netlink_ext_ack *extack);
1248c2ecf20Sopenharmony_ciint lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate,
1258c2ecf20Sopenharmony_ci			int encap_attr, int encap_type_attr);
1268c2ecf20Sopenharmony_ciint lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
1278c2ecf20Sopenharmony_cistruct lwtunnel_state *lwtunnel_state_alloc(int hdr_len);
1288c2ecf20Sopenharmony_ciint lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b);
1298c2ecf20Sopenharmony_ciint lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb);
1308c2ecf20Sopenharmony_ciint lwtunnel_input(struct sk_buff *skb);
1318c2ecf20Sopenharmony_ciint lwtunnel_xmit(struct sk_buff *skb);
1328c2ecf20Sopenharmony_ciint bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len,
1338c2ecf20Sopenharmony_ci			  bool ingress);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline void lwtunnel_set_redirect(struct dst_entry *dst)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	if (lwtunnel_output_redirect(dst->lwtstate)) {
1388c2ecf20Sopenharmony_ci		dst->lwtstate->orig_output = dst->output;
1398c2ecf20Sopenharmony_ci		dst->output = lwtunnel_output;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci	if (lwtunnel_input_redirect(dst->lwtstate)) {
1428c2ecf20Sopenharmony_ci		dst->lwtstate->orig_input = dst->input;
1438c2ecf20Sopenharmony_ci		dst->input = lwtunnel_input;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci#else
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic inline void lwtstate_free(struct lwtunnel_state *lws)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic inline struct lwtunnel_state *
1538c2ecf20Sopenharmony_cilwtstate_get(struct lwtunnel_state *lws)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	return lws;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic inline void lwtstate_put(struct lwtunnel_state *lws)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return false;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return false;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	return false;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic inline void lwtunnel_set_redirect(struct dst_entry *dst)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate,
1828c2ecf20Sopenharmony_ci					     unsigned int mtu)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
1888c2ecf20Sopenharmony_ci					 unsigned int num)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
1958c2ecf20Sopenharmony_ci					 unsigned int num)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic inline int lwtunnel_valid_encap_type(u16 encap_type,
2018c2ecf20Sopenharmony_ci					    struct netlink_ext_ack *extack)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG(extack, "CONFIG_LWTUNNEL is not enabled in this kernel");
2048c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_cistatic inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
2078c2ecf20Sopenharmony_ci						 struct netlink_ext_ack *extack)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	/* return 0 since we are not walking attr looking for
2108c2ecf20Sopenharmony_ci	 * RTA_ENCAP_TYPE attribute on nexthops.
2118c2ecf20Sopenharmony_ci	 */
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic inline int lwtunnel_build_state(struct net *net, u16 encap_type,
2168c2ecf20Sopenharmony_ci				       struct nlattr *encap,
2178c2ecf20Sopenharmony_ci				       unsigned int family, const void *cfg,
2188c2ecf20Sopenharmony_ci				       struct lwtunnel_state **lws,
2198c2ecf20Sopenharmony_ci				       struct netlink_ext_ack *extack)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic inline int lwtunnel_fill_encap(struct sk_buff *skb,
2258c2ecf20Sopenharmony_ci				      struct lwtunnel_state *lwtstate,
2268c2ecf20Sopenharmony_ci				      int encap_attr, int encap_type_attr)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	return 0;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	return NULL;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic inline int lwtunnel_cmp_encap(struct lwtunnel_state *a,
2428c2ecf20Sopenharmony_ci				     struct lwtunnel_state *b)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	return 0;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic inline int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic inline int lwtunnel_input(struct sk_buff *skb)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic inline int lwtunnel_xmit(struct sk_buff *skb)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci#endif /* CONFIG_LWTUNNEL */
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci#define MODULE_ALIAS_RTNL_LWT(encap_type) MODULE_ALIAS("rtnl-lwt-" __stringify(encap_type))
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci#endif /* __NET_LWTUNNEL_H */
267