162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __NET_UDP_TUNNEL_H
362306a36Sopenharmony_ci#define __NET_UDP_TUNNEL_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <net/ip_tunnels.h>
662306a36Sopenharmony_ci#include <net/udp.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
962306a36Sopenharmony_ci#include <net/ipv6.h>
1062306a36Sopenharmony_ci#include <net/ipv6_stubs.h>
1162306a36Sopenharmony_ci#endif
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct udp_port_cfg {
1462306a36Sopenharmony_ci	u8			family;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	/* Used only for kernel-created sockets */
1762306a36Sopenharmony_ci	union {
1862306a36Sopenharmony_ci		struct in_addr		local_ip;
1962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2062306a36Sopenharmony_ci		struct in6_addr		local_ip6;
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci	};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	union {
2562306a36Sopenharmony_ci		struct in_addr		peer_ip;
2662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2762306a36Sopenharmony_ci		struct in6_addr		peer_ip6;
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci	};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	__be16			local_udp_port;
3262306a36Sopenharmony_ci	__be16			peer_udp_port;
3362306a36Sopenharmony_ci	int			bind_ifindex;
3462306a36Sopenharmony_ci	unsigned int		use_udp_checksums:1,
3562306a36Sopenharmony_ci				use_udp6_tx_checksums:1,
3662306a36Sopenharmony_ci				use_udp6_rx_checksums:1,
3762306a36Sopenharmony_ci				ipv6_v6only:1;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciint udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
4162306a36Sopenharmony_ci		     struct socket **sockp);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
4462306a36Sopenharmony_ciint udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
4562306a36Sopenharmony_ci		     struct socket **sockp);
4662306a36Sopenharmony_ci#else
4762306a36Sopenharmony_cistatic inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
4862306a36Sopenharmony_ci				   struct socket **sockp)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	return 0;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic inline int udp_sock_create(struct net *net,
5562306a36Sopenharmony_ci				  struct udp_port_cfg *cfg,
5662306a36Sopenharmony_ci				  struct socket **sockp)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	if (cfg->family == AF_INET)
5962306a36Sopenharmony_ci		return udp_sock_create4(net, cfg, sockp);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (cfg->family == AF_INET6)
6262306a36Sopenharmony_ci		return udp_sock_create6(net, cfg, sockp);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return -EPFNOSUPPORT;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_citypedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb);
6862306a36Sopenharmony_citypedef int (*udp_tunnel_encap_err_lookup_t)(struct sock *sk,
6962306a36Sopenharmony_ci					     struct sk_buff *skb);
7062306a36Sopenharmony_citypedef void (*udp_tunnel_encap_err_rcv_t)(struct sock *sk,
7162306a36Sopenharmony_ci					   struct sk_buff *skb, int err,
7262306a36Sopenharmony_ci					   __be16 port, u32 info, u8 *payload);
7362306a36Sopenharmony_citypedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk);
7462306a36Sopenharmony_citypedef struct sk_buff *(*udp_tunnel_gro_receive_t)(struct sock *sk,
7562306a36Sopenharmony_ci						    struct list_head *head,
7662306a36Sopenharmony_ci						    struct sk_buff *skb);
7762306a36Sopenharmony_citypedef int (*udp_tunnel_gro_complete_t)(struct sock *sk, struct sk_buff *skb,
7862306a36Sopenharmony_ci					 int nhoff);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct udp_tunnel_sock_cfg {
8162306a36Sopenharmony_ci	void *sk_user_data;     /* user data used by encap_rcv call back */
8262306a36Sopenharmony_ci	/* Used for setting up udp_sock fields, see udp.h for details */
8362306a36Sopenharmony_ci	__u8  encap_type;
8462306a36Sopenharmony_ci	udp_tunnel_encap_rcv_t encap_rcv;
8562306a36Sopenharmony_ci	udp_tunnel_encap_err_lookup_t encap_err_lookup;
8662306a36Sopenharmony_ci	udp_tunnel_encap_err_rcv_t encap_err_rcv;
8762306a36Sopenharmony_ci	udp_tunnel_encap_destroy_t encap_destroy;
8862306a36Sopenharmony_ci	udp_tunnel_gro_receive_t gro_receive;
8962306a36Sopenharmony_ci	udp_tunnel_gro_complete_t gro_complete;
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Setup the given (UDP) sock to receive UDP encapsulated packets */
9362306a36Sopenharmony_civoid setup_udp_tunnel_sock(struct net *net, struct socket *sock,
9462306a36Sopenharmony_ci			   struct udp_tunnel_sock_cfg *sock_cfg);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* -- List of parsable UDP tunnel types --
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Adding to this list will result in serious debate.  The main issue is
9962306a36Sopenharmony_ci * that this list is essentially a list of workarounds for either poorly
10062306a36Sopenharmony_ci * designed tunnels, or poorly designed device offloads.
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * The parsing supported via these types should really be used for Rx
10362306a36Sopenharmony_ci * traffic only as the network stack will have already inserted offsets for
10462306a36Sopenharmony_ci * the location of the headers in the skb.  In addition any ports that are
10562306a36Sopenharmony_ci * pushed should be kept within the namespace without leaking to other
10662306a36Sopenharmony_ci * devices such as VFs or other ports on the same device.
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * It is strongly encouraged to use CHECKSUM_COMPLETE for Rx to avoid the
10962306a36Sopenharmony_ci * need to use this for Rx checksum offload.  It should not be necessary to
11062306a36Sopenharmony_ci * call this function to perform Tx offloads on outgoing traffic.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cienum udp_parsable_tunnel_type {
11362306a36Sopenharmony_ci	UDP_TUNNEL_TYPE_VXLAN	  = BIT(0), /* RFC 7348 */
11462306a36Sopenharmony_ci	UDP_TUNNEL_TYPE_GENEVE	  = BIT(1), /* draft-ietf-nvo3-geneve */
11562306a36Sopenharmony_ci	UDP_TUNNEL_TYPE_VXLAN_GPE = BIT(2), /* draft-ietf-nvo3-vxlan-gpe */
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct udp_tunnel_info {
11962306a36Sopenharmony_ci	unsigned short type;
12062306a36Sopenharmony_ci	sa_family_t sa_family;
12162306a36Sopenharmony_ci	__be16 port;
12262306a36Sopenharmony_ci	u8 hw_priv;
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* Notify network devices of offloadable types */
12662306a36Sopenharmony_civoid udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
12762306a36Sopenharmony_ci			     unsigned short type);
12862306a36Sopenharmony_civoid udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock,
12962306a36Sopenharmony_ci			     unsigned short type);
13062306a36Sopenharmony_civoid udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type);
13162306a36Sopenharmony_civoid udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic inline void udp_tunnel_get_rx_info(struct net_device *dev)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	ASSERT_RTNL();
13662306a36Sopenharmony_ci	if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
13762306a36Sopenharmony_ci		return;
13862306a36Sopenharmony_ci	call_netdevice_notifiers(NETDEV_UDP_TUNNEL_PUSH_INFO, dev);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic inline void udp_tunnel_drop_rx_info(struct net_device *dev)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	ASSERT_RTNL();
14462306a36Sopenharmony_ci	if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
14562306a36Sopenharmony_ci		return;
14662306a36Sopenharmony_ci	call_netdevice_notifiers(NETDEV_UDP_TUNNEL_DROP_INFO, dev);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* Transmit the skb using UDP encapsulation. */
15062306a36Sopenharmony_civoid udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
15162306a36Sopenharmony_ci			 __be32 src, __be32 dst, __u8 tos, __u8 ttl,
15262306a36Sopenharmony_ci			 __be16 df, __be16 src_port, __be16 dst_port,
15362306a36Sopenharmony_ci			 bool xnet, bool nocheck);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ciint udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
15662306a36Sopenharmony_ci			 struct sk_buff *skb,
15762306a36Sopenharmony_ci			 struct net_device *dev, struct in6_addr *saddr,
15862306a36Sopenharmony_ci			 struct in6_addr *daddr,
15962306a36Sopenharmony_ci			 __u8 prio, __u8 ttl, __be32 label,
16062306a36Sopenharmony_ci			 __be16 src_port, __be16 dst_port, bool nocheck);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_civoid udp_tunnel_sock_release(struct socket *sock);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistruct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family,
16562306a36Sopenharmony_ci				    __be16 flags, __be64 tunnel_id,
16662306a36Sopenharmony_ci				    int md_size);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#ifdef CONFIG_INET
16962306a36Sopenharmony_cistatic inline int udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	int type = udp_csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return iptunnel_handle_offloads(skb, type);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci#endif
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic inline void udp_tunnel_encap_enable(struct sock *sk)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	if (udp_test_and_set_bit(ENCAP_ENABLED, sk))
18062306a36Sopenharmony_ci		return;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
18362306a36Sopenharmony_ci	if (READ_ONCE(sk->sk_family) == PF_INET6)
18462306a36Sopenharmony_ci		ipv6_stub->udpv6_encap_enable();
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci	udp_encap_enable();
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#define UDP_TUNNEL_NIC_MAX_TABLES	4
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cienum udp_tunnel_nic_info_flags {
19262306a36Sopenharmony_ci	/* Device callbacks may sleep */
19362306a36Sopenharmony_ci	UDP_TUNNEL_NIC_INFO_MAY_SLEEP	= BIT(0),
19462306a36Sopenharmony_ci	/* Device only supports offloads when it's open, all ports
19562306a36Sopenharmony_ci	 * will be removed before close and re-added after open.
19662306a36Sopenharmony_ci	 */
19762306a36Sopenharmony_ci	UDP_TUNNEL_NIC_INFO_OPEN_ONLY	= BIT(1),
19862306a36Sopenharmony_ci	/* Device supports only IPv4 tunnels */
19962306a36Sopenharmony_ci	UDP_TUNNEL_NIC_INFO_IPV4_ONLY	= BIT(2),
20062306a36Sopenharmony_ci	/* Device has hard-coded the IANA VXLAN port (4789) as VXLAN.
20162306a36Sopenharmony_ci	 * This port must not be counted towards n_entries of any table.
20262306a36Sopenharmony_ci	 * Driver will not receive any callback associated with port 4789.
20362306a36Sopenharmony_ci	 */
20462306a36Sopenharmony_ci	UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN	= BIT(3),
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistruct udp_tunnel_nic;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define UDP_TUNNEL_NIC_MAX_SHARING_DEVICES	(U16_MAX / 2)
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct udp_tunnel_nic_shared {
21262306a36Sopenharmony_ci	struct udp_tunnel_nic *udp_tunnel_nic_info;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	struct list_head devices;
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistruct udp_tunnel_nic_shared_node {
21862306a36Sopenharmony_ci	struct net_device *dev;
21962306a36Sopenharmony_ci	struct list_head list;
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/**
22362306a36Sopenharmony_ci * struct udp_tunnel_nic_info - driver UDP tunnel offload information
22462306a36Sopenharmony_ci * @set_port:	callback for adding a new port
22562306a36Sopenharmony_ci * @unset_port:	callback for removing a port
22662306a36Sopenharmony_ci * @sync_table:	callback for syncing the entire port table at once
22762306a36Sopenharmony_ci * @shared:	reference to device global state (optional)
22862306a36Sopenharmony_ci * @flags:	device flags from enum udp_tunnel_nic_info_flags
22962306a36Sopenharmony_ci * @tables:	UDP port tables this device has
23062306a36Sopenharmony_ci * @tables.n_entries:		number of entries in this table
23162306a36Sopenharmony_ci * @tables.tunnel_types:	types of tunnels this table accepts
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * Drivers are expected to provide either @set_port and @unset_port callbacks
23462306a36Sopenharmony_ci * or the @sync_table callback. Callbacks are invoked with rtnl lock held.
23562306a36Sopenharmony_ci *
23662306a36Sopenharmony_ci * Devices which (misguidedly) share the UDP tunnel port table across multiple
23762306a36Sopenharmony_ci * netdevs should allocate an instance of struct udp_tunnel_nic_shared and
23862306a36Sopenharmony_ci * point @shared at it.
23962306a36Sopenharmony_ci * There must never be more than %UDP_TUNNEL_NIC_MAX_SHARING_DEVICES devices
24062306a36Sopenharmony_ci * sharing a table.
24162306a36Sopenharmony_ci *
24262306a36Sopenharmony_ci * Known limitations:
24362306a36Sopenharmony_ci *  - UDP tunnel port notifications are fundamentally best-effort -
24462306a36Sopenharmony_ci *    it is likely the driver will both see skbs which use a UDP tunnel port,
24562306a36Sopenharmony_ci *    while not being a tunneled skb, and tunnel skbs from other ports -
24662306a36Sopenharmony_ci *    drivers should only use these ports for non-critical RX-side offloads,
24762306a36Sopenharmony_ci *    e.g. the checksum offload;
24862306a36Sopenharmony_ci *  - none of the devices care about the socket family at present, so we don't
24962306a36Sopenharmony_ci *    track it. Please extend this code if you care.
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_cistruct udp_tunnel_nic_info {
25262306a36Sopenharmony_ci	/* one-by-one */
25362306a36Sopenharmony_ci	int (*set_port)(struct net_device *dev,
25462306a36Sopenharmony_ci			unsigned int table, unsigned int entry,
25562306a36Sopenharmony_ci			struct udp_tunnel_info *ti);
25662306a36Sopenharmony_ci	int (*unset_port)(struct net_device *dev,
25762306a36Sopenharmony_ci			  unsigned int table, unsigned int entry,
25862306a36Sopenharmony_ci			  struct udp_tunnel_info *ti);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* all at once */
26162306a36Sopenharmony_ci	int (*sync_table)(struct net_device *dev, unsigned int table);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	struct udp_tunnel_nic_shared *shared;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	unsigned int flags;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	struct udp_tunnel_nic_table_info {
26862306a36Sopenharmony_ci		unsigned int n_entries;
26962306a36Sopenharmony_ci		unsigned int tunnel_types;
27062306a36Sopenharmony_ci	} tables[UDP_TUNNEL_NIC_MAX_TABLES];
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* UDP tunnel module dependencies
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * Tunnel drivers are expected to have a hard dependency on the udp_tunnel
27662306a36Sopenharmony_ci * module. NIC drivers are not, they just attach their
27762306a36Sopenharmony_ci * struct udp_tunnel_nic_info to the netdev and wait for callbacks to come.
27862306a36Sopenharmony_ci * Loading a tunnel driver will cause the udp_tunnel module to be loaded
27962306a36Sopenharmony_ci * and only then will all the required state structures be allocated.
28062306a36Sopenharmony_ci * Since we want a weak dependency from the drivers and the core to udp_tunnel
28162306a36Sopenharmony_ci * we call things through the following stubs.
28262306a36Sopenharmony_ci */
28362306a36Sopenharmony_cistruct udp_tunnel_nic_ops {
28462306a36Sopenharmony_ci	void (*get_port)(struct net_device *dev, unsigned int table,
28562306a36Sopenharmony_ci			 unsigned int idx, struct udp_tunnel_info *ti);
28662306a36Sopenharmony_ci	void (*set_port_priv)(struct net_device *dev, unsigned int table,
28762306a36Sopenharmony_ci			      unsigned int idx, u8 priv);
28862306a36Sopenharmony_ci	void (*add_port)(struct net_device *dev, struct udp_tunnel_info *ti);
28962306a36Sopenharmony_ci	void (*del_port)(struct net_device *dev, struct udp_tunnel_info *ti);
29062306a36Sopenharmony_ci	void (*reset_ntf)(struct net_device *dev);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	size_t (*dump_size)(struct net_device *dev, unsigned int table);
29362306a36Sopenharmony_ci	int (*dump_write)(struct net_device *dev, unsigned int table,
29462306a36Sopenharmony_ci			  struct sk_buff *skb);
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#ifdef CONFIG_INET
29862306a36Sopenharmony_ciextern const struct udp_tunnel_nic_ops *udp_tunnel_nic_ops;
29962306a36Sopenharmony_ci#else
30062306a36Sopenharmony_ci#define udp_tunnel_nic_ops	((struct udp_tunnel_nic_ops *)NULL)
30162306a36Sopenharmony_ci#endif
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic inline void
30462306a36Sopenharmony_ciudp_tunnel_nic_get_port(struct net_device *dev, unsigned int table,
30562306a36Sopenharmony_ci			unsigned int idx, struct udp_tunnel_info *ti)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	/* This helper is used from .sync_table, we indicate empty entries
30862306a36Sopenharmony_ci	 * by zero'ed @ti. Drivers which need to know the details of a port
30962306a36Sopenharmony_ci	 * when it gets deleted should use the .set_port / .unset_port
31062306a36Sopenharmony_ci	 * callbacks.
31162306a36Sopenharmony_ci	 * Zero out here, otherwise !CONFIG_INET causes uninitilized warnings.
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci	memset(ti, 0, sizeof(*ti));
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (udp_tunnel_nic_ops)
31662306a36Sopenharmony_ci		udp_tunnel_nic_ops->get_port(dev, table, idx, ti);
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic inline void
32062306a36Sopenharmony_ciudp_tunnel_nic_set_port_priv(struct net_device *dev, unsigned int table,
32162306a36Sopenharmony_ci			     unsigned int idx, u8 priv)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	if (udp_tunnel_nic_ops)
32462306a36Sopenharmony_ci		udp_tunnel_nic_ops->set_port_priv(dev, table, idx, priv);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic inline void
32862306a36Sopenharmony_ciudp_tunnel_nic_add_port(struct net_device *dev, struct udp_tunnel_info *ti)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
33162306a36Sopenharmony_ci		return;
33262306a36Sopenharmony_ci	if (udp_tunnel_nic_ops)
33362306a36Sopenharmony_ci		udp_tunnel_nic_ops->add_port(dev, ti);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic inline void
33762306a36Sopenharmony_ciudp_tunnel_nic_del_port(struct net_device *dev, struct udp_tunnel_info *ti)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
34062306a36Sopenharmony_ci		return;
34162306a36Sopenharmony_ci	if (udp_tunnel_nic_ops)
34262306a36Sopenharmony_ci		udp_tunnel_nic_ops->del_port(dev, ti);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/**
34662306a36Sopenharmony_ci * udp_tunnel_nic_reset_ntf() - device-originating reset notification
34762306a36Sopenharmony_ci * @dev: network interface device structure
34862306a36Sopenharmony_ci *
34962306a36Sopenharmony_ci * Called by the driver to inform the core that the entire UDP tunnel port
35062306a36Sopenharmony_ci * state has been lost, usually due to device reset. Core will assume device
35162306a36Sopenharmony_ci * forgot all the ports and issue .set_port and .sync_table callbacks as
35262306a36Sopenharmony_ci * necessary.
35362306a36Sopenharmony_ci *
35462306a36Sopenharmony_ci * This function must be called with rtnl lock held, and will issue all
35562306a36Sopenharmony_ci * the callbacks before returning.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_cistatic inline void udp_tunnel_nic_reset_ntf(struct net_device *dev)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	if (udp_tunnel_nic_ops)
36062306a36Sopenharmony_ci		udp_tunnel_nic_ops->reset_ntf(dev);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic inline size_t
36462306a36Sopenharmony_ciudp_tunnel_nic_dump_size(struct net_device *dev, unsigned int table)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	if (!udp_tunnel_nic_ops)
36762306a36Sopenharmony_ci		return 0;
36862306a36Sopenharmony_ci	return udp_tunnel_nic_ops->dump_size(dev, table);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic inline int
37262306a36Sopenharmony_ciudp_tunnel_nic_dump_write(struct net_device *dev, unsigned int table,
37362306a36Sopenharmony_ci			  struct sk_buff *skb)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	if (!udp_tunnel_nic_ops)
37662306a36Sopenharmony_ci		return 0;
37762306a36Sopenharmony_ci	return udp_tunnel_nic_ops->dump_write(dev, table, skb);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci#endif
380