xref: /freebsd/sys/net/if_geneve.c (revision f4e5b45b11628416f596b3aec2ccd3056800a171)
1e44d2e94SPouria Mousavizadeh Tehrani /*-
2e44d2e94SPouria Mousavizadeh Tehrani  * SPDX-License-Identifier: BSD-2-Clause
3e44d2e94SPouria Mousavizadeh Tehrani  *
4e44d2e94SPouria Mousavizadeh Tehrani  * Copyright (c) 2025-2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
5e44d2e94SPouria Mousavizadeh Tehrani  * All rights reserved.
6e44d2e94SPouria Mousavizadeh Tehrani  *
7e44d2e94SPouria Mousavizadeh Tehrani  * Redistribution and use in source and binary forms, with or without
8e44d2e94SPouria Mousavizadeh Tehrani  * modification, are permitted provided that the following conditions
9e44d2e94SPouria Mousavizadeh Tehrani  * are met:
10e44d2e94SPouria Mousavizadeh Tehrani  * 1. Redistributions of source code must retain the above copyright
11e44d2e94SPouria Mousavizadeh Tehrani  *    notice, this list of conditions and the following disclaimer.
12e44d2e94SPouria Mousavizadeh Tehrani  * 2. Redistributions in binary form must reproduce the above copyright
13e44d2e94SPouria Mousavizadeh Tehrani  *    notice, this list of conditions and the following disclaimer in the
14e44d2e94SPouria Mousavizadeh Tehrani  *    documentation and/or other materials provided with the distribution.
15e44d2e94SPouria Mousavizadeh Tehrani  *
16e44d2e94SPouria Mousavizadeh Tehrani  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17e44d2e94SPouria Mousavizadeh Tehrani  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18e44d2e94SPouria Mousavizadeh Tehrani  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19e44d2e94SPouria Mousavizadeh Tehrani  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20e44d2e94SPouria Mousavizadeh Tehrani  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21e44d2e94SPouria Mousavizadeh Tehrani  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22e44d2e94SPouria Mousavizadeh Tehrani  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23e44d2e94SPouria Mousavizadeh Tehrani  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24e44d2e94SPouria Mousavizadeh Tehrani  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25e44d2e94SPouria Mousavizadeh Tehrani  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26e44d2e94SPouria Mousavizadeh Tehrani  * SUCH DAMAGE.
27e44d2e94SPouria Mousavizadeh Tehrani  */
28e44d2e94SPouria Mousavizadeh Tehrani 
29e44d2e94SPouria Mousavizadeh Tehrani #include "opt_inet.h"
30e44d2e94SPouria Mousavizadeh Tehrani #include "opt_inet6.h"
31e44d2e94SPouria Mousavizadeh Tehrani 
32e44d2e94SPouria Mousavizadeh Tehrani #include <sys/param.h>
33e44d2e94SPouria Mousavizadeh Tehrani #include <sys/kernel.h>
34e44d2e94SPouria Mousavizadeh Tehrani #include <sys/lock.h>
35e44d2e94SPouria Mousavizadeh Tehrani #include <sys/hash.h>
36e44d2e94SPouria Mousavizadeh Tehrani #include <sys/malloc.h>
37e44d2e94SPouria Mousavizadeh Tehrani #include <sys/mbuf.h>
38e44d2e94SPouria Mousavizadeh Tehrani #include <sys/module.h>
39e44d2e94SPouria Mousavizadeh Tehrani #include <sys/refcount.h>
40e44d2e94SPouria Mousavizadeh Tehrani #include <sys/rmlock.h>
41e44d2e94SPouria Mousavizadeh Tehrani #include <sys/priv.h>
42e44d2e94SPouria Mousavizadeh Tehrani #include <sys/proc.h>
43e44d2e94SPouria Mousavizadeh Tehrani #include <sys/queue.h>
44e44d2e94SPouria Mousavizadeh Tehrani #include <sys/sdt.h>
45e44d2e94SPouria Mousavizadeh Tehrani #include <sys/socket.h>
46e44d2e94SPouria Mousavizadeh Tehrani #include <sys/socketvar.h>
47e44d2e94SPouria Mousavizadeh Tehrani #include <sys/sockio.h>
48e44d2e94SPouria Mousavizadeh Tehrani #include <sys/sx.h>
49e44d2e94SPouria Mousavizadeh Tehrani #include <sys/systm.h>
50e44d2e94SPouria Mousavizadeh Tehrani #include <sys/counter.h>
51e44d2e94SPouria Mousavizadeh Tehrani #include <sys/jail.h>
52e44d2e94SPouria Mousavizadeh Tehrani 
53e44d2e94SPouria Mousavizadeh Tehrani #include <net/bpf.h>
54e44d2e94SPouria Mousavizadeh Tehrani #include <net/ethernet.h>
55e44d2e94SPouria Mousavizadeh Tehrani #include <net/if.h>
56e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_var.h>
57e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_private.h>
58e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_arp.h>
59e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_clone.h>
60e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_media.h>
61e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_types.h>
62e44d2e94SPouria Mousavizadeh Tehrani #include <net/netisr.h>
63e44d2e94SPouria Mousavizadeh Tehrani #include <net/route.h>
64e44d2e94SPouria Mousavizadeh Tehrani #include <net/route/nhop.h>
65e44d2e94SPouria Mousavizadeh Tehrani 
66e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/in.h>
67e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/in_systm.h>
68e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/in_var.h>
69e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/in_pcb.h>
70e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/ip.h>
71e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/ip_var.h>
72e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/ip6.h>
73e44d2e94SPouria Mousavizadeh Tehrani #include <netinet6/ip6_var.h>
74e44d2e94SPouria Mousavizadeh Tehrani #include <netinet6/in6_var.h>
75e44d2e94SPouria Mousavizadeh Tehrani #include <netinet6/scope6_var.h>
76e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/udp.h>
77e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/udp_var.h>
78e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/in_fib.h>
79e44d2e94SPouria Mousavizadeh Tehrani #include <netinet6/in6_fib.h>
80e44d2e94SPouria Mousavizadeh Tehrani #include <netinet/ip_ecn.h>
81e44d2e94SPouria Mousavizadeh Tehrani #include <net/if_geneve.h>
82e44d2e94SPouria Mousavizadeh Tehrani 
83e44d2e94SPouria Mousavizadeh Tehrani #include <netlink/netlink.h>
84e44d2e94SPouria Mousavizadeh Tehrani #include <netlink/netlink_ctl.h>
85e44d2e94SPouria Mousavizadeh Tehrani #include <netlink/netlink_var.h>
86e44d2e94SPouria Mousavizadeh Tehrani #include <netlink/netlink_route.h>
87e44d2e94SPouria Mousavizadeh Tehrani #include <netlink/route/route_var.h>
88e44d2e94SPouria Mousavizadeh Tehrani 
89e44d2e94SPouria Mousavizadeh Tehrani #include <security/mac/mac_framework.h>
90e44d2e94SPouria Mousavizadeh Tehrani 
91e44d2e94SPouria Mousavizadeh Tehrani SDT_PROVIDER_DEFINE(if_geneve);
92e44d2e94SPouria Mousavizadeh Tehrani 
93e44d2e94SPouria Mousavizadeh Tehrani struct geneve_softc;
94e44d2e94SPouria Mousavizadeh Tehrani LIST_HEAD(geneve_softc_head, geneve_softc);
95e44d2e94SPouria Mousavizadeh Tehrani 
96e44d2e94SPouria Mousavizadeh Tehrani static struct sx geneve_sx;
97e44d2e94SPouria Mousavizadeh Tehrani SX_SYSINIT(geneve, &geneve_sx, "GENEVE global start/stop lock");
98e44d2e94SPouria Mousavizadeh Tehrani 
99e44d2e94SPouria Mousavizadeh Tehrani static unsigned geneve_osd_jail_slot;
100e44d2e94SPouria Mousavizadeh Tehrani 
101e44d2e94SPouria Mousavizadeh Tehrani union sockaddr_union {
102e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr		sa;
103e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr_in	sin;
104e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr_in6	sin6;
105e44d2e94SPouria Mousavizadeh Tehrani };
106e44d2e94SPouria Mousavizadeh Tehrani 
107e44d2e94SPouria Mousavizadeh Tehrani struct geneve_socket_mc_info {
108e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union	gnvsomc_saddr;
109e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union	gnvsomc_gaddr;
110e44d2e94SPouria Mousavizadeh Tehrani 	int			gnvsomc_ifidx;
111e44d2e94SPouria Mousavizadeh Tehrani 	int			gnvsomc_users;
112e44d2e94SPouria Mousavizadeh Tehrani };
113e44d2e94SPouria Mousavizadeh Tehrani 
114e44d2e94SPouria Mousavizadeh Tehrani /* The maximum MTU of encapsulated geneve packet. */
115e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_MAX_L3MTU	(IP_MAXPACKET - \
116e44d2e94SPouria Mousavizadeh Tehrani 	    60 /* Maximum IPv4 header len */ - \
117e44d2e94SPouria Mousavizadeh Tehrani 	    sizeof(struct udphdr) - \
118e44d2e94SPouria Mousavizadeh Tehrani 	    sizeof(struct genevehdr))
119e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_MAX_MTU		(GENEVE_MAX_L3MTU - \
120e44d2e94SPouria Mousavizadeh Tehrani 	    ETHER_HDR_LEN - ETHER_VLAN_ENCAP_LEN)
121e44d2e94SPouria Mousavizadeh Tehrani 
122e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_BASIC_IFCAPS (IFCAP_LINKSTATE | IFCAP_JUMBO_MTU | IFCAP_NV)
123e44d2e94SPouria Mousavizadeh Tehrani 
124e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_VERSION	0
125e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_VNI_MASK	(GENEVE_VNI_MAX - 1)
126e44d2e94SPouria Mousavizadeh Tehrani 
127e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_HDR_VNI_SHIFT	8
128e44d2e94SPouria Mousavizadeh Tehrani 
129e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_MC_MAX_GROUPS		32
130e44d2e94SPouria Mousavizadeh Tehrani 
131e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_VNI_HASH_SHIFT	6
132e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_VNI_HASH_SIZE		(1 << GENEVE_SO_VNI_HASH_SHIFT)
133e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_VNI_HASH(_vni)	((_vni) % GENEVE_SO_VNI_HASH_SIZE)
134e44d2e94SPouria Mousavizadeh Tehrani 
135e44d2e94SPouria Mousavizadeh Tehrani struct geneve_socket {
136e44d2e94SPouria Mousavizadeh Tehrani 	struct socket			*gnvso_sock;
137e44d2e94SPouria Mousavizadeh Tehrani 	struct rmlock			gnvso_lock;
138e44d2e94SPouria Mousavizadeh Tehrani 	u_int				gnvso_refcnt;
139e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union		gnvso_laddr;
140e44d2e94SPouria Mousavizadeh Tehrani 	LIST_ENTRY(geneve_socket)	gnvso_entry;
141e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc_head	gnvso_vni_hash[GENEVE_SO_VNI_HASH_SIZE];
142e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket_mc_info	gnvso_mc[GENEVE_SO_MC_MAX_GROUPS];
143e44d2e94SPouria Mousavizadeh Tehrani };
144e44d2e94SPouria Mousavizadeh Tehrani 
145e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_RLOCK(_gnvso, _p)	rm_rlock(&(_gnvso)->gnvso_lock, (_p))
146e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_RUNLOCK(_gnvso, _p)	rm_runlock(&(_gnvso)->gnvso_lock, (_p))
147e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_WLOCK(_gnvso)		rm_wlock(&(_gnvso)->gnvso_lock)
148e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_WUNLOCK(_gnvso)		rm_wunlock(&(_gnvso)->gnvso_lock)
149e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_LOCK_ASSERT(_gnvso) \
150e44d2e94SPouria Mousavizadeh Tehrani     rm_assert(&(_gnvso)->gnvso_lock, RA_LOCKED)
151e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_LOCK_WASSERT(_gnvso) \
152e44d2e94SPouria Mousavizadeh Tehrani     rm_assert(&(_gnvso)->gnvso_lock, RA_WLOCKED)
153e44d2e94SPouria Mousavizadeh Tehrani 
154e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_ACQUIRE(_gnvso)		refcount_acquire(&(_gnvso)->gnvso_refcnt)
155e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SO_RELEASE(_gnvso)		refcount_release(&(_gnvso)->gnvso_refcnt)
156e44d2e94SPouria Mousavizadeh Tehrani 
157e44d2e94SPouria Mousavizadeh Tehrani struct gnv_ftable_entry {
158e44d2e94SPouria Mousavizadeh Tehrani 	LIST_ENTRY(gnv_ftable_entry)	gnvfe_hash;
159e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			gnvfe_flags;
160e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t				gnvfe_mac[ETHER_ADDR_LEN];
161e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union		gnvfe_raddr;
162e44d2e94SPouria Mousavizadeh Tehrani 	time_t				gnvfe_expire;
163e44d2e94SPouria Mousavizadeh Tehrani };
164e44d2e94SPouria Mousavizadeh Tehrani 
165e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FE_FLAG_DYNAMIC		0x01
166e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FE_FLAG_STATIC		0x02
167e44d2e94SPouria Mousavizadeh Tehrani 
168e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FE_IS_DYNAMIC(_fe) \
169e44d2e94SPouria Mousavizadeh Tehrani     ((_fe)->gnvfe_flags & GENEVE_FE_FLAG_DYNAMIC)
170e44d2e94SPouria Mousavizadeh Tehrani 
171e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SC_FTABLE_SHIFT		9
172e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SC_FTABLE_SIZE		(1 << GENEVE_SC_FTABLE_SHIFT)
173e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SC_FTABLE_MASK		(GENEVE_SC_FTABLE_SIZE - 1)
174e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_SC_FTABLE_HASH(_sc, _mac)	\
175e44d2e94SPouria Mousavizadeh Tehrani     (geneve_mac_hash(_sc, _mac) % GENEVE_SC_FTABLE_SIZE)
176e44d2e94SPouria Mousavizadeh Tehrani 
177e44d2e94SPouria Mousavizadeh Tehrani LIST_HEAD(geneve_ftable_head, gnv_ftable_entry);
178e44d2e94SPouria Mousavizadeh Tehrani 
179e44d2e94SPouria Mousavizadeh Tehrani struct geneve_statistics {
180e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t	ftable_nospace;
181e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t	ftable_lock_upgrade_failed;
182e44d2e94SPouria Mousavizadeh Tehrani 	counter_u64_t	txcsum;
183e44d2e94SPouria Mousavizadeh Tehrani 	counter_u64_t	tso;
184e44d2e94SPouria Mousavizadeh Tehrani 	counter_u64_t	rxcsum;
185e44d2e94SPouria Mousavizadeh Tehrani };
186e44d2e94SPouria Mousavizadeh Tehrani 
187e44d2e94SPouria Mousavizadeh Tehrani struct geneve_softc {
188e44d2e94SPouria Mousavizadeh Tehrani 	LIST_ENTRY(geneve_softc)	gnv_entry;
189e44d2e94SPouria Mousavizadeh Tehrani 
190e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet			*gnv_ifp;
191e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_flags;
192e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_INIT		0x0001
193e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_RUNNING		0x0002
194e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_TEARDOWN		0x0004
195e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_LEARN		0x0008
196e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_USER_MTU		0x0010
197e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_TTL_INHERIT		0x0020
198e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_DSCP_INHERIT	0x0040
199e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FLAG_COLLECT_METADATA	0x0080
200e44d2e94SPouria Mousavizadeh Tehrani 
201e44d2e94SPouria Mousavizadeh Tehrani 	int				gnv_reqcap;
202e44d2e94SPouria Mousavizadeh Tehrani 	int				gnv_reqcap2;
203e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket		*gnv_sock;
204e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union		gnv_src_addr;
205e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union		gnv_dst_addr;
206e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_fibnum;
207e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_vni;
208e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_port_hash_key;
209e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			gnv_proto;
210e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			gnv_min_port;
211e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			gnv_max_port;
212e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t				gnv_ttl;
213e44d2e94SPouria Mousavizadeh Tehrani 	enum ifla_geneve_df		gnv_df;
214e44d2e94SPouria Mousavizadeh Tehrani 
215e44d2e94SPouria Mousavizadeh Tehrani 	/* Lookup table from MAC address to forwarding entry. */
216e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_ftable_cnt;
217e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_ftable_max;
218e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_ftable_timeout;
219e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			gnv_ftable_hash_key;
220e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_ftable_head	*gnv_ftable;
221e44d2e94SPouria Mousavizadeh Tehrani 
222e44d2e94SPouria Mousavizadeh Tehrani 	/* Derived from gnv_dst_addr. */
223e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry		gnv_default_fe;
224e44d2e94SPouria Mousavizadeh Tehrani 
225e44d2e94SPouria Mousavizadeh Tehrani 	struct ip_moptions		*gnv_im4o;
226e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_moptions		*gnv_im6o;
227e44d2e94SPouria Mousavizadeh Tehrani 
228e44d2e94SPouria Mousavizadeh Tehrani 	struct rmlock			gnv_lock;
229e44d2e94SPouria Mousavizadeh Tehrani 	volatile u_int			gnv_refcnt;
230e44d2e94SPouria Mousavizadeh Tehrani 
231e44d2e94SPouria Mousavizadeh Tehrani 	int				gnv_so_mc_index;
232e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_statistics	gnv_stats;
233e44d2e94SPouria Mousavizadeh Tehrani 	struct callout			gnv_callout;
234e44d2e94SPouria Mousavizadeh Tehrani 	struct ether_addr		gnv_hwaddr;
235e44d2e94SPouria Mousavizadeh Tehrani 	int				gnv_mc_ifindex;
236e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet			*gnv_mc_ifp;
237e44d2e94SPouria Mousavizadeh Tehrani 	struct ifmedia			gnv_media;
238e44d2e94SPouria Mousavizadeh Tehrani 	char				gnv_mc_ifname[IFNAMSIZ];
239e44d2e94SPouria Mousavizadeh Tehrani 
240e44d2e94SPouria Mousavizadeh Tehrani 	/* For rate limiting errors on the tx fast path. */
241e44d2e94SPouria Mousavizadeh Tehrani 	struct timeval			err_time;
242e44d2e94SPouria Mousavizadeh Tehrani 	int				err_pps;
243e44d2e94SPouria Mousavizadeh Tehrani };
244e44d2e94SPouria Mousavizadeh Tehrani 
245e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_RLOCK(_sc, _p)	rm_rlock(&(_sc)->gnv_lock, (_p))
246e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_RUNLOCK(_sc, _p)	rm_runlock(&(_sc)->gnv_lock, (_p))
247e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_WLOCK(_sc)	rm_wlock(&(_sc)->gnv_lock)
248e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_WUNLOCK(_sc)	rm_wunlock(&(_sc)->gnv_lock)
249e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_LOCK_WOWNED(_sc)	rm_wowned(&(_sc)->gnv_lock)
250e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_LOCK_ASSERT(_sc)	rm_assert(&(_sc)->gnv_lock, RA_LOCKED)
251e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_LOCK_WASSERT(_sc) rm_assert(&(_sc)->gnv_lock, RA_WLOCKED)
252e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_UNLOCK(_sc, _p) do {		\
253e44d2e94SPouria Mousavizadeh Tehrani     if (GENEVE_LOCK_WOWNED(_sc))		\
254e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(_sc);			\
255e44d2e94SPouria Mousavizadeh Tehrani     else					\
256e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_RUNLOCK(_sc, _p);		\
257e44d2e94SPouria Mousavizadeh Tehrani } while (0)
258e44d2e94SPouria Mousavizadeh Tehrani 
259e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_ACQUIRE(_sc)	refcount_acquire(&(_sc)->gnv_refcnt)
260e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_RELEASE(_sc)	refcount_release(&(_sc)->gnv_refcnt)
261e44d2e94SPouria Mousavizadeh Tehrani 
262e44d2e94SPouria Mousavizadeh Tehrani #define	SATOCONSTSIN(sa)	((const struct sockaddr_in *)(sa))
263e44d2e94SPouria Mousavizadeh Tehrani #define	SATOCONSTSIN6(sa)	((const struct sockaddr_in6 *)(sa))
264e44d2e94SPouria Mousavizadeh Tehrani 
265e44d2e94SPouria Mousavizadeh Tehrani struct geneve_pkt_info {
266e44d2e94SPouria Mousavizadeh Tehrani 	u_int		isr;
267e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t	ethertype;
268e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t		ecn;
269e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t		ttl;
270e44d2e94SPouria Mousavizadeh Tehrani };
271e44d2e94SPouria Mousavizadeh Tehrani 
272e44d2e94SPouria Mousavizadeh Tehrani struct nl_parsed_geneve {
273e44d2e94SPouria Mousavizadeh Tehrani 	/* essential */
274e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			ifla_vni;
275e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			ifla_proto;
276e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr			*ifla_local;
277e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr			*ifla_remote;
278e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			ifla_local_port;
279e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t			ifla_remote_port;
280e44d2e94SPouria Mousavizadeh Tehrani 
281e44d2e94SPouria Mousavizadeh Tehrani 	/* optional */
282e44d2e94SPouria Mousavizadeh Tehrani 	struct ifla_geneve_port_range	ifla_port_range;
283e44d2e94SPouria Mousavizadeh Tehrani 	enum ifla_geneve_df		ifla_df;
284e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t				ifla_ttl;
285e44d2e94SPouria Mousavizadeh Tehrani 	bool				ifla_ttl_inherit;
286e44d2e94SPouria Mousavizadeh Tehrani 	bool				ifla_dscp_inherit;
287e44d2e94SPouria Mousavizadeh Tehrani 	bool				ifla_external;
288e44d2e94SPouria Mousavizadeh Tehrani 
289e44d2e94SPouria Mousavizadeh Tehrani 	/* l2 specific */
290e44d2e94SPouria Mousavizadeh Tehrani 	bool				ifla_ftable_learn;
291e44d2e94SPouria Mousavizadeh Tehrani 	bool				ifla_ftable_flush;
292e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			ifla_ftable_max;
293e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			ifla_ftable_timeout;
294e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			ifla_ftable_count;	/* read-only */
295e44d2e94SPouria Mousavizadeh Tehrani 
296e44d2e94SPouria Mousavizadeh Tehrani 	/* multicast specific */
297e44d2e94SPouria Mousavizadeh Tehrani 	char				*ifla_mc_ifname;
298e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t			ifla_mc_ifindex;	/* read-only */
299e44d2e94SPouria Mousavizadeh Tehrani };
300e44d2e94SPouria Mousavizadeh Tehrani 
301e44d2e94SPouria Mousavizadeh Tehrani /* The multicast-based learning parts of the code are taken from if_vxlan */
302e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_ftable_addr_cmp(const uint8_t *, const uint8_t *);
303e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_init(struct geneve_softc *);
304e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_fini(struct geneve_softc *);
305e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_flush(struct geneve_softc *, int);
306e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_expire(struct geneve_softc *);
307e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_ftable_update_locked(struct geneve_softc *,
308e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, const uint8_t *,
309e44d2e94SPouria Mousavizadeh Tehrani 		    struct rm_priotracker *);
310e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_ftable_learn(struct geneve_softc *,
311e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *, const uint8_t *);
312e44d2e94SPouria Mousavizadeh Tehrani 
313e44d2e94SPouria Mousavizadeh Tehrani static struct gnv_ftable_entry *
314e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_entry_alloc(void);
315e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_entry_free(struct gnv_ftable_entry *);
316e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_entry_init(struct geneve_softc *,
317e44d2e94SPouria Mousavizadeh Tehrani 		    struct gnv_ftable_entry *, const uint8_t *,
318e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *, uint32_t);
319e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_ftable_entry_destroy(struct geneve_softc *,
320e44d2e94SPouria Mousavizadeh Tehrani 		    struct gnv_ftable_entry *);
321e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_ftable_entry_insert(struct geneve_softc *,
322e44d2e94SPouria Mousavizadeh Tehrani 		    struct gnv_ftable_entry *);
323e44d2e94SPouria Mousavizadeh Tehrani static struct gnv_ftable_entry *
324e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_entry_lookup(struct geneve_softc *,
325e44d2e94SPouria Mousavizadeh Tehrani 		    const uint8_t *);
326e44d2e94SPouria Mousavizadeh Tehrani 
327e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_socket *
328e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_alloc(union sockaddr_union *laddr);
329e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_socket_destroy(struct geneve_socket *);
330e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_socket_release(struct geneve_socket *);
331e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_socket *
332e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_lookup(union sockaddr_union *);
333e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_socket_insert(struct geneve_socket *);
334e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_init(struct geneve_socket *, struct ifnet *);
335e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_bind(struct geneve_socket *, struct ifnet *);
336e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_create(struct ifnet *, int,
337e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, struct geneve_socket **);
338e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_set_df(struct geneve_socket *, bool);
339e44d2e94SPouria Mousavizadeh Tehrani 
340e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_socket *
341e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_mc_lookup(const union sockaddr_union *);
342e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_sockaddr_mc_info_match(
343e44d2e94SPouria Mousavizadeh Tehrani 		    const struct geneve_socket_mc_info *,
344e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *,
345e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, int);
346e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_mc_join_group(struct geneve_socket *,
347e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, const union sockaddr_union *,
348e44d2e94SPouria Mousavizadeh Tehrani 		    int *, union sockaddr_union *);
349e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_mc_leave_group(struct geneve_socket *,
350e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *,
351e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, int);
352e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_mc_add_group(struct geneve_socket *,
353e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *,
354e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, int, int *);
355e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_socket_mc_release_group(struct geneve_socket *, int);
356e44d2e94SPouria Mousavizadeh Tehrani 
357e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_softc *
358e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_lookup_softc_locked(struct geneve_socket *,
359e44d2e94SPouria Mousavizadeh Tehrani 		    uint32_t);
360e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_softc *
361e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_lookup_softc(struct geneve_socket *, uint32_t);
362e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_socket_insert_softc(struct geneve_socket *,
363e44d2e94SPouria Mousavizadeh Tehrani 		    struct geneve_softc *);
364e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_socket_remove_softc(struct geneve_socket *,
365e44d2e94SPouria Mousavizadeh Tehrani 		    struct geneve_softc *);
366e44d2e94SPouria Mousavizadeh Tehrani 
367e44d2e94SPouria Mousavizadeh Tehrani static struct ifnet *
368e44d2e94SPouria Mousavizadeh Tehrani 		geneve_multicast_if_ref(struct geneve_softc *, uint32_t);
369e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_free_multicast(struct geneve_softc *);
370e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_setup_multicast_interface(struct geneve_softc *);
371e44d2e94SPouria Mousavizadeh Tehrani 
372e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_setup_multicast(struct geneve_softc *);
373e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_setup_socket(struct geneve_softc *);
374e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_setup_interface_hdrlen(struct geneve_softc *);
375e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_valid_init_config(struct geneve_softc *);
376e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_init_complete(struct geneve_softc *);
377e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_init(void *);
378e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_release(struct geneve_softc *);
379e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_teardown_wait(struct geneve_softc *);
380e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_teardown_locked(struct geneve_softc *);
381e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_teardown(struct geneve_softc *);
382e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_timer(void *);
383e44d2e94SPouria Mousavizadeh Tehrani 
384e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_flush_ftable(struct geneve_softc *, bool);
385e44d2e94SPouria Mousavizadeh Tehrani static uint16_t	geneve_get_local_port(struct geneve_softc *);
386e44d2e94SPouria Mousavizadeh Tehrani static uint16_t	geneve_get_remote_port(struct geneve_softc *);
387e44d2e94SPouria Mousavizadeh Tehrani 
388e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_vni_nl(struct geneve_softc *, struct nl_pstate *,
389e44d2e94SPouria Mousavizadeh Tehrani 		    uint32_t);
390e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_local_addr_nl(struct geneve_softc *, struct nl_pstate *,
391e44d2e94SPouria Mousavizadeh Tehrani 		    struct sockaddr *);
392e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_remote_addr_nl(struct geneve_softc *, struct nl_pstate *,
393e44d2e94SPouria Mousavizadeh Tehrani 		    struct sockaddr *);
394e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_local_port_nl(struct geneve_softc *, struct nl_pstate *,
395e44d2e94SPouria Mousavizadeh Tehrani 		    uint16_t);
396e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_remote_port_nl(struct geneve_softc *, struct nl_pstate *,
397e44d2e94SPouria Mousavizadeh Tehrani 		    uint16_t);
398e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_port_range_nl(struct geneve_softc *, struct nl_pstate *,
399e44d2e94SPouria Mousavizadeh Tehrani 		    struct ifla_geneve_port_range);
400e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_df_nl(struct geneve_softc *, struct nl_pstate *,
401e44d2e94SPouria Mousavizadeh Tehrani 		    enum ifla_geneve_df);
402e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_ttl_nl(struct geneve_softc *, struct nl_pstate *,
403e44d2e94SPouria Mousavizadeh Tehrani 		    uint8_t);
404e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_ttl_inherit_nl(struct geneve_softc *, struct nl_pstate *,
405e44d2e94SPouria Mousavizadeh Tehrani 		    bool);
406e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_dscp_inherit_nl(struct geneve_softc *, struct nl_pstate *,
407e44d2e94SPouria Mousavizadeh Tehrani 		    bool);
408e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_collect_metadata_nl(struct geneve_softc *,
409e44d2e94SPouria Mousavizadeh Tehrani 		    struct nl_pstate *, bool);
410e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_learn_nl(struct geneve_softc *, struct nl_pstate *,
411e44d2e94SPouria Mousavizadeh Tehrani 		    bool);
412e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_ftable_max_nl(struct geneve_softc *, struct nl_pstate *,
413e44d2e94SPouria Mousavizadeh Tehrani 		    uint32_t);
414e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_ftable_timeout_nl(struct geneve_softc *,
415e44d2e94SPouria Mousavizadeh Tehrani 		    struct nl_pstate *, uint32_t);
416e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_mc_if_nl(struct geneve_softc *, struct nl_pstate *,
417e44d2e94SPouria Mousavizadeh Tehrani 		    char *);
418e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_flush_ftable_nl(struct geneve_softc *, struct nl_pstate *,
419e44d2e94SPouria Mousavizadeh Tehrani 		    bool);
420e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_get_local_addr_nl(struct geneve_softc *, struct nl_writer *);
421e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_get_remote_addr_nl(struct geneve_softc *, struct nl_writer *);
422e44d2e94SPouria Mousavizadeh Tehrani 
423e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_ioctl_ifflags(struct geneve_softc *);
424e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_ioctl(struct ifnet *, u_long, caddr_t);
425e44d2e94SPouria Mousavizadeh Tehrani 
426e44d2e94SPouria Mousavizadeh Tehrani static uint16_t geneve_pick_source_port(struct geneve_softc *, struct mbuf *);
427e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_encap_header(struct geneve_softc *, struct mbuf *,
428e44d2e94SPouria Mousavizadeh Tehrani 		    int, uint16_t, uint16_t, uint16_t);
429e44d2e94SPouria Mousavizadeh Tehrani static uint16_t	geneve_get_ethertype(struct mbuf *);
430e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_inherit_l3_hdr(struct mbuf *, struct geneve_softc *,
431e44d2e94SPouria Mousavizadeh Tehrani 		    uint16_t, uint8_t *, uint8_t *, u_short *);
432*f4e5b45bSJohn Baldwin #ifdef INET
433e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_encap4(struct geneve_softc *,
434e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, struct mbuf *);
435*f4e5b45bSJohn Baldwin #endif
436*f4e5b45bSJohn Baldwin #ifdef INET6
437e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_encap6(struct geneve_softc *,
438e44d2e94SPouria Mousavizadeh Tehrani 		    const union sockaddr_union *, struct mbuf *);
439*f4e5b45bSJohn Baldwin #endif
440e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_transmit(struct ifnet *, struct mbuf *);
441e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_qflush(struct ifnet *);
442e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_output(struct ifnet *, struct mbuf *,
443e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *, struct route *);
444e44d2e94SPouria Mousavizadeh Tehrani static uint32_t	geneve_map_etype_to_af(uint32_t);
445e44d2e94SPouria Mousavizadeh Tehrani static bool	geneve_udp_input(struct mbuf *, int, struct inpcb *,
446e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *, void *);
447e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_input_ether(struct geneve_softc *, struct mbuf **,
448e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *, struct geneve_pkt_info *);
449e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_input_inherit(struct geneve_softc *,
450e44d2e94SPouria Mousavizadeh Tehrani 		    struct mbuf **, int, struct geneve_pkt_info *);
451e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_next_option(struct geneve_socket *, struct genevehdr *,
452e44d2e94SPouria Mousavizadeh Tehrani 		    struct mbuf **);
453e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_input_csum(struct mbuf *m, struct ifnet *ifp,
454e44d2e94SPouria Mousavizadeh Tehrani 		    counter_u64_t rxcsum);
455e44d2e94SPouria Mousavizadeh Tehrani 
456e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_stats_alloc(struct geneve_softc *);
457e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_stats_free(struct geneve_softc *);
458e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_set_default_config(struct geneve_softc *);
459e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_set_reqcap(struct geneve_softc *, struct ifnet *, int,
460e44d2e94SPouria Mousavizadeh Tehrani 		    int);
461e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_set_hwcaps(struct geneve_softc *);
462e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_clone_create(struct if_clone *, char *, size_t,
463e44d2e94SPouria Mousavizadeh Tehrani 		    struct ifc_data *, struct ifnet **);
464e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_clone_destroy(struct if_clone *, struct ifnet *,
465e44d2e94SPouria Mousavizadeh Tehrani 		    uint32_t);
466e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_clone_create_nl(struct if_clone *, char *, size_t,
467e44d2e94SPouria Mousavizadeh Tehrani 		    struct ifc_data_nl *);
468e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_clone_modify_nl(struct ifnet *, struct ifc_data_nl *);
469e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_clone_dump_nl(struct ifnet *, struct nl_writer *);
470e44d2e94SPouria Mousavizadeh Tehrani 
471e44d2e94SPouria Mousavizadeh Tehrani static uint32_t geneve_mac_hash(struct geneve_softc *, const uint8_t *);
472e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_media_change(struct ifnet *);
473e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_media_status(struct ifnet *, struct ifmediareq *);
474e44d2e94SPouria Mousavizadeh Tehrani 
475e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_sockaddr_cmp(const union sockaddr_union *,
476e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *);
477e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_sockaddr_copy(union sockaddr_union *,
478e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *);
479e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_sockaddr_in_equal(const union sockaddr_union *,
480e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *);
481e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_sockaddr_in_copy(union sockaddr_union *,
482e44d2e94SPouria Mousavizadeh Tehrani 		    const struct sockaddr *);
483e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_sockaddr_supported(const union sockaddr_union *, int);
484e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_sockaddr_in_any(const union sockaddr_union *);
485e44d2e94SPouria Mousavizadeh Tehrani 
486e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_can_change_config(struct geneve_softc *);
487e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_check_proto(uint16_t);
488e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_check_multicast_addr(const union sockaddr_union *);
489e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_check_sockaddr(const union sockaddr_union *, const int);
490e44d2e94SPouria Mousavizadeh Tehrani 
491e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_prison_remove(void *, void *);
492e44d2e94SPouria Mousavizadeh Tehrani static void	vnet_geneve_load(void);
493e44d2e94SPouria Mousavizadeh Tehrani static void	vnet_geneve_unload(void);
494e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_module_init(void);
495e44d2e94SPouria Mousavizadeh Tehrani static void	geneve_module_deinit(void);
496e44d2e94SPouria Mousavizadeh Tehrani static int	geneve_modevent(module_t, int, void *);
497e44d2e94SPouria Mousavizadeh Tehrani 
498e44d2e94SPouria Mousavizadeh Tehrani 
499e44d2e94SPouria Mousavizadeh Tehrani static const char geneve_name[] = "geneve";
500e44d2e94SPouria Mousavizadeh Tehrani static MALLOC_DEFINE(M_GENEVE, geneve_name,
501e44d2e94SPouria Mousavizadeh Tehrani     "Generic Network Virtualization Encapsulation Interface");
502e44d2e94SPouria Mousavizadeh Tehrani #define MTAG_GENEVE_LOOP	0x93d66dc0 /* geneve mtag */
503e44d2e94SPouria Mousavizadeh Tehrani 
504e44d2e94SPouria Mousavizadeh Tehrani VNET_DEFINE_STATIC(struct if_clone *, geneve_cloner);
505e44d2e94SPouria Mousavizadeh Tehrani #define	V_geneve_cloner	VNET(geneve_cloner)
506e44d2e94SPouria Mousavizadeh Tehrani 
507e44d2e94SPouria Mousavizadeh Tehrani static struct mtx geneve_list_mtx;
508e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_LIST_LOCK()	mtx_lock(&geneve_list_mtx)
509e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_LIST_UNLOCK()	mtx_unlock(&geneve_list_mtx)
510e44d2e94SPouria Mousavizadeh Tehrani 
511e44d2e94SPouria Mousavizadeh Tehrani static LIST_HEAD(, geneve_socket) geneve_socket_list = LIST_HEAD_INITIALIZER(geneve_socket_list);
512e44d2e94SPouria Mousavizadeh Tehrani 
513e44d2e94SPouria Mousavizadeh Tehrani /* Default maximum number of addresses in the forwarding table. */
514e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FTABLE_MAX	2000
515e44d2e94SPouria Mousavizadeh Tehrani 
516e44d2e94SPouria Mousavizadeh Tehrani /* Timeout (in seconds) of addresses learned in the forwarding table. */
517e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FTABLE_TIMEOUT	(20 * 60)
518e44d2e94SPouria Mousavizadeh Tehrani 
519e44d2e94SPouria Mousavizadeh Tehrani /* Maximum timeout (in seconds) of addresses learned in the forwarding table. */
520e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FTABLE_MAX_TIMEOUT	(60 * 60 * 24)
521e44d2e94SPouria Mousavizadeh Tehrani 
522e44d2e94SPouria Mousavizadeh Tehrani /* Number of seconds between pruning attempts of the forwarding table. */
523e44d2e94SPouria Mousavizadeh Tehrani #define GENEVE_FTABLE_PRUNE	(5 * 60)
524e44d2e94SPouria Mousavizadeh Tehrani 
525e44d2e94SPouria Mousavizadeh Tehrani static int geneve_ftable_prune_period = GENEVE_FTABLE_PRUNE;
526e44d2e94SPouria Mousavizadeh Tehrani 
527e44d2e94SPouria Mousavizadeh Tehrani #define _OUT(_field)	offsetof(struct nl_parsed_geneve, _field)
528e44d2e94SPouria Mousavizadeh Tehrani static const struct nlattr_parser nla_p_geneve_create[] = {
529e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_PROTOCOL, .off = _OUT(ifla_proto), .cb = nlattr_get_uint16 },
530e44d2e94SPouria Mousavizadeh Tehrani };
531e44d2e94SPouria Mousavizadeh Tehrani #undef _OUT
532e44d2e94SPouria Mousavizadeh Tehrani NL_DECLARE_ATTR_PARSER(geneve_create_parser, nla_p_geneve_create);
533e44d2e94SPouria Mousavizadeh Tehrani 
534e44d2e94SPouria Mousavizadeh Tehrani #define _OUT(_field)	offsetof(struct nl_parsed_geneve, _field)
535e44d2e94SPouria Mousavizadeh Tehrani static const struct nlattr_parser nla_p_geneve[] = {
536e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_ID, .off = _OUT(ifla_vni), .cb = nlattr_get_uint32 },
537e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_PROTOCOL, .off = _OUT(ifla_proto), .cb = nlattr_get_uint16 },
538e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_LOCAL, .off = _OUT(ifla_local), .cb = nlattr_get_ip },
539e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_REMOTE, .off = _OUT(ifla_remote), .cb = nlattr_get_ip },
540e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_LOCAL_PORT, .off = _OUT(ifla_local_port), .cb = nlattr_get_uint16 },
541e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_PORT, .off = _OUT(ifla_remote_port), .cb = nlattr_get_uint16 },
542e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_PORT_RANGE, .off = _OUT(ifla_port_range),
543e44d2e94SPouria Mousavizadeh Tehrani 		.arg = (void *)sizeof(struct ifla_geneve_port_range), .cb = nlattr_get_bytes },
544e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_DF, .off = _OUT(ifla_df), .cb = nlattr_get_uint8 },
545e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_TTL, .off = _OUT(ifla_ttl), .cb = nlattr_get_uint8 },
546e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_TTL_INHERIT, .off = _OUT(ifla_ttl_inherit), .cb = nlattr_get_bool },
547e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_DSCP_INHERIT, .off = _OUT(ifla_dscp_inherit), .cb = nlattr_get_bool },
548e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_COLLECT_METADATA, .off = _OUT(ifla_external), .cb = nlattr_get_bool },
549e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_FTABLE_LEARN, .off = _OUT(ifla_ftable_learn), .cb = nlattr_get_bool },
550e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_FTABLE_FLUSH, .off = _OUT(ifla_ftable_flush), .cb = nlattr_get_bool },
551e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_FTABLE_MAX, .off = _OUT(ifla_ftable_max), .cb = nlattr_get_uint32 },
552e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_FTABLE_TIMEOUT, .off = _OUT(ifla_ftable_timeout), .cb = nlattr_get_uint32 },
553e44d2e94SPouria Mousavizadeh Tehrani 	{ .type = IFLA_GENEVE_MC_IFNAME, .off = _OUT(ifla_mc_ifname), .cb = nlattr_get_string },
554e44d2e94SPouria Mousavizadeh Tehrani };
555e44d2e94SPouria Mousavizadeh Tehrani #undef _OUT
556e44d2e94SPouria Mousavizadeh Tehrani NL_DECLARE_ATTR_PARSER(geneve_modify_parser, nla_p_geneve);
557e44d2e94SPouria Mousavizadeh Tehrani 
558e44d2e94SPouria Mousavizadeh Tehrani static const struct nlhdr_parser *all_parsers[] = {
559e44d2e94SPouria Mousavizadeh Tehrani 	&geneve_create_parser, &geneve_modify_parser,
560e44d2e94SPouria Mousavizadeh Tehrani };
561e44d2e94SPouria Mousavizadeh Tehrani 
562e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_ftable_addr_cmp(const uint8_t * a,const uint8_t * b)563e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_addr_cmp(const uint8_t *a, const uint8_t *b)
564e44d2e94SPouria Mousavizadeh Tehrani {
565e44d2e94SPouria Mousavizadeh Tehrani 	int i, d;
566e44d2e94SPouria Mousavizadeh Tehrani 
567e44d2e94SPouria Mousavizadeh Tehrani 	for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++)
568e44d2e94SPouria Mousavizadeh Tehrani 		d = (int)a[i] - (int)b[i];
569e44d2e94SPouria Mousavizadeh Tehrani 
570e44d2e94SPouria Mousavizadeh Tehrani 	return (d);
571e44d2e94SPouria Mousavizadeh Tehrani }
572e44d2e94SPouria Mousavizadeh Tehrani 
573e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_init(struct geneve_softc * sc)574e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_init(struct geneve_softc *sc)
575e44d2e94SPouria Mousavizadeh Tehrani {
576e44d2e94SPouria Mousavizadeh Tehrani 	int i;
577e44d2e94SPouria Mousavizadeh Tehrani 
578e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable = malloc(sizeof(struct geneve_ftable_head) *
579e44d2e94SPouria Mousavizadeh Tehrani 	    GENEVE_SC_FTABLE_SIZE, M_GENEVE, M_ZERO | M_WAITOK);
580e44d2e94SPouria Mousavizadeh Tehrani 
581e44d2e94SPouria Mousavizadeh Tehrani 	for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++)
582e44d2e94SPouria Mousavizadeh Tehrani 		LIST_INIT(&sc->gnv_ftable[i]);
583e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable_hash_key = arc4random();
584e44d2e94SPouria Mousavizadeh Tehrani }
585e44d2e94SPouria Mousavizadeh Tehrani 
586e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_fini(struct geneve_softc * sc)587e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_fini(struct geneve_softc *sc)
588e44d2e94SPouria Mousavizadeh Tehrani {
589e44d2e94SPouria Mousavizadeh Tehrani 	int i;
590e44d2e94SPouria Mousavizadeh Tehrani 
591e44d2e94SPouria Mousavizadeh Tehrani 	for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
592e44d2e94SPouria Mousavizadeh Tehrani 		KASSERT(LIST_EMPTY(&sc->gnv_ftable[i]),
593e44d2e94SPouria Mousavizadeh Tehrani 		    ("%s: geneve %p ftable[%d] not empty", __func__, sc, i));
594e44d2e94SPouria Mousavizadeh Tehrani 	}
595e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(sc->gnv_ftable_cnt == 0);
596e44d2e94SPouria Mousavizadeh Tehrani 
597e44d2e94SPouria Mousavizadeh Tehrani 	free(sc->gnv_ftable, M_GENEVE);
598e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable = NULL;
599e44d2e94SPouria Mousavizadeh Tehrani }
600e44d2e94SPouria Mousavizadeh Tehrani 
601e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_flush(struct geneve_softc * sc,int all)602e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_flush(struct geneve_softc *sc, int all)
603e44d2e94SPouria Mousavizadeh Tehrani {
604e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *fe, *tfe;
605e44d2e94SPouria Mousavizadeh Tehrani 
606e44d2e94SPouria Mousavizadeh Tehrani 	for (int i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
607e44d2e94SPouria Mousavizadeh Tehrani 		LIST_FOREACH_SAFE(fe, &sc->gnv_ftable[i], gnvfe_hash, tfe) {
608e44d2e94SPouria Mousavizadeh Tehrani 			if (all || GENEVE_FE_IS_DYNAMIC(fe))
609e44d2e94SPouria Mousavizadeh Tehrani 				geneve_ftable_entry_destroy(sc, fe);
610e44d2e94SPouria Mousavizadeh Tehrani 		}
611e44d2e94SPouria Mousavizadeh Tehrani 	}
612e44d2e94SPouria Mousavizadeh Tehrani }
613e44d2e94SPouria Mousavizadeh Tehrani 
614e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_expire(struct geneve_softc * sc)615e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_expire(struct geneve_softc *sc)
616e44d2e94SPouria Mousavizadeh Tehrani {
617e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *fe, *tfe;
618e44d2e94SPouria Mousavizadeh Tehrani 
619e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_WASSERT(sc);
620e44d2e94SPouria Mousavizadeh Tehrani 
621e44d2e94SPouria Mousavizadeh Tehrani 	for (int i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
622e44d2e94SPouria Mousavizadeh Tehrani 		LIST_FOREACH_SAFE(fe, &sc->gnv_ftable[i], gnvfe_hash, tfe) {
623e44d2e94SPouria Mousavizadeh Tehrani 			if (GENEVE_FE_IS_DYNAMIC(fe) &&
624e44d2e94SPouria Mousavizadeh Tehrani 			    time_uptime >= fe->gnvfe_expire)
625e44d2e94SPouria Mousavizadeh Tehrani 				geneve_ftable_entry_destroy(sc, fe);
626e44d2e94SPouria Mousavizadeh Tehrani 		}
627e44d2e94SPouria Mousavizadeh Tehrani 	}
628e44d2e94SPouria Mousavizadeh Tehrani }
629e44d2e94SPouria Mousavizadeh Tehrani 
630e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_ftable_update_locked(struct geneve_softc * sc,const union sockaddr_union * unsa,const uint8_t * mac,struct rm_priotracker * tracker)631e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_update_locked(struct geneve_softc *sc,
632e44d2e94SPouria Mousavizadeh Tehrani     const union sockaddr_union *unsa, const uint8_t *mac,
633e44d2e94SPouria Mousavizadeh Tehrani     struct rm_priotracker *tracker)
634e44d2e94SPouria Mousavizadeh Tehrani {
635e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *fe;
636e44d2e94SPouria Mousavizadeh Tehrani 	int error;
637e44d2e94SPouria Mousavizadeh Tehrani 
638e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
639e44d2e94SPouria Mousavizadeh Tehrani 
640e44d2e94SPouria Mousavizadeh Tehrani again:
641e44d2e94SPouria Mousavizadeh Tehrani 	/*
642e44d2e94SPouria Mousavizadeh Tehrani 	 * A forwarding entry for this MAC address might already exist. If
643e44d2e94SPouria Mousavizadeh Tehrani 	 * so, update it, otherwise create a new one. We may have to upgrade
644e44d2e94SPouria Mousavizadeh Tehrani 	 * the lock if we have to change or create an entry.
645e44d2e94SPouria Mousavizadeh Tehrani 	 */
646e44d2e94SPouria Mousavizadeh Tehrani 	fe = geneve_ftable_entry_lookup(sc, mac);
647e44d2e94SPouria Mousavizadeh Tehrani 	if (fe != NULL) {
648e44d2e94SPouria Mousavizadeh Tehrani 		fe->gnvfe_expire = time_uptime + sc->gnv_ftable_timeout;
649e44d2e94SPouria Mousavizadeh Tehrani 
650e44d2e94SPouria Mousavizadeh Tehrani 		if (!GENEVE_FE_IS_DYNAMIC(fe) ||
651e44d2e94SPouria Mousavizadeh Tehrani 		    geneve_sockaddr_in_equal(&fe->gnvfe_raddr, &unsa->sa))
652e44d2e94SPouria Mousavizadeh Tehrani 			return (0);
653e44d2e94SPouria Mousavizadeh Tehrani 		if (!GENEVE_LOCK_WOWNED(sc)) {
654e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_RUNLOCK(sc, tracker);
655e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_WLOCK(sc);
656e44d2e94SPouria Mousavizadeh Tehrani 			sc->gnv_stats.ftable_lock_upgrade_failed++;
657e44d2e94SPouria Mousavizadeh Tehrani 			goto again;
658e44d2e94SPouria Mousavizadeh Tehrani 		}
659e44d2e94SPouria Mousavizadeh Tehrani 		geneve_sockaddr_in_copy(&fe->gnvfe_raddr, &unsa->sa);
660e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
661e44d2e94SPouria Mousavizadeh Tehrani 	}
662e44d2e94SPouria Mousavizadeh Tehrani 
663e44d2e94SPouria Mousavizadeh Tehrani 	if (!GENEVE_LOCK_WOWNED(sc)) {
664e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_RUNLOCK(sc, tracker);
665e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WLOCK(sc);
666e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_stats.ftable_lock_upgrade_failed++;
667e44d2e94SPouria Mousavizadeh Tehrani 		goto again;
668e44d2e94SPouria Mousavizadeh Tehrani 	}
669e44d2e94SPouria Mousavizadeh Tehrani 
670e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_ftable_cnt >= sc->gnv_ftable_max) {
671e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_stats.ftable_nospace++;
672e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOSPC);
673e44d2e94SPouria Mousavizadeh Tehrani 	}
674e44d2e94SPouria Mousavizadeh Tehrani 
675e44d2e94SPouria Mousavizadeh Tehrani 	fe = geneve_ftable_entry_alloc();
676e44d2e94SPouria Mousavizadeh Tehrani 	if (fe == NULL)
677e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOMEM);
678e44d2e94SPouria Mousavizadeh Tehrani 
679e44d2e94SPouria Mousavizadeh Tehrani 	geneve_ftable_entry_init(sc, fe, mac, &unsa->sa, GENEVE_FE_FLAG_DYNAMIC);
680e44d2e94SPouria Mousavizadeh Tehrani 
681e44d2e94SPouria Mousavizadeh Tehrani 	/* The prior lookup failed, so the insert should not. */
682e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_ftable_entry_insert(sc, fe);
683e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(error == 0);
684e44d2e94SPouria Mousavizadeh Tehrani 
685e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
686e44d2e94SPouria Mousavizadeh Tehrani }
687e44d2e94SPouria Mousavizadeh Tehrani 
688e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_ftable_learn(struct geneve_softc * sc,const struct sockaddr * sa,const uint8_t * mac)689e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_learn(struct geneve_softc *sc, const struct sockaddr *sa,
690e44d2e94SPouria Mousavizadeh Tehrani     const uint8_t *mac)
691e44d2e94SPouria Mousavizadeh Tehrani {
692e44d2e94SPouria Mousavizadeh Tehrani 	struct rm_priotracker tracker;
693e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union unsa;
694e44d2e94SPouria Mousavizadeh Tehrani 	int error;
695e44d2e94SPouria Mousavizadeh Tehrani 
696e44d2e94SPouria Mousavizadeh Tehrani 	/*
697e44d2e94SPouria Mousavizadeh Tehrani 	 * The source port may be randomly selected by the remote host, so
698e44d2e94SPouria Mousavizadeh Tehrani 	 * use the port of the default destination address.
699e44d2e94SPouria Mousavizadeh Tehrani 	 */
700e44d2e94SPouria Mousavizadeh Tehrani 	geneve_sockaddr_copy(&unsa, sa);
701e44d2e94SPouria Mousavizadeh Tehrani 	unsa.sin.sin_port = sc->gnv_dst_addr.sin.sin_port;
702e44d2e94SPouria Mousavizadeh Tehrani 
703*f4e5b45bSJohn Baldwin #ifdef INET6
704e44d2e94SPouria Mousavizadeh Tehrani 	if (unsa.sa.sa_family == AF_INET6) {
705e44d2e94SPouria Mousavizadeh Tehrani 		error = sa6_embedscope(&unsa.sin6, V_ip6_use_defzone);
706e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
707e44d2e94SPouria Mousavizadeh Tehrani 			return (error);
708e44d2e94SPouria Mousavizadeh Tehrani 	}
709*f4e5b45bSJohn Baldwin #endif
710e44d2e94SPouria Mousavizadeh Tehrani 
711e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_RLOCK(sc, &tracker);
712e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_ftable_update_locked(sc, &unsa, mac, &tracker);
713e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_UNLOCK(sc, &tracker);
714e44d2e94SPouria Mousavizadeh Tehrani 
715e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
716e44d2e94SPouria Mousavizadeh Tehrani }
717e44d2e94SPouria Mousavizadeh Tehrani 
718e44d2e94SPouria Mousavizadeh Tehrani static struct gnv_ftable_entry *
geneve_ftable_entry_alloc(void)719e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_entry_alloc(void)
720e44d2e94SPouria Mousavizadeh Tehrani {
721e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *fe;
722e44d2e94SPouria Mousavizadeh Tehrani 
723e44d2e94SPouria Mousavizadeh Tehrani 	fe = malloc(sizeof(*fe), M_GENEVE, M_ZERO | M_NOWAIT);
724e44d2e94SPouria Mousavizadeh Tehrani 
725e44d2e94SPouria Mousavizadeh Tehrani 	return (fe);
726e44d2e94SPouria Mousavizadeh Tehrani }
727e44d2e94SPouria Mousavizadeh Tehrani 
728e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_entry_free(struct gnv_ftable_entry * fe)729e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_entry_free(struct gnv_ftable_entry *fe)
730e44d2e94SPouria Mousavizadeh Tehrani {
731e44d2e94SPouria Mousavizadeh Tehrani 
732e44d2e94SPouria Mousavizadeh Tehrani 	free(fe, M_GENEVE);
733e44d2e94SPouria Mousavizadeh Tehrani }
734e44d2e94SPouria Mousavizadeh Tehrani 
735e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_entry_init(struct geneve_softc * sc,struct gnv_ftable_entry * fe,const uint8_t * mac,const struct sockaddr * sa,uint32_t flags)736e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_entry_init(struct geneve_softc *sc, struct gnv_ftable_entry *fe,
737e44d2e94SPouria Mousavizadeh Tehrani     const uint8_t *mac, const struct sockaddr *sa, uint32_t flags)
738e44d2e94SPouria Mousavizadeh Tehrani {
739e44d2e94SPouria Mousavizadeh Tehrani 
740e44d2e94SPouria Mousavizadeh Tehrani 	fe->gnvfe_flags = flags;
741e44d2e94SPouria Mousavizadeh Tehrani 	fe->gnvfe_expire = time_uptime + sc->gnv_ftable_timeout;
742e44d2e94SPouria Mousavizadeh Tehrani 	memcpy(fe->gnvfe_mac, mac, ETHER_ADDR_LEN);
743e44d2e94SPouria Mousavizadeh Tehrani 	geneve_sockaddr_copy(&fe->gnvfe_raddr, sa);
744e44d2e94SPouria Mousavizadeh Tehrani }
745e44d2e94SPouria Mousavizadeh Tehrani 
746e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_ftable_entry_destroy(struct geneve_softc * sc,struct gnv_ftable_entry * fe)747e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_entry_destroy(struct geneve_softc *sc,
748e44d2e94SPouria Mousavizadeh Tehrani     struct gnv_ftable_entry *fe)
749e44d2e94SPouria Mousavizadeh Tehrani {
750e44d2e94SPouria Mousavizadeh Tehrani 
751e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable_cnt--;
752e44d2e94SPouria Mousavizadeh Tehrani 	LIST_REMOVE(fe, gnvfe_hash);
753e44d2e94SPouria Mousavizadeh Tehrani 	geneve_ftable_entry_free(fe);
754e44d2e94SPouria Mousavizadeh Tehrani }
755e44d2e94SPouria Mousavizadeh Tehrani 
756e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_ftable_entry_insert(struct geneve_softc * sc,struct gnv_ftable_entry * fe)757e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_entry_insert(struct geneve_softc *sc,
758e44d2e94SPouria Mousavizadeh Tehrani     struct gnv_ftable_entry *fe)
759e44d2e94SPouria Mousavizadeh Tehrani {
760e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *lfe;
761e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t hash;
762e44d2e94SPouria Mousavizadeh Tehrani 	int dir;
763e44d2e94SPouria Mousavizadeh Tehrani 
764e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_WASSERT(sc);
765e44d2e94SPouria Mousavizadeh Tehrani 	hash = GENEVE_SC_FTABLE_HASH(sc, fe->gnvfe_mac);
766e44d2e94SPouria Mousavizadeh Tehrani 
767e44d2e94SPouria Mousavizadeh Tehrani 	lfe = LIST_FIRST(&sc->gnv_ftable[hash]);
768e44d2e94SPouria Mousavizadeh Tehrani 	if (lfe == NULL) {
769e44d2e94SPouria Mousavizadeh Tehrani 		LIST_INSERT_HEAD(&sc->gnv_ftable[hash], fe, gnvfe_hash);
770e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
771e44d2e94SPouria Mousavizadeh Tehrani 	}
772e44d2e94SPouria Mousavizadeh Tehrani 
773e44d2e94SPouria Mousavizadeh Tehrani 	do {
774e44d2e94SPouria Mousavizadeh Tehrani 		dir = geneve_ftable_addr_cmp(fe->gnvfe_mac, lfe->gnvfe_mac);
775e44d2e94SPouria Mousavizadeh Tehrani 		if (dir == 0)
776e44d2e94SPouria Mousavizadeh Tehrani 			return (EEXIST);
777e44d2e94SPouria Mousavizadeh Tehrani 		if (dir > 0) {
778e44d2e94SPouria Mousavizadeh Tehrani 			LIST_INSERT_BEFORE(lfe, fe, gnvfe_hash);
779e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
780e44d2e94SPouria Mousavizadeh Tehrani 		} else if (LIST_NEXT(lfe, gnvfe_hash) == NULL) {
781e44d2e94SPouria Mousavizadeh Tehrani 			LIST_INSERT_AFTER(lfe, fe, gnvfe_hash);
782e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
783e44d2e94SPouria Mousavizadeh Tehrani 		} else
784e44d2e94SPouria Mousavizadeh Tehrani 			lfe = LIST_NEXT(lfe, gnvfe_hash);
785e44d2e94SPouria Mousavizadeh Tehrani 	} while (lfe != NULL);
786e44d2e94SPouria Mousavizadeh Tehrani 
787e44d2e94SPouria Mousavizadeh Tehrani out:
788e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable_cnt++;
789e44d2e94SPouria Mousavizadeh Tehrani 
790e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
791e44d2e94SPouria Mousavizadeh Tehrani }
792e44d2e94SPouria Mousavizadeh Tehrani 
793e44d2e94SPouria Mousavizadeh Tehrani static struct gnv_ftable_entry *
geneve_ftable_entry_lookup(struct geneve_softc * sc,const uint8_t * mac)794e44d2e94SPouria Mousavizadeh Tehrani geneve_ftable_entry_lookup(struct geneve_softc *sc, const uint8_t *mac)
795e44d2e94SPouria Mousavizadeh Tehrani {
796e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *fe;
797e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t hash;
798e44d2e94SPouria Mousavizadeh Tehrani 	int dir;
799e44d2e94SPouria Mousavizadeh Tehrani 
800e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
801e44d2e94SPouria Mousavizadeh Tehrani 
802e44d2e94SPouria Mousavizadeh Tehrani 	hash = GENEVE_SC_FTABLE_HASH(sc, mac);
803e44d2e94SPouria Mousavizadeh Tehrani 	LIST_FOREACH(fe, &sc->gnv_ftable[hash], gnvfe_hash) {
804e44d2e94SPouria Mousavizadeh Tehrani 		dir = geneve_ftable_addr_cmp(mac, fe->gnvfe_mac);
805e44d2e94SPouria Mousavizadeh Tehrani 		if (dir == 0)
806e44d2e94SPouria Mousavizadeh Tehrani 			return (fe);
807e44d2e94SPouria Mousavizadeh Tehrani 		if (dir > 0)
808e44d2e94SPouria Mousavizadeh Tehrani 			break;
809e44d2e94SPouria Mousavizadeh Tehrani 	}
810e44d2e94SPouria Mousavizadeh Tehrani 
811e44d2e94SPouria Mousavizadeh Tehrani 	return (NULL);
812e44d2e94SPouria Mousavizadeh Tehrani }
813e44d2e94SPouria Mousavizadeh Tehrani 
814e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_socket *
geneve_socket_alloc(union sockaddr_union * laddr)815e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_alloc(union sockaddr_union *laddr)
816e44d2e94SPouria Mousavizadeh Tehrani {
817e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket *gnvso;
818e44d2e94SPouria Mousavizadeh Tehrani 
819e44d2e94SPouria Mousavizadeh Tehrani 	gnvso = malloc(sizeof(*gnvso), M_GENEVE, M_WAITOK | M_ZERO);
820e44d2e94SPouria Mousavizadeh Tehrani 	rm_init(&gnvso->gnvso_lock, "genevesorm");
821e44d2e94SPouria Mousavizadeh Tehrani 	refcount_init(&gnvso->gnvso_refcnt, 0);
822e44d2e94SPouria Mousavizadeh Tehrani 	for (int i = 0; i < GENEVE_SO_VNI_HASH_SIZE; i++)
823e44d2e94SPouria Mousavizadeh Tehrani 		LIST_INIT(&gnvso->gnvso_vni_hash[i]);
824e44d2e94SPouria Mousavizadeh Tehrani 	gnvso->gnvso_laddr = *laddr;
825e44d2e94SPouria Mousavizadeh Tehrani 
826e44d2e94SPouria Mousavizadeh Tehrani 	return (gnvso);
827e44d2e94SPouria Mousavizadeh Tehrani }
828e44d2e94SPouria Mousavizadeh Tehrani 
829e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_socket_destroy(struct geneve_socket * gnvso)830e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_destroy(struct geneve_socket *gnvso)
831e44d2e94SPouria Mousavizadeh Tehrani {
832e44d2e94SPouria Mousavizadeh Tehrani 	struct socket *so;
833e44d2e94SPouria Mousavizadeh Tehrani 
834e44d2e94SPouria Mousavizadeh Tehrani 	so = gnvso->gnvso_sock;
835e44d2e94SPouria Mousavizadeh Tehrani 	if (so != NULL) {
836e44d2e94SPouria Mousavizadeh Tehrani 		gnvso->gnvso_sock = NULL;
837e44d2e94SPouria Mousavizadeh Tehrani 		soclose(so);
838e44d2e94SPouria Mousavizadeh Tehrani 	}
839e44d2e94SPouria Mousavizadeh Tehrani 
840e44d2e94SPouria Mousavizadeh Tehrani 	rm_destroy(&gnvso->gnvso_lock);
841e44d2e94SPouria Mousavizadeh Tehrani 	free(gnvso, M_GENEVE);
842e44d2e94SPouria Mousavizadeh Tehrani }
843e44d2e94SPouria Mousavizadeh Tehrani 
844e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_socket_release(struct geneve_socket * gnvso)845e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_release(struct geneve_socket *gnvso)
846e44d2e94SPouria Mousavizadeh Tehrani {
847e44d2e94SPouria Mousavizadeh Tehrani 	int destroy;
848e44d2e94SPouria Mousavizadeh Tehrani 
849e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LIST_LOCK();
850e44d2e94SPouria Mousavizadeh Tehrani 	destroy = GENEVE_SO_RELEASE(gnvso);
851e44d2e94SPouria Mousavizadeh Tehrani 	if (destroy != 0)
852e44d2e94SPouria Mousavizadeh Tehrani 		LIST_REMOVE(gnvso, gnvso_entry);
853e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LIST_UNLOCK();
854e44d2e94SPouria Mousavizadeh Tehrani 
855e44d2e94SPouria Mousavizadeh Tehrani 	if (destroy != 0)
856e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_destroy(gnvso);
857e44d2e94SPouria Mousavizadeh Tehrani }
858e44d2e94SPouria Mousavizadeh Tehrani 
859e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_socket *
geneve_socket_lookup(union sockaddr_union * unsa)860e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_lookup(union sockaddr_union *unsa)
861e44d2e94SPouria Mousavizadeh Tehrani {
862e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket *gnvso;
863e44d2e94SPouria Mousavizadeh Tehrani 
864e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LIST_LOCK();
865e44d2e94SPouria Mousavizadeh Tehrani 	LIST_FOREACH(gnvso, &geneve_socket_list, gnvso_entry) {
866e44d2e94SPouria Mousavizadeh Tehrani 		if (geneve_sockaddr_cmp(&gnvso->gnvso_laddr, &unsa->sa) == 0) {
867e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_SO_ACQUIRE(gnvso);
868e44d2e94SPouria Mousavizadeh Tehrani 			break;
869e44d2e94SPouria Mousavizadeh Tehrani 		}
870e44d2e94SPouria Mousavizadeh Tehrani 	}
871e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LIST_UNLOCK();
872e44d2e94SPouria Mousavizadeh Tehrani 
873e44d2e94SPouria Mousavizadeh Tehrani 	return (gnvso);
874e44d2e94SPouria Mousavizadeh Tehrani }
875e44d2e94SPouria Mousavizadeh Tehrani 
876e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_socket_insert(struct geneve_socket * gnvso)877e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_insert(struct geneve_socket *gnvso)
878e44d2e94SPouria Mousavizadeh Tehrani {
879e44d2e94SPouria Mousavizadeh Tehrani 
880e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LIST_LOCK();
881e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_ACQUIRE(gnvso);
882e44d2e94SPouria Mousavizadeh Tehrani 	LIST_INSERT_HEAD(&geneve_socket_list, gnvso, gnvso_entry);
883e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LIST_UNLOCK();
884e44d2e94SPouria Mousavizadeh Tehrani }
885e44d2e94SPouria Mousavizadeh Tehrani 
886e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_init(struct geneve_socket * gnvso,struct ifnet * ifp)887e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_init(struct geneve_socket *gnvso, struct ifnet *ifp)
888e44d2e94SPouria Mousavizadeh Tehrani {
889e44d2e94SPouria Mousavizadeh Tehrani 	struct thread *td;
890e44d2e94SPouria Mousavizadeh Tehrani 	int error;
891e44d2e94SPouria Mousavizadeh Tehrani 
892e44d2e94SPouria Mousavizadeh Tehrani 	td = curthread;
893e44d2e94SPouria Mousavizadeh Tehrani 	error = socreate(gnvso->gnvso_laddr.sa.sa_family, &gnvso->gnvso_sock,
894e44d2e94SPouria Mousavizadeh Tehrani 	    SOCK_DGRAM, IPPROTO_UDP, td->td_ucred, td);
895e44d2e94SPouria Mousavizadeh Tehrani 	if (error) {
896e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "cannot create socket: %d\n", error);
897e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
898e44d2e94SPouria Mousavizadeh Tehrani 	}
899e44d2e94SPouria Mousavizadeh Tehrani 
900e44d2e94SPouria Mousavizadeh Tehrani 	/*
901e44d2e94SPouria Mousavizadeh Tehrani 	 * XXX: If Geneve traffic is shared with other UDP listeners on
902e44d2e94SPouria Mousavizadeh Tehrani 	 * the same IP address, tunnel endpoints SHOULD implement a mechanism
903e44d2e94SPouria Mousavizadeh Tehrani 	 * to ensure ICMP return traffic arising from network errors is
904e44d2e94SPouria Mousavizadeh Tehrani 	 * directed to the correct listener. Unfortunately,
905e44d2e94SPouria Mousavizadeh Tehrani 	 * udp_set_kernel_tunneling does not handle icmp errors from transit
906e44d2e94SPouria Mousavizadeh Tehrani 	 * devices other than specified source.
907e44d2e94SPouria Mousavizadeh Tehrani 	 */
908e44d2e94SPouria Mousavizadeh Tehrani 	error = udp_set_kernel_tunneling(gnvso->gnvso_sock,
909e44d2e94SPouria Mousavizadeh Tehrani 	    geneve_udp_input, NULL, gnvso);
910e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
911e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "cannot set tunneling function: %d\n", error);
912e44d2e94SPouria Mousavizadeh Tehrani 
913e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
914e44d2e94SPouria Mousavizadeh Tehrani }
915e44d2e94SPouria Mousavizadeh Tehrani 
916e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_bind(struct geneve_socket * gnvso,struct ifnet * ifp)917e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_bind(struct geneve_socket *gnvso, struct ifnet *ifp)
918e44d2e94SPouria Mousavizadeh Tehrani {
919e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union laddr;
920e44d2e94SPouria Mousavizadeh Tehrani 	int error;
921e44d2e94SPouria Mousavizadeh Tehrani 
922e44d2e94SPouria Mousavizadeh Tehrani 	laddr = gnvso->gnvso_laddr;
923e44d2e94SPouria Mousavizadeh Tehrani 	error = sobind(gnvso->gnvso_sock, &laddr.sa, curthread);
924e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
925e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
926e44d2e94SPouria Mousavizadeh Tehrani 
927e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
928e44d2e94SPouria Mousavizadeh Tehrani }
929e44d2e94SPouria Mousavizadeh Tehrani 
930e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_create(struct ifnet * ifp,int multicast,const union sockaddr_union * unsa,struct geneve_socket ** xgnvso)931e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_create(struct ifnet *ifp, int multicast,
932e44d2e94SPouria Mousavizadeh Tehrani     const union sockaddr_union *unsa, struct geneve_socket **xgnvso)
933e44d2e94SPouria Mousavizadeh Tehrani {
934e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union laddr;
935e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket *gnvso;
936e44d2e94SPouria Mousavizadeh Tehrani 	int error;
937e44d2e94SPouria Mousavizadeh Tehrani 
938e44d2e94SPouria Mousavizadeh Tehrani 	laddr = *unsa;
939e44d2e94SPouria Mousavizadeh Tehrani 
940e44d2e94SPouria Mousavizadeh Tehrani 	/*
941e44d2e94SPouria Mousavizadeh Tehrani 	 * If this socket will be multicast, then only the local port
942e44d2e94SPouria Mousavizadeh Tehrani 	 * must be specified when binding.
943e44d2e94SPouria Mousavizadeh Tehrani 	 */
944e44d2e94SPouria Mousavizadeh Tehrani 	if (multicast != 0) {
945*f4e5b45bSJohn Baldwin 		switch (laddr.sa.sa_family) {
946*f4e5b45bSJohn Baldwin #ifdef INET
947*f4e5b45bSJohn Baldwin 		case AF_INET:
948e44d2e94SPouria Mousavizadeh Tehrani 			laddr.sin.sin_addr.s_addr = INADDR_ANY;
949*f4e5b45bSJohn Baldwin 			break;
950*f4e5b45bSJohn Baldwin #endif
951*f4e5b45bSJohn Baldwin #ifdef INET6
952*f4e5b45bSJohn Baldwin 		case AF_INET6:
953e44d2e94SPouria Mousavizadeh Tehrani 			laddr.sin6.sin6_addr = in6addr_any;
954*f4e5b45bSJohn Baldwin 			break;
955*f4e5b45bSJohn Baldwin #endif
956*f4e5b45bSJohn Baldwin 		default:
957*f4e5b45bSJohn Baldwin 			return (EAFNOSUPPORT);
958*f4e5b45bSJohn Baldwin 		}
959e44d2e94SPouria Mousavizadeh Tehrani 	}
960e44d2e94SPouria Mousavizadeh Tehrani 	gnvso = geneve_socket_alloc(&laddr);
961e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvso == NULL)
962e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOMEM);
963e44d2e94SPouria Mousavizadeh Tehrani 
964e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_socket_init(gnvso, ifp);
965e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
966e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
967e44d2e94SPouria Mousavizadeh Tehrani 
968e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_socket_bind(gnvso, ifp);
969e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
970e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
971e44d2e94SPouria Mousavizadeh Tehrani 
972e44d2e94SPouria Mousavizadeh Tehrani 	/*
973e44d2e94SPouria Mousavizadeh Tehrani 	 * There is a small window between the bind completing and
974e44d2e94SPouria Mousavizadeh Tehrani 	 * inserting the socket, so that a concurrent create may fail.
975e44d2e94SPouria Mousavizadeh Tehrani 	 * Let's not worry about that for now.
976e44d2e94SPouria Mousavizadeh Tehrani 	 */
977e44d2e94SPouria Mousavizadeh Tehrani 	if_printf(ifp, "new geneve socket inserted to socket list\n");
978e44d2e94SPouria Mousavizadeh Tehrani 	geneve_socket_insert(gnvso);
979e44d2e94SPouria Mousavizadeh Tehrani 	*xgnvso = gnvso;
980e44d2e94SPouria Mousavizadeh Tehrani 
981e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
982e44d2e94SPouria Mousavizadeh Tehrani 
983e44d2e94SPouria Mousavizadeh Tehrani fail:
984e44d2e94SPouria Mousavizadeh Tehrani 	if_printf(ifp, "can't create new socket (error: %d)\n", error);
985e44d2e94SPouria Mousavizadeh Tehrani 	geneve_socket_destroy(gnvso);
986e44d2e94SPouria Mousavizadeh Tehrani 
987e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
988e44d2e94SPouria Mousavizadeh Tehrani }
989e44d2e94SPouria Mousavizadeh Tehrani 
990e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_socket *
geneve_socket_mc_lookup(const union sockaddr_union * unsa)991e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_mc_lookup(const union sockaddr_union *unsa)
992e44d2e94SPouria Mousavizadeh Tehrani {
993e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union laddr;
994e44d2e94SPouria Mousavizadeh Tehrani 
995e44d2e94SPouria Mousavizadeh Tehrani 	laddr = *unsa;
996e44d2e94SPouria Mousavizadeh Tehrani 
997*f4e5b45bSJohn Baldwin 	switch (laddr.sa.sa_family) {
998*f4e5b45bSJohn Baldwin #ifdef INET
999*f4e5b45bSJohn Baldwin 	case AF_INET:
1000e44d2e94SPouria Mousavizadeh Tehrani 		laddr.sin.sin_addr.s_addr = INADDR_ANY;
1001*f4e5b45bSJohn Baldwin 		break;
1002*f4e5b45bSJohn Baldwin #endif
1003*f4e5b45bSJohn Baldwin #ifdef INET6
1004*f4e5b45bSJohn Baldwin 	case AF_INET6:
1005e44d2e94SPouria Mousavizadeh Tehrani 		laddr.sin6.sin6_addr = in6addr_any;
1006*f4e5b45bSJohn Baldwin 		break;
1007*f4e5b45bSJohn Baldwin #endif
1008*f4e5b45bSJohn Baldwin 	default:
1009*f4e5b45bSJohn Baldwin 		return (NULL);
1010*f4e5b45bSJohn Baldwin 	}
1011e44d2e94SPouria Mousavizadeh Tehrani 
1012e44d2e94SPouria Mousavizadeh Tehrani 	return (geneve_socket_lookup(&laddr));
1013e44d2e94SPouria Mousavizadeh Tehrani }
1014e44d2e94SPouria Mousavizadeh Tehrani 
1015e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_sockaddr_mc_info_match(const struct geneve_socket_mc_info * mc,const union sockaddr_union * group,const union sockaddr_union * local,int ifidx)1016e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_mc_info_match(const struct geneve_socket_mc_info *mc,
1017e44d2e94SPouria Mousavizadeh Tehrani     const union sockaddr_union *group, const union sockaddr_union *local,
1018e44d2e94SPouria Mousavizadeh Tehrani     int ifidx)
1019e44d2e94SPouria Mousavizadeh Tehrani {
1020e44d2e94SPouria Mousavizadeh Tehrani 
1021e44d2e94SPouria Mousavizadeh Tehrani 	if (!geneve_sockaddr_in_any(local) &&
1022e44d2e94SPouria Mousavizadeh Tehrani 	    !geneve_sockaddr_in_equal(&mc->gnvsomc_saddr, &local->sa))
1023e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
1024e44d2e94SPouria Mousavizadeh Tehrani 	if (!geneve_sockaddr_in_equal(&mc->gnvsomc_gaddr, &group->sa))
1025e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
1026e44d2e94SPouria Mousavizadeh Tehrani 	if (ifidx != 0 && ifidx != mc->gnvsomc_ifidx)
1027e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
1028e44d2e94SPouria Mousavizadeh Tehrani 
1029e44d2e94SPouria Mousavizadeh Tehrani 	return (1);
1030e44d2e94SPouria Mousavizadeh Tehrani }
1031e44d2e94SPouria Mousavizadeh Tehrani 
1032e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_mc_join_group(struct geneve_socket * gnvso,const union sockaddr_union * group,const union sockaddr_union * local,int * ifidx,union sockaddr_union * source)1033e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_mc_join_group(struct geneve_socket *gnvso,
1034e44d2e94SPouria Mousavizadeh Tehrani     const union sockaddr_union *group, const union sockaddr_union *local,
1035e44d2e94SPouria Mousavizadeh Tehrani     int *ifidx, union sockaddr_union *source)
1036e44d2e94SPouria Mousavizadeh Tehrani {
1037e44d2e94SPouria Mousavizadeh Tehrani 	struct sockopt sopt;
1038e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1039e44d2e94SPouria Mousavizadeh Tehrani 
1040e44d2e94SPouria Mousavizadeh Tehrani 	*source = *local;
1041e44d2e94SPouria Mousavizadeh Tehrani 
1042e44d2e94SPouria Mousavizadeh Tehrani 	if (group->sa.sa_family == AF_INET) {
1043e44d2e94SPouria Mousavizadeh Tehrani 		struct ip_mreq mreq;
1044e44d2e94SPouria Mousavizadeh Tehrani 
1045e44d2e94SPouria Mousavizadeh Tehrani 		mreq.imr_multiaddr = group->sin.sin_addr;
1046e44d2e94SPouria Mousavizadeh Tehrani 		mreq.imr_interface = local->sin.sin_addr;
1047e44d2e94SPouria Mousavizadeh Tehrani 
1048e44d2e94SPouria Mousavizadeh Tehrani 		memset(&sopt, 0, sizeof(sopt));
1049e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_dir = SOPT_SET;
1050e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_level = IPPROTO_IP;
1051e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_name = IP_ADD_MEMBERSHIP;
1052e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_val = &mreq;
1053e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_valsize = sizeof(mreq);
1054e44d2e94SPouria Mousavizadeh Tehrani 		error = sosetopt(gnvso->gnvso_sock, &sopt);
1055e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
1056e44d2e94SPouria Mousavizadeh Tehrani 			return (error);
1057e44d2e94SPouria Mousavizadeh Tehrani 
1058e44d2e94SPouria Mousavizadeh Tehrani 		/*
1059e44d2e94SPouria Mousavizadeh Tehrani 		 * BMV: Ideally, there would be a formal way for us to get
1060e44d2e94SPouria Mousavizadeh Tehrani 		 * the local interface that was selected based on the
1061e44d2e94SPouria Mousavizadeh Tehrani 		 * imr_interface address. We could then update *ifidx so
1062e44d2e94SPouria Mousavizadeh Tehrani 		 * geneve_sockaddr_mc_info_match() would return a match for
1063e44d2e94SPouria Mousavizadeh Tehrani 		 * later creates that explicitly set the multicast interface.
1064e44d2e94SPouria Mousavizadeh Tehrani 		 *
1065e44d2e94SPouria Mousavizadeh Tehrani 		 * If we really need to, we can of course look in the INP's
1066e44d2e94SPouria Mousavizadeh Tehrani 		 * membership list:
1067e44d2e94SPouria Mousavizadeh Tehrani 		 *     sotoinpcb(gnvso->gnvso_sock)->inp_moptions->
1068e44d2e94SPouria Mousavizadeh Tehrani 		 *         imo_head[]->imf_inm->inm_ifp
1069e44d2e94SPouria Mousavizadeh Tehrani 		 * similarly to imo_match_group().
1070e44d2e94SPouria Mousavizadeh Tehrani 		 */
1071e44d2e94SPouria Mousavizadeh Tehrani 		source->sin.sin_addr = local->sin.sin_addr;
1072e44d2e94SPouria Mousavizadeh Tehrani 
1073e44d2e94SPouria Mousavizadeh Tehrani 	} else if (group->sa.sa_family == AF_INET6) {
1074e44d2e94SPouria Mousavizadeh Tehrani 		struct ipv6_mreq mreq;
1075e44d2e94SPouria Mousavizadeh Tehrani 
1076e44d2e94SPouria Mousavizadeh Tehrani 		mreq.ipv6mr_multiaddr = group->sin6.sin6_addr;
1077e44d2e94SPouria Mousavizadeh Tehrani 		mreq.ipv6mr_interface = *ifidx;
1078e44d2e94SPouria Mousavizadeh Tehrani 
1079e44d2e94SPouria Mousavizadeh Tehrani 		memset(&sopt, 0, sizeof(sopt));
1080e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_dir = SOPT_SET;
1081e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_level = IPPROTO_IPV6;
1082e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_name = IPV6_JOIN_GROUP;
1083e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_val = &mreq;
1084e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_valsize = sizeof(mreq);
1085e44d2e94SPouria Mousavizadeh Tehrani 		error = sosetopt(gnvso->gnvso_sock, &sopt);
1086e44d2e94SPouria Mousavizadeh Tehrani 
1087e44d2e94SPouria Mousavizadeh Tehrani 		/*
1088e44d2e94SPouria Mousavizadeh Tehrani 		 * BMV: As with IPv4, we would really like to know what
1089e44d2e94SPouria Mousavizadeh Tehrani 		 * interface in6p_lookup_mcast_ifp() selected.
1090e44d2e94SPouria Mousavizadeh Tehrani 		 */
1091e44d2e94SPouria Mousavizadeh Tehrani 	} else
1092e44d2e94SPouria Mousavizadeh Tehrani 		error = EAFNOSUPPORT;
1093e44d2e94SPouria Mousavizadeh Tehrani 
1094e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1095e44d2e94SPouria Mousavizadeh Tehrani }
1096e44d2e94SPouria Mousavizadeh Tehrani 
1097e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_mc_leave_group(struct geneve_socket * gnvso,const union sockaddr_union * group,const union sockaddr_union * source,int ifidx)1098e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_mc_leave_group(struct geneve_socket *gnvso,
1099e44d2e94SPouria Mousavizadeh Tehrani     const union sockaddr_union *group, const union sockaddr_union *source,
1100e44d2e94SPouria Mousavizadeh Tehrani     int ifidx)
1101e44d2e94SPouria Mousavizadeh Tehrani {
1102e44d2e94SPouria Mousavizadeh Tehrani 	struct sockopt sopt;
1103e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1104e44d2e94SPouria Mousavizadeh Tehrani 
1105e44d2e94SPouria Mousavizadeh Tehrani 	memset(&sopt, 0, sizeof(sopt));
1106e44d2e94SPouria Mousavizadeh Tehrani 	sopt.sopt_dir = SOPT_SET;
1107e44d2e94SPouria Mousavizadeh Tehrani 
1108e44d2e94SPouria Mousavizadeh Tehrani 	if (group->sa.sa_family == AF_INET) {
1109e44d2e94SPouria Mousavizadeh Tehrani 		struct ip_mreq mreq;
1110e44d2e94SPouria Mousavizadeh Tehrani 
1111e44d2e94SPouria Mousavizadeh Tehrani 		mreq.imr_multiaddr = group->sin.sin_addr;
1112e44d2e94SPouria Mousavizadeh Tehrani 		mreq.imr_interface = source->sin.sin_addr;
1113e44d2e94SPouria Mousavizadeh Tehrani 
1114e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_level = IPPROTO_IP;
1115e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_name = IP_DROP_MEMBERSHIP;
1116e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_val = &mreq;
1117e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_valsize = sizeof(mreq);
1118e44d2e94SPouria Mousavizadeh Tehrani 		error = sosetopt(gnvso->gnvso_sock, &sopt);
1119e44d2e94SPouria Mousavizadeh Tehrani 	} else if (group->sa.sa_family == AF_INET6) {
1120e44d2e94SPouria Mousavizadeh Tehrani 		struct ipv6_mreq mreq;
1121e44d2e94SPouria Mousavizadeh Tehrani 
1122e44d2e94SPouria Mousavizadeh Tehrani 		mreq.ipv6mr_multiaddr = group->sin6.sin6_addr;
1123e44d2e94SPouria Mousavizadeh Tehrani 		mreq.ipv6mr_interface = ifidx;
1124e44d2e94SPouria Mousavizadeh Tehrani 
1125e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_level = IPPROTO_IPV6;
1126e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_name = IPV6_LEAVE_GROUP;
1127e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_val = &mreq;
1128e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_valsize = sizeof(mreq);
1129e44d2e94SPouria Mousavizadeh Tehrani 		error = sosetopt(gnvso->gnvso_sock, &sopt);
1130e44d2e94SPouria Mousavizadeh Tehrani 	} else
1131e44d2e94SPouria Mousavizadeh Tehrani 		error = EAFNOSUPPORT;
1132e44d2e94SPouria Mousavizadeh Tehrani 
1133e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1134e44d2e94SPouria Mousavizadeh Tehrani }
1135e44d2e94SPouria Mousavizadeh Tehrani 
1136e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_mc_add_group(struct geneve_socket * gnvso,const union sockaddr_union * group,const union sockaddr_union * local,int ifidx,int * idx)1137e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_mc_add_group(struct geneve_socket *gnvso,
1138e44d2e94SPouria Mousavizadeh Tehrani     const union sockaddr_union *group, const union sockaddr_union *local,
1139e44d2e94SPouria Mousavizadeh Tehrani     int ifidx, int *idx)
1140e44d2e94SPouria Mousavizadeh Tehrani {
1141e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union source;
1142e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket_mc_info *mc;
1143e44d2e94SPouria Mousavizadeh Tehrani 	int i, empty, error;
1144e44d2e94SPouria Mousavizadeh Tehrani 
1145e44d2e94SPouria Mousavizadeh Tehrani 	/*
1146e44d2e94SPouria Mousavizadeh Tehrani 	 * Within a socket, the same multicast group may be used by multiple
1147e44d2e94SPouria Mousavizadeh Tehrani 	 * interfaces, each with a different network identifier. But a socket
1148e44d2e94SPouria Mousavizadeh Tehrani 	 * may only join a multicast group once, so keep track of the users
1149e44d2e94SPouria Mousavizadeh Tehrani 	 * here.
1150e44d2e94SPouria Mousavizadeh Tehrani 	 */
1151e44d2e94SPouria Mousavizadeh Tehrani 
1152e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WLOCK(gnvso);
1153e44d2e94SPouria Mousavizadeh Tehrani 	for (empty = 0, i = 0; i < GENEVE_SO_MC_MAX_GROUPS; i++) {
1154e44d2e94SPouria Mousavizadeh Tehrani 		mc = &gnvso->gnvso_mc[i];
1155e44d2e94SPouria Mousavizadeh Tehrani 
1156e44d2e94SPouria Mousavizadeh Tehrani 		if (mc->gnvsomc_gaddr.sa.sa_family == AF_UNSPEC) {
1157e44d2e94SPouria Mousavizadeh Tehrani 			empty++;
1158e44d2e94SPouria Mousavizadeh Tehrani 			continue;
1159e44d2e94SPouria Mousavizadeh Tehrani 		}
1160e44d2e94SPouria Mousavizadeh Tehrani 		if (geneve_sockaddr_mc_info_match(mc, group, local, ifidx))
1161e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
1162e44d2e94SPouria Mousavizadeh Tehrani 	}
1163e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WUNLOCK(gnvso);
1164e44d2e94SPouria Mousavizadeh Tehrani 
1165e44d2e94SPouria Mousavizadeh Tehrani 	if (empty == 0)
1166e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOSPC);
1167e44d2e94SPouria Mousavizadeh Tehrani 
1168e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_socket_mc_join_group(gnvso, group, local, &ifidx, &source);
1169e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
1170e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
1171e44d2e94SPouria Mousavizadeh Tehrani 
1172e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WLOCK(gnvso);
1173e44d2e94SPouria Mousavizadeh Tehrani 	for (i = 0; i < GENEVE_SO_MC_MAX_GROUPS; i++) {
1174e44d2e94SPouria Mousavizadeh Tehrani 		mc = &gnvso->gnvso_mc[i];
1175e44d2e94SPouria Mousavizadeh Tehrani 
1176e44d2e94SPouria Mousavizadeh Tehrani 		if (mc->gnvsomc_gaddr.sa.sa_family == AF_UNSPEC) {
1177e44d2e94SPouria Mousavizadeh Tehrani 			geneve_sockaddr_copy(&mc->gnvsomc_gaddr, &group->sa);
1178e44d2e94SPouria Mousavizadeh Tehrani 			geneve_sockaddr_copy(&mc->gnvsomc_saddr, &source.sa);
1179e44d2e94SPouria Mousavizadeh Tehrani 			mc->gnvsomc_ifidx = ifidx;
1180e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
1181e44d2e94SPouria Mousavizadeh Tehrani 		}
1182e44d2e94SPouria Mousavizadeh Tehrani 	}
1183e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WUNLOCK(gnvso);
1184e44d2e94SPouria Mousavizadeh Tehrani 
1185e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_socket_mc_leave_group(gnvso, group, &source, ifidx);
1186e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(error == 0);
1187e44d2e94SPouria Mousavizadeh Tehrani 
1188e44d2e94SPouria Mousavizadeh Tehrani 	return (ENOSPC);
1189e44d2e94SPouria Mousavizadeh Tehrani 
1190e44d2e94SPouria Mousavizadeh Tehrani out:
1191e44d2e94SPouria Mousavizadeh Tehrani 	mc->gnvsomc_users++;
1192e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WUNLOCK(gnvso);
1193e44d2e94SPouria Mousavizadeh Tehrani 	*idx = i;
1194e44d2e94SPouria Mousavizadeh Tehrani 
1195e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1196e44d2e94SPouria Mousavizadeh Tehrani }
1197e44d2e94SPouria Mousavizadeh Tehrani 
1198e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_socket_mc_release_group(struct geneve_socket * vso,int idx)1199e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_mc_release_group(struct geneve_socket *vso, int idx)
1200e44d2e94SPouria Mousavizadeh Tehrani {
1201e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union group, source;
1202e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket_mc_info *mc;
1203e44d2e94SPouria Mousavizadeh Tehrani 	int ifidx, leave;
1204e44d2e94SPouria Mousavizadeh Tehrani 
1205e44d2e94SPouria Mousavizadeh Tehrani 	KASSERT(idx >= 0 && idx < GENEVE_SO_MC_MAX_GROUPS,
1206e44d2e94SPouria Mousavizadeh Tehrani 	    ("%s: vso %p idx %d out of bounds", __func__, vso, idx));
1207e44d2e94SPouria Mousavizadeh Tehrani 
1208e44d2e94SPouria Mousavizadeh Tehrani 	leave = 0;
1209e44d2e94SPouria Mousavizadeh Tehrani 	mc = &vso->gnvso_mc[idx];
1210e44d2e94SPouria Mousavizadeh Tehrani 
1211e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WLOCK(vso);
1212e44d2e94SPouria Mousavizadeh Tehrani 	mc->gnvsomc_users--;
1213e44d2e94SPouria Mousavizadeh Tehrani 	if (mc->gnvsomc_users == 0) {
1214e44d2e94SPouria Mousavizadeh Tehrani 		group = mc->gnvsomc_gaddr;
1215e44d2e94SPouria Mousavizadeh Tehrani 		source = mc->gnvsomc_saddr;
1216e44d2e94SPouria Mousavizadeh Tehrani 		ifidx = mc->gnvsomc_ifidx;
1217e44d2e94SPouria Mousavizadeh Tehrani 		memset(mc, 0, sizeof(*mc));
1218e44d2e94SPouria Mousavizadeh Tehrani 		leave = 1;
1219e44d2e94SPouria Mousavizadeh Tehrani 	}
1220e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WUNLOCK(vso);
1221e44d2e94SPouria Mousavizadeh Tehrani 
1222e44d2e94SPouria Mousavizadeh Tehrani 	if (leave != 0) {
1223e44d2e94SPouria Mousavizadeh Tehrani 		/*
1224e44d2e94SPouria Mousavizadeh Tehrani 		 * Our socket's membership in this group may have already
1225e44d2e94SPouria Mousavizadeh Tehrani 		 * been removed if we joined through an interface that's
1226e44d2e94SPouria Mousavizadeh Tehrani 		 * been detached.
1227e44d2e94SPouria Mousavizadeh Tehrani 		 */
1228e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_mc_leave_group(vso, &group, &source, ifidx);
1229e44d2e94SPouria Mousavizadeh Tehrani 	}
1230e44d2e94SPouria Mousavizadeh Tehrani }
1231e44d2e94SPouria Mousavizadeh Tehrani 
1232e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_softc *
geneve_socket_lookup_softc_locked(struct geneve_socket * gnvso,uint32_t vni)1233e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_lookup_softc_locked(struct geneve_socket *gnvso, uint32_t vni)
1234e44d2e94SPouria Mousavizadeh Tehrani {
1235e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
1236e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t hash;
1237e44d2e94SPouria Mousavizadeh Tehrani 
1238e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_LOCK_ASSERT(gnvso);
1239e44d2e94SPouria Mousavizadeh Tehrani 	hash = GENEVE_SO_VNI_HASH(vni);
1240e44d2e94SPouria Mousavizadeh Tehrani 
1241e44d2e94SPouria Mousavizadeh Tehrani 	LIST_FOREACH(sc, &gnvso->gnvso_vni_hash[hash], gnv_entry) {
1242e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_vni == vni) {
1243e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_ACQUIRE(sc);
1244e44d2e94SPouria Mousavizadeh Tehrani 			break;
1245e44d2e94SPouria Mousavizadeh Tehrani 		}
1246e44d2e94SPouria Mousavizadeh Tehrani 	}
1247e44d2e94SPouria Mousavizadeh Tehrani 
1248e44d2e94SPouria Mousavizadeh Tehrani 	return (sc);
1249e44d2e94SPouria Mousavizadeh Tehrani }
1250e44d2e94SPouria Mousavizadeh Tehrani 
1251e44d2e94SPouria Mousavizadeh Tehrani static struct geneve_softc *
geneve_socket_lookup_softc(struct geneve_socket * gnvso,uint32_t vni)1252e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_lookup_softc(struct geneve_socket *gnvso, uint32_t vni)
1253e44d2e94SPouria Mousavizadeh Tehrani {
1254e44d2e94SPouria Mousavizadeh Tehrani 	struct rm_priotracker tracker;
1255e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
1256e44d2e94SPouria Mousavizadeh Tehrani 
1257e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_RLOCK(gnvso, &tracker);
1258e44d2e94SPouria Mousavizadeh Tehrani 	sc = geneve_socket_lookup_softc_locked(gnvso, vni);
1259e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_RUNLOCK(gnvso, &tracker);
1260e44d2e94SPouria Mousavizadeh Tehrani 
1261e44d2e94SPouria Mousavizadeh Tehrani 	return (sc);
1262e44d2e94SPouria Mousavizadeh Tehrani }
1263e44d2e94SPouria Mousavizadeh Tehrani 
1264e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_insert_softc(struct geneve_socket * gnvso,struct geneve_softc * sc)1265e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_insert_softc(struct geneve_socket *gnvso, struct geneve_softc *sc)
1266e44d2e94SPouria Mousavizadeh Tehrani {
1267e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *tsc;
1268e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t vni, hash;
1269e44d2e94SPouria Mousavizadeh Tehrani 
1270e44d2e94SPouria Mousavizadeh Tehrani 	vni = sc->gnv_vni;
1271e44d2e94SPouria Mousavizadeh Tehrani 	hash = GENEVE_SO_VNI_HASH(vni);
1272e44d2e94SPouria Mousavizadeh Tehrani 
1273e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WLOCK(gnvso);
1274e44d2e94SPouria Mousavizadeh Tehrani 	tsc = geneve_socket_lookup_softc_locked(gnvso, vni);
1275e44d2e94SPouria Mousavizadeh Tehrani 	if (tsc != NULL) {
1276e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_SO_WUNLOCK(gnvso);
1277e44d2e94SPouria Mousavizadeh Tehrani 		geneve_release(tsc);
1278e44d2e94SPouria Mousavizadeh Tehrani 		return (EEXIST);
1279e44d2e94SPouria Mousavizadeh Tehrani 	}
1280e44d2e94SPouria Mousavizadeh Tehrani 
1281e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_ACQUIRE(sc);
1282e44d2e94SPouria Mousavizadeh Tehrani 	LIST_INSERT_HEAD(&gnvso->gnvso_vni_hash[hash], sc, gnv_entry);
1283e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WUNLOCK(gnvso);
1284e44d2e94SPouria Mousavizadeh Tehrani 
1285e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1286e44d2e94SPouria Mousavizadeh Tehrani }
1287e44d2e94SPouria Mousavizadeh Tehrani 
1288e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_socket_remove_softc(struct geneve_socket * gnvso,struct geneve_softc * sc)1289e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_remove_softc(struct geneve_socket *gnvso, struct geneve_softc *sc)
1290e44d2e94SPouria Mousavizadeh Tehrani {
1291e44d2e94SPouria Mousavizadeh Tehrani 
1292e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WLOCK(gnvso);
1293e44d2e94SPouria Mousavizadeh Tehrani 	LIST_REMOVE(sc, gnv_entry);
1294e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_SO_WUNLOCK(gnvso);
1295e44d2e94SPouria Mousavizadeh Tehrani 
1296e44d2e94SPouria Mousavizadeh Tehrani 	geneve_release(sc);
1297e44d2e94SPouria Mousavizadeh Tehrani }
1298e44d2e94SPouria Mousavizadeh Tehrani 
1299e44d2e94SPouria Mousavizadeh Tehrani static struct ifnet *
geneve_multicast_if_ref(struct geneve_softc * sc,uint32_t af)1300e44d2e94SPouria Mousavizadeh Tehrani geneve_multicast_if_ref(struct geneve_softc *sc, uint32_t af)
1301e44d2e94SPouria Mousavizadeh Tehrani {
1302e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1303e44d2e94SPouria Mousavizadeh Tehrani 
1304e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
1305e44d2e94SPouria Mousavizadeh Tehrani 
1306e44d2e94SPouria Mousavizadeh Tehrani 	ifp = NULL;
1307e44d2e94SPouria Mousavizadeh Tehrani 	if (af == AF_INET && sc->gnv_im4o != NULL)
1308e44d2e94SPouria Mousavizadeh Tehrani 		ifp = sc->gnv_im4o->imo_multicast_ifp;
1309e44d2e94SPouria Mousavizadeh Tehrani 	else if (af == AF_INET6 && sc->gnv_im6o != NULL)
1310e44d2e94SPouria Mousavizadeh Tehrani 		ifp = sc->gnv_im6o->im6o_multicast_ifp;
1311e44d2e94SPouria Mousavizadeh Tehrani 
1312e44d2e94SPouria Mousavizadeh Tehrani 	if (ifp != NULL)
1313e44d2e94SPouria Mousavizadeh Tehrani 		if_ref(ifp);
1314e44d2e94SPouria Mousavizadeh Tehrani 
1315e44d2e94SPouria Mousavizadeh Tehrani 	return (ifp);
1316e44d2e94SPouria Mousavizadeh Tehrani }
1317e44d2e94SPouria Mousavizadeh Tehrani 
1318e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_free_multicast(struct geneve_softc * sc)1319e44d2e94SPouria Mousavizadeh Tehrani geneve_free_multicast(struct geneve_softc *sc)
1320e44d2e94SPouria Mousavizadeh Tehrani {
1321e44d2e94SPouria Mousavizadeh Tehrani 
1322e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_mc_ifp != NULL) {
1323e44d2e94SPouria Mousavizadeh Tehrani 		if_rele(sc->gnv_mc_ifp);
1324e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_mc_ifp = NULL;
1325e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_mc_ifindex = 0;
1326e44d2e94SPouria Mousavizadeh Tehrani 	}
1327e44d2e94SPouria Mousavizadeh Tehrani 
1328e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_im4o != NULL) {
1329e44d2e94SPouria Mousavizadeh Tehrani 		free(sc->gnv_im4o, M_GENEVE);
1330e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im4o = NULL;
1331e44d2e94SPouria Mousavizadeh Tehrani 	}
1332e44d2e94SPouria Mousavizadeh Tehrani 
1333e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_im6o != NULL) {
1334e44d2e94SPouria Mousavizadeh Tehrani 		free(sc->gnv_im6o, M_GENEVE);
1335e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im6o = NULL;
1336e44d2e94SPouria Mousavizadeh Tehrani 	}
1337e44d2e94SPouria Mousavizadeh Tehrani }
1338e44d2e94SPouria Mousavizadeh Tehrani 
1339e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_setup_multicast_interface(struct geneve_softc * sc)1340e44d2e94SPouria Mousavizadeh Tehrani geneve_setup_multicast_interface(struct geneve_softc *sc)
1341e44d2e94SPouria Mousavizadeh Tehrani {
1342e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1343e44d2e94SPouria Mousavizadeh Tehrani 
1344e44d2e94SPouria Mousavizadeh Tehrani 	ifp = ifunit_ref(sc->gnv_mc_ifname);
1345e44d2e94SPouria Mousavizadeh Tehrani 	if (ifp == NULL) {
1346e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(sc->gnv_ifp, "multicast interface %s does not exist\n",
1347e44d2e94SPouria Mousavizadeh Tehrani 		    sc->gnv_mc_ifname);
1348e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOENT);
1349e44d2e94SPouria Mousavizadeh Tehrani 	}
1350e44d2e94SPouria Mousavizadeh Tehrani 
1351e44d2e94SPouria Mousavizadeh Tehrani 	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
1352e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(sc->gnv_ifp, "interface %s does not support multicast\n",
1353e44d2e94SPouria Mousavizadeh Tehrani 		    sc->gnv_mc_ifname);
1354e44d2e94SPouria Mousavizadeh Tehrani 		if_rele(ifp);
1355e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOTSUP);
1356e44d2e94SPouria Mousavizadeh Tehrani 	}
1357e44d2e94SPouria Mousavizadeh Tehrani 
1358e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_mc_ifp = ifp;
1359e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_mc_ifindex = ifp->if_index;
1360e44d2e94SPouria Mousavizadeh Tehrani 
1361e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1362e44d2e94SPouria Mousavizadeh Tehrani }
1363e44d2e94SPouria Mousavizadeh Tehrani 
1364e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_setup_multicast(struct geneve_softc * sc)1365e44d2e94SPouria Mousavizadeh Tehrani geneve_setup_multicast(struct geneve_softc *sc)
1366e44d2e94SPouria Mousavizadeh Tehrani {
1367e44d2e94SPouria Mousavizadeh Tehrani 	const union sockaddr_union *group;
1368e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1369e44d2e94SPouria Mousavizadeh Tehrani 
1370e44d2e94SPouria Mousavizadeh Tehrani 	group = &sc->gnv_dst_addr;
1371e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
1372e44d2e94SPouria Mousavizadeh Tehrani 
1373e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_mc_ifname[0] != '\0') {
1374e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_setup_multicast_interface(sc);
1375e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
1376e44d2e94SPouria Mousavizadeh Tehrani 			return (error);
1377e44d2e94SPouria Mousavizadeh Tehrani 	}
1378e44d2e94SPouria Mousavizadeh Tehrani 
1379e44d2e94SPouria Mousavizadeh Tehrani 	/*
1380e44d2e94SPouria Mousavizadeh Tehrani 	 * Initialize an multicast options structure that is sufficiently
1381e44d2e94SPouria Mousavizadeh Tehrani 	 * populated for use in the respective IP output routine. This
1382e44d2e94SPouria Mousavizadeh Tehrani 	 * structure is typically stored in the socket, but our sockets
1383e44d2e94SPouria Mousavizadeh Tehrani 	 * may be shared among multiple interfaces.
1384e44d2e94SPouria Mousavizadeh Tehrani 	 */
1385e44d2e94SPouria Mousavizadeh Tehrani 	if (group->sa.sa_family == AF_INET) {
1386e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im4o = malloc(sizeof(struct ip_moptions), M_GENEVE,
1387e44d2e94SPouria Mousavizadeh Tehrani 		    M_ZERO | M_WAITOK);
1388e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im4o->imo_multicast_ifp = sc->gnv_mc_ifp;
1389e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im4o->imo_multicast_ttl = sc->gnv_ttl;
1390e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im4o->imo_multicast_vif = -1;
1391e44d2e94SPouria Mousavizadeh Tehrani 	} else if (group->sa.sa_family == AF_INET6) {
1392e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im6o = malloc(sizeof(struct ip6_moptions), M_GENEVE,
1393e44d2e94SPouria Mousavizadeh Tehrani 		    M_ZERO | M_WAITOK);
1394e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im6o->im6o_multicast_ifp = sc->gnv_mc_ifp;
1395e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im6o->im6o_multicast_hlim = sc->gnv_ttl;
1396e44d2e94SPouria Mousavizadeh Tehrani 	}
1397e44d2e94SPouria Mousavizadeh Tehrani 
1398e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1399e44d2e94SPouria Mousavizadeh Tehrani }
1400e44d2e94SPouria Mousavizadeh Tehrani 
1401e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_setup_socket(struct geneve_softc * sc)1402e44d2e94SPouria Mousavizadeh Tehrani geneve_setup_socket(struct geneve_softc *sc)
1403e44d2e94SPouria Mousavizadeh Tehrani {
1404e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket *gnvso;
1405e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1406e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union *saddr, *daddr;
1407e44d2e94SPouria Mousavizadeh Tehrani 	int multicast, error;
1408e44d2e94SPouria Mousavizadeh Tehrani 
1409e44d2e94SPouria Mousavizadeh Tehrani 	gnvso = NULL;
1410e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
1411e44d2e94SPouria Mousavizadeh Tehrani 	saddr = &sc->gnv_src_addr;
1412e44d2e94SPouria Mousavizadeh Tehrani 	daddr = &sc->gnv_dst_addr;
1413e44d2e94SPouria Mousavizadeh Tehrani 	multicast = geneve_check_multicast_addr(daddr);
1414e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(multicast != EINVAL);
1415e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_so_mc_index = -1;
1416e44d2e94SPouria Mousavizadeh Tehrani 
1417e44d2e94SPouria Mousavizadeh Tehrani 	/* Try to create the socket. If that fails, attempt to use an existing one. */
1418e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_socket_create(ifp, multicast, saddr, &gnvso);
1419e44d2e94SPouria Mousavizadeh Tehrani 	if (error) {
1420e44d2e94SPouria Mousavizadeh Tehrani 		if (multicast != 0)
1421e44d2e94SPouria Mousavizadeh Tehrani 			gnvso = geneve_socket_mc_lookup(saddr);
1422e44d2e94SPouria Mousavizadeh Tehrani 		else
1423e44d2e94SPouria Mousavizadeh Tehrani 			gnvso = geneve_socket_lookup(saddr);
1424e44d2e94SPouria Mousavizadeh Tehrani 
1425e44d2e94SPouria Mousavizadeh Tehrani 		if (gnvso == NULL) {
1426e44d2e94SPouria Mousavizadeh Tehrani 			if_printf(ifp, "can't find existing socket\n");
1427e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
1428e44d2e94SPouria Mousavizadeh Tehrani 		}
1429e44d2e94SPouria Mousavizadeh Tehrani 	}
1430e44d2e94SPouria Mousavizadeh Tehrani 
1431e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_df == IFLA_GENEVE_DF_SET) {
1432e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_socket_set_df(gnvso, true);
1433e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
1434e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
1435e44d2e94SPouria Mousavizadeh Tehrani 	}
1436e44d2e94SPouria Mousavizadeh Tehrani 
1437e44d2e94SPouria Mousavizadeh Tehrani 	if (multicast != 0) {
1438e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_setup_multicast(sc);
1439e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
1440e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
1441e44d2e94SPouria Mousavizadeh Tehrani 
1442e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_socket_mc_add_group(gnvso, daddr, saddr,
1443e44d2e94SPouria Mousavizadeh Tehrani 		    sc->gnv_mc_ifindex, &sc->gnv_so_mc_index);
1444e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
1445e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
1446e44d2e94SPouria Mousavizadeh Tehrani 	}
1447e44d2e94SPouria Mousavizadeh Tehrani 
1448e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_sock = gnvso;
1449e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_socket_insert_softc(gnvso, sc);
1450e44d2e94SPouria Mousavizadeh Tehrani 	if (error) {
1451e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_sock = NULL;
1452e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "network identifier %d already exists\n", sc->gnv_vni);
1453e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
1454e44d2e94SPouria Mousavizadeh Tehrani 	}
1455e44d2e94SPouria Mousavizadeh Tehrani 
1456e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1457e44d2e94SPouria Mousavizadeh Tehrani 
1458e44d2e94SPouria Mousavizadeh Tehrani out:
1459e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvso != NULL) {
1460e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_so_mc_index != -1) {
1461e44d2e94SPouria Mousavizadeh Tehrani 			geneve_socket_mc_release_group(gnvso, sc->gnv_so_mc_index);
1462e44d2e94SPouria Mousavizadeh Tehrani 			sc->gnv_so_mc_index = -1;
1463e44d2e94SPouria Mousavizadeh Tehrani 		}
1464e44d2e94SPouria Mousavizadeh Tehrani 		if (multicast != 0)
1465e44d2e94SPouria Mousavizadeh Tehrani 			geneve_free_multicast(sc);
1466e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_release(gnvso);
1467e44d2e94SPouria Mousavizadeh Tehrani 	}
1468e44d2e94SPouria Mousavizadeh Tehrani 
1469e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1470e44d2e94SPouria Mousavizadeh Tehrani }
1471e44d2e94SPouria Mousavizadeh Tehrani 
1472e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_setup_interface_hdrlen(struct geneve_softc * sc)1473e44d2e94SPouria Mousavizadeh Tehrani geneve_setup_interface_hdrlen(struct geneve_softc *sc)
1474e44d2e94SPouria Mousavizadeh Tehrani {
1475e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1476e44d2e94SPouria Mousavizadeh Tehrani 
1477e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_WASSERT(sc);
1478e44d2e94SPouria Mousavizadeh Tehrani 
1479e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
1480e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_hdrlen = ETHER_HDR_LEN + sizeof(struct geneveudphdr);
1481e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER)
1482e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_hdrlen += ETHER_HDR_LEN;
1483e44d2e94SPouria Mousavizadeh Tehrani 
1484e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_dst_addr.sa.sa_family == AF_INET)
1485e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_hdrlen += sizeof(struct ip);
1486e44d2e94SPouria Mousavizadeh Tehrani 	else
1487e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_hdrlen += sizeof(struct ip6_hdr);
1488e44d2e94SPouria Mousavizadeh Tehrani 
1489e44d2e94SPouria Mousavizadeh Tehrani 	if ((sc->gnv_flags & GENEVE_FLAG_USER_MTU) == 0)
1490e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_mtu = ETHERMTU - ifp->if_hdrlen;
1491e44d2e94SPouria Mousavizadeh Tehrani }
1492e44d2e94SPouria Mousavizadeh Tehrani 
1493e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_socket_set_df(struct geneve_socket * gnvso,bool df)1494e44d2e94SPouria Mousavizadeh Tehrani geneve_socket_set_df(struct geneve_socket *gnvso, bool df)
1495e44d2e94SPouria Mousavizadeh Tehrani {
1496e44d2e94SPouria Mousavizadeh Tehrani 	struct sockopt sopt;
1497e44d2e94SPouria Mousavizadeh Tehrani 	int optval;
1498e44d2e94SPouria Mousavizadeh Tehrani 
1499e44d2e94SPouria Mousavizadeh Tehrani 	memset(&sopt, 0, sizeof(sopt));
1500e44d2e94SPouria Mousavizadeh Tehrani 	sopt.sopt_dir = SOPT_SET;
1501e44d2e94SPouria Mousavizadeh Tehrani 
1502e44d2e94SPouria Mousavizadeh Tehrani 	switch (gnvso->gnvso_laddr.sa.sa_family) {
1503e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET:
1504e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_level = IPPROTO_IP;
1505e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_name = IP_DONTFRAG;
1506e44d2e94SPouria Mousavizadeh Tehrani 		break;
1507e44d2e94SPouria Mousavizadeh Tehrani 
1508e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET6:
1509e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_level = IPPROTO_IPV6;
1510e44d2e94SPouria Mousavizadeh Tehrani 		sopt.sopt_name = IPV6_DONTFRAG;
1511e44d2e94SPouria Mousavizadeh Tehrani 		break;
1512e44d2e94SPouria Mousavizadeh Tehrani 
1513e44d2e94SPouria Mousavizadeh Tehrani 	default:
1514e44d2e94SPouria Mousavizadeh Tehrani 		return (EAFNOSUPPORT);
1515e44d2e94SPouria Mousavizadeh Tehrani 	}
1516e44d2e94SPouria Mousavizadeh Tehrani 
1517e44d2e94SPouria Mousavizadeh Tehrani 	optval = df ? 1 : 0;
1518e44d2e94SPouria Mousavizadeh Tehrani 	sopt.sopt_val = &optval;
1519e44d2e94SPouria Mousavizadeh Tehrani 	sopt.sopt_valsize = sizeof(optval);
1520e44d2e94SPouria Mousavizadeh Tehrani 
1521e44d2e94SPouria Mousavizadeh Tehrani 	return (sosetopt(gnvso->gnvso_sock, &sopt));
1522e44d2e94SPouria Mousavizadeh Tehrani }
1523e44d2e94SPouria Mousavizadeh Tehrani 
1524e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_valid_init_config(struct geneve_softc * sc)1525e44d2e94SPouria Mousavizadeh Tehrani geneve_valid_init_config(struct geneve_softc *sc)
1526e44d2e94SPouria Mousavizadeh Tehrani {
1527e44d2e94SPouria Mousavizadeh Tehrani 	const char *reason;
1528e44d2e94SPouria Mousavizadeh Tehrani 
1529e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_vni >= GENEVE_VNI_MAX) {
1530e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(sc->gnv_ifp, "%u", sc->gnv_vni);
1531e44d2e94SPouria Mousavizadeh Tehrani 		reason = "invalid virtual network identifier specified";
1532e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1533e44d2e94SPouria Mousavizadeh Tehrani 	}
1534e44d2e94SPouria Mousavizadeh Tehrani 
1535e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_sockaddr_supported(&sc->gnv_src_addr, 1) == 0) {
1536e44d2e94SPouria Mousavizadeh Tehrani 		reason = "source address type is not supported";
1537e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1538e44d2e94SPouria Mousavizadeh Tehrani 	}
1539e44d2e94SPouria Mousavizadeh Tehrani 
1540e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_sockaddr_supported(&sc->gnv_dst_addr, 0) == 0) {
1541e44d2e94SPouria Mousavizadeh Tehrani 		reason = "destination address type is not supported";
1542e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1543e44d2e94SPouria Mousavizadeh Tehrani 	}
1544e44d2e94SPouria Mousavizadeh Tehrani 
1545e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_sockaddr_in_any(&sc->gnv_dst_addr) != 0) {
1546e44d2e94SPouria Mousavizadeh Tehrani 		reason = "no valid destination address specified";
1547e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1548e44d2e94SPouria Mousavizadeh Tehrani 	}
1549e44d2e94SPouria Mousavizadeh Tehrani 
1550e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_check_multicast_addr(&sc->gnv_dst_addr) == 0 &&
1551e44d2e94SPouria Mousavizadeh Tehrani 	    sc->gnv_mc_ifname[0] != '\0') {
1552e44d2e94SPouria Mousavizadeh Tehrani 		reason = "can only specify interface with a group address";
1553e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1554e44d2e94SPouria Mousavizadeh Tehrani 	}
1555e44d2e94SPouria Mousavizadeh Tehrani 
1556e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_sockaddr_in_any(&sc->gnv_src_addr) == 0) {
1557e44d2e94SPouria Mousavizadeh Tehrani 		if (&sc->gnv_src_addr.sa.sa_family ==
1558e44d2e94SPouria Mousavizadeh Tehrani 		    &sc->gnv_dst_addr.sa.sa_family) {
1559e44d2e94SPouria Mousavizadeh Tehrani 			reason = "source and destination address must both be either IPv4 or IPv6";
1560e44d2e94SPouria Mousavizadeh Tehrani 			goto fail;
1561e44d2e94SPouria Mousavizadeh Tehrani 		}
1562e44d2e94SPouria Mousavizadeh Tehrani 	}
1563e44d2e94SPouria Mousavizadeh Tehrani 
1564e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_src_addr.sin.sin_port == 0) {
1565e44d2e94SPouria Mousavizadeh Tehrani 		reason = "local port not specified";
1566e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1567e44d2e94SPouria Mousavizadeh Tehrani 	}
1568e44d2e94SPouria Mousavizadeh Tehrani 
1569e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_dst_addr.sin.sin_port == 0) {
1570e44d2e94SPouria Mousavizadeh Tehrani 		reason = "remote port not specified";
1571e44d2e94SPouria Mousavizadeh Tehrani 		goto fail;
1572e44d2e94SPouria Mousavizadeh Tehrani 	}
1573e44d2e94SPouria Mousavizadeh Tehrani 
1574e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1575e44d2e94SPouria Mousavizadeh Tehrani 
1576e44d2e94SPouria Mousavizadeh Tehrani fail:
1577e44d2e94SPouria Mousavizadeh Tehrani 	if_printf(sc->gnv_ifp, "cannot initialize interface: %s\n", reason);
1578e44d2e94SPouria Mousavizadeh Tehrani 	return (EINVAL);
1579e44d2e94SPouria Mousavizadeh Tehrani }
1580e44d2e94SPouria Mousavizadeh Tehrani 
1581e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_init_complete(struct geneve_softc * sc)1582e44d2e94SPouria Mousavizadeh Tehrani geneve_init_complete(struct geneve_softc *sc)
1583e44d2e94SPouria Mousavizadeh Tehrani {
1584e44d2e94SPouria Mousavizadeh Tehrani 
1585e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1586e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags |= GENEVE_FLAG_RUNNING;
1587e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags &= ~GENEVE_FLAG_INIT;
1588e44d2e94SPouria Mousavizadeh Tehrani 	wakeup(sc);
1589e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1590e44d2e94SPouria Mousavizadeh Tehrani }
1591e44d2e94SPouria Mousavizadeh Tehrani 
1592e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_init(void * xsc)1593e44d2e94SPouria Mousavizadeh Tehrani geneve_init(void *xsc)
1594e44d2e94SPouria Mousavizadeh Tehrani {
1595e44d2e94SPouria Mousavizadeh Tehrani 	static const uint8_t empty_mac[ETHER_ADDR_LEN];
1596e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
1597e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1598e44d2e94SPouria Mousavizadeh Tehrani 
1599e44d2e94SPouria Mousavizadeh Tehrani 	sc = xsc;
1600e44d2e94SPouria Mousavizadeh Tehrani 	sx_xlock(&geneve_sx);
1601e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1602e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
1603e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_RUNNING) {
1604e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WUNLOCK(sc);
1605e44d2e94SPouria Mousavizadeh Tehrani 		sx_xunlock(&geneve_sx);
1606e44d2e94SPouria Mousavizadeh Tehrani 		return;
1607e44d2e94SPouria Mousavizadeh Tehrani 	}
1608e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags |= GENEVE_FLAG_INIT;
1609e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1610e44d2e94SPouria Mousavizadeh Tehrani 
1611e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_valid_init_config(sc) != 0)
1612e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
1613e44d2e94SPouria Mousavizadeh Tehrani 
1614e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_setup_socket(sc) != 0)
1615e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
1616e44d2e94SPouria Mousavizadeh Tehrani 
1617e44d2e94SPouria Mousavizadeh Tehrani 	/* Initialize the default forwarding entry. */
1618e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER) {
1619e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_entry_init(sc, &sc->gnv_default_fe, empty_mac,
1620e44d2e94SPouria Mousavizadeh Tehrani 		    &sc->gnv_dst_addr.sa, GENEVE_FE_FLAG_STATIC);
1621e44d2e94SPouria Mousavizadeh Tehrani 
1622e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WLOCK(sc);
1623e44d2e94SPouria Mousavizadeh Tehrani 		callout_reset(&sc->gnv_callout, geneve_ftable_prune_period * hz,
1624e44d2e94SPouria Mousavizadeh Tehrani 		    geneve_timer, sc);
1625e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WUNLOCK(sc);
1626e44d2e94SPouria Mousavizadeh Tehrani 	}
1627e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1628e44d2e94SPouria Mousavizadeh Tehrani 	if_link_state_change(ifp, LINK_STATE_UP);
1629e44d2e94SPouria Mousavizadeh Tehrani 
1630e44d2e94SPouria Mousavizadeh Tehrani out:
1631e44d2e94SPouria Mousavizadeh Tehrani 	geneve_init_complete(sc);
1632e44d2e94SPouria Mousavizadeh Tehrani 	sx_xunlock(&geneve_sx);
1633e44d2e94SPouria Mousavizadeh Tehrani }
1634e44d2e94SPouria Mousavizadeh Tehrani 
1635e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_release(struct geneve_softc * sc)1636e44d2e94SPouria Mousavizadeh Tehrani geneve_release(struct geneve_softc *sc)
1637e44d2e94SPouria Mousavizadeh Tehrani {
1638e44d2e94SPouria Mousavizadeh Tehrani 
1639e44d2e94SPouria Mousavizadeh Tehrani 	/*
1640e44d2e94SPouria Mousavizadeh Tehrani 	 * The softc may be destroyed as soon as we release our reference,
1641e44d2e94SPouria Mousavizadeh Tehrani 	 * so we cannot serialize the wakeup with the softc lock. We use a
1642e44d2e94SPouria Mousavizadeh Tehrani 	 * timeout in our sleeps so a missed wakeup is unfortunate but not fatal.
1643e44d2e94SPouria Mousavizadeh Tehrani 	 */
1644e44d2e94SPouria Mousavizadeh Tehrani 	if (GENEVE_RELEASE(sc) != 0)
1645e44d2e94SPouria Mousavizadeh Tehrani 		wakeup(sc);
1646e44d2e94SPouria Mousavizadeh Tehrani }
1647e44d2e94SPouria Mousavizadeh Tehrani 
1648e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_teardown_wait(struct geneve_softc * sc)1649e44d2e94SPouria Mousavizadeh Tehrani geneve_teardown_wait(struct geneve_softc *sc)
1650e44d2e94SPouria Mousavizadeh Tehrani {
1651e44d2e94SPouria Mousavizadeh Tehrani 
1652e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_WASSERT(sc);
1653e44d2e94SPouria Mousavizadeh Tehrani 	while (sc->gnv_flags & GENEVE_FLAG_TEARDOWN)
1654e44d2e94SPouria Mousavizadeh Tehrani 		rm_sleep(sc, &sc->gnv_lock, 0, "gnvtrn", hz);
1655e44d2e94SPouria Mousavizadeh Tehrani }
1656e44d2e94SPouria Mousavizadeh Tehrani 
1657e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_teardown_locked(struct geneve_softc * sc)1658e44d2e94SPouria Mousavizadeh Tehrani geneve_teardown_locked(struct geneve_softc *sc)
1659e44d2e94SPouria Mousavizadeh Tehrani {
1660e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1661e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket *gnvso;
1662e44d2e94SPouria Mousavizadeh Tehrani 
1663e44d2e94SPouria Mousavizadeh Tehrani 	sx_assert(&geneve_sx, SA_XLOCKED);
1664e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_WASSERT(sc);
1665e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(sc->gnv_flags & GENEVE_FLAG_TEARDOWN);
1666e44d2e94SPouria Mousavizadeh Tehrani 
1667e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
1668e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_flags &= ~IFF_UP;
1669e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags &= ~GENEVE_FLAG_RUNNING;
1670e44d2e94SPouria Mousavizadeh Tehrani 
1671e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER)
1672e44d2e94SPouria Mousavizadeh Tehrani 		callout_stop(&sc->gnv_callout);
1673e44d2e94SPouria Mousavizadeh Tehrani 	gnvso = sc->gnv_sock;
1674e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_sock = NULL;
1675e44d2e94SPouria Mousavizadeh Tehrani 
1676e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1677e44d2e94SPouria Mousavizadeh Tehrani 	if_link_state_change(ifp, LINK_STATE_DOWN);
1678e44d2e94SPouria Mousavizadeh Tehrani 
1679e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvso != NULL) {
1680e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_remove_softc(gnvso, sc);
1681e44d2e94SPouria Mousavizadeh Tehrani 
1682e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_so_mc_index != -1) {
1683e44d2e94SPouria Mousavizadeh Tehrani 			geneve_socket_mc_release_group(gnvso, sc->gnv_so_mc_index);
1684e44d2e94SPouria Mousavizadeh Tehrani 			sc->gnv_so_mc_index = -1;
1685e44d2e94SPouria Mousavizadeh Tehrani 		}
1686e44d2e94SPouria Mousavizadeh Tehrani 	}
1687e44d2e94SPouria Mousavizadeh Tehrani 
1688e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1689e44d2e94SPouria Mousavizadeh Tehrani 	while (sc->gnv_refcnt != 0)
1690e44d2e94SPouria Mousavizadeh Tehrani 		rm_sleep(sc, &sc->gnv_lock, 0, "gnvdrn", hz);
1691e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1692e44d2e94SPouria Mousavizadeh Tehrani 
1693e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER)
1694e44d2e94SPouria Mousavizadeh Tehrani 		callout_drain(&sc->gnv_callout);
1695e44d2e94SPouria Mousavizadeh Tehrani 
1696e44d2e94SPouria Mousavizadeh Tehrani 	geneve_free_multicast(sc);
1697e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvso != NULL)
1698e44d2e94SPouria Mousavizadeh Tehrani 		geneve_socket_release(gnvso);
1699e44d2e94SPouria Mousavizadeh Tehrani 
1700e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1701e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags &= ~GENEVE_FLAG_TEARDOWN;
1702e44d2e94SPouria Mousavizadeh Tehrani 	wakeup(sc);
1703e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1704e44d2e94SPouria Mousavizadeh Tehrani }
1705e44d2e94SPouria Mousavizadeh Tehrani 
1706e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_teardown(struct geneve_softc * sc)1707e44d2e94SPouria Mousavizadeh Tehrani geneve_teardown(struct geneve_softc *sc)
1708e44d2e94SPouria Mousavizadeh Tehrani {
1709e44d2e94SPouria Mousavizadeh Tehrani 
1710e44d2e94SPouria Mousavizadeh Tehrani 	sx_xlock(&geneve_sx);
1711e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1712e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_TEARDOWN) {
1713e44d2e94SPouria Mousavizadeh Tehrani 		geneve_teardown_wait(sc);
1714e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WUNLOCK(sc);
1715e44d2e94SPouria Mousavizadeh Tehrani 		sx_xunlock(&geneve_sx);
1716e44d2e94SPouria Mousavizadeh Tehrani 		return;
1717e44d2e94SPouria Mousavizadeh Tehrani 	}
1718e44d2e94SPouria Mousavizadeh Tehrani 
1719e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags |= GENEVE_FLAG_TEARDOWN;
1720e44d2e94SPouria Mousavizadeh Tehrani 	geneve_teardown_locked(sc);
1721e44d2e94SPouria Mousavizadeh Tehrani 	sx_xunlock(&geneve_sx);
1722e44d2e94SPouria Mousavizadeh Tehrani }
1723e44d2e94SPouria Mousavizadeh Tehrani 
1724e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_timer(void * xsc)1725e44d2e94SPouria Mousavizadeh Tehrani geneve_timer(void *xsc)
1726e44d2e94SPouria Mousavizadeh Tehrani {
1727e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
1728e44d2e94SPouria Mousavizadeh Tehrani 
1729e44d2e94SPouria Mousavizadeh Tehrani 	sc = xsc;
1730e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_WASSERT(sc);
1731e44d2e94SPouria Mousavizadeh Tehrani 
1732e44d2e94SPouria Mousavizadeh Tehrani 	geneve_ftable_expire(sc);
1733e44d2e94SPouria Mousavizadeh Tehrani 	callout_schedule(&sc->gnv_callout, geneve_ftable_prune_period * hz);
1734e44d2e94SPouria Mousavizadeh Tehrani }
1735e44d2e94SPouria Mousavizadeh Tehrani 
1736e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_ioctl_ifflags(struct geneve_softc * sc)1737e44d2e94SPouria Mousavizadeh Tehrani geneve_ioctl_ifflags(struct geneve_softc *sc)
1738e44d2e94SPouria Mousavizadeh Tehrani {
1739e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
1740e44d2e94SPouria Mousavizadeh Tehrani 
1741e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
1742e44d2e94SPouria Mousavizadeh Tehrani 
1743e44d2e94SPouria Mousavizadeh Tehrani 	if ((ifp->if_flags & IFF_UP) != 0) {
1744e44d2e94SPouria Mousavizadeh Tehrani 		if ((sc->gnv_flags & GENEVE_FLAG_RUNNING) == 0)
1745e44d2e94SPouria Mousavizadeh Tehrani 			geneve_init(sc);
1746e44d2e94SPouria Mousavizadeh Tehrani 	} else {
1747e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_flags & GENEVE_FLAG_RUNNING)
1748e44d2e94SPouria Mousavizadeh Tehrani 			geneve_teardown(sc);
1749e44d2e94SPouria Mousavizadeh Tehrani 	}
1750e44d2e94SPouria Mousavizadeh Tehrani 
1751e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1752e44d2e94SPouria Mousavizadeh Tehrani }
1753e44d2e94SPouria Mousavizadeh Tehrani 
1754e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_flush_ftable(struct geneve_softc * sc,bool flush)1755e44d2e94SPouria Mousavizadeh Tehrani geneve_flush_ftable(struct geneve_softc *sc, bool flush)
1756e44d2e94SPouria Mousavizadeh Tehrani {
1757e44d2e94SPouria Mousavizadeh Tehrani 
1758e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1759e44d2e94SPouria Mousavizadeh Tehrani 	geneve_ftable_flush(sc, flush);
1760e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1761e44d2e94SPouria Mousavizadeh Tehrani 
1762e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
1763e44d2e94SPouria Mousavizadeh Tehrani }
1764e44d2e94SPouria Mousavizadeh Tehrani 
1765e44d2e94SPouria Mousavizadeh Tehrani static uint16_t
geneve_get_local_port(struct geneve_softc * sc)1766e44d2e94SPouria Mousavizadeh Tehrani geneve_get_local_port(struct geneve_softc *sc)
1767e44d2e94SPouria Mousavizadeh Tehrani {
1768e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t port = 0;
1769e44d2e94SPouria Mousavizadeh Tehrani 
1770e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
1771e44d2e94SPouria Mousavizadeh Tehrani 
1772e44d2e94SPouria Mousavizadeh Tehrani 	switch (sc->gnv_src_addr.sa.sa_family) {
1773e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET:
1774e44d2e94SPouria Mousavizadeh Tehrani 		port = ntohs(sc->gnv_src_addr.sin.sin_port);
1775e44d2e94SPouria Mousavizadeh Tehrani 		break;
1776e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET6:
1777e44d2e94SPouria Mousavizadeh Tehrani 		port = ntohs(sc->gnv_src_addr.sin6.sin6_port);
1778e44d2e94SPouria Mousavizadeh Tehrani 		break;
1779e44d2e94SPouria Mousavizadeh Tehrani 	}
1780e44d2e94SPouria Mousavizadeh Tehrani 
1781e44d2e94SPouria Mousavizadeh Tehrani 	return (port);
1782e44d2e94SPouria Mousavizadeh Tehrani }
1783e44d2e94SPouria Mousavizadeh Tehrani 
1784e44d2e94SPouria Mousavizadeh Tehrani static uint16_t
geneve_get_remote_port(struct geneve_softc * sc)1785e44d2e94SPouria Mousavizadeh Tehrani geneve_get_remote_port(struct geneve_softc *sc)
1786e44d2e94SPouria Mousavizadeh Tehrani {
1787e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t port = 0;
1788e44d2e94SPouria Mousavizadeh Tehrani 
1789e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
1790e44d2e94SPouria Mousavizadeh Tehrani 
1791e44d2e94SPouria Mousavizadeh Tehrani 	switch (sc->gnv_dst_addr.sa.sa_family) {
1792e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET:
1793e44d2e94SPouria Mousavizadeh Tehrani 		port = ntohs(sc->gnv_dst_addr.sin.sin_port);
1794e44d2e94SPouria Mousavizadeh Tehrani 		break;
1795e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET6:
1796e44d2e94SPouria Mousavizadeh Tehrani 		port = ntohs(sc->gnv_dst_addr.sin6.sin6_port);
1797e44d2e94SPouria Mousavizadeh Tehrani 		break;
1798e44d2e94SPouria Mousavizadeh Tehrani 	}
1799e44d2e94SPouria Mousavizadeh Tehrani 
1800e44d2e94SPouria Mousavizadeh Tehrani 	return (port);
1801e44d2e94SPouria Mousavizadeh Tehrani }
1802e44d2e94SPouria Mousavizadeh Tehrani 
1803e44d2e94SPouria Mousavizadeh Tehrani /* Netlink Helpers */
1804e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_vni_nl(struct geneve_softc * sc,struct nl_pstate * npt,uint32_t vni)1805e44d2e94SPouria Mousavizadeh Tehrani geneve_set_vni_nl(struct geneve_softc *sc, struct nl_pstate *npt, uint32_t vni)
1806e44d2e94SPouria Mousavizadeh Tehrani {
1807e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1808e44d2e94SPouria Mousavizadeh Tehrani 
1809e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
1810e44d2e94SPouria Mousavizadeh Tehrani 	if (vni >= GENEVE_VNI_MAX) {
1811e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
1812e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1813e44d2e94SPouria Mousavizadeh Tehrani 	}
1814e44d2e94SPouria Mousavizadeh Tehrani 
1815e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1816e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc))
1817e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_vni = vni;
1818e44d2e94SPouria Mousavizadeh Tehrani 	else
1819e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
1820e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1821e44d2e94SPouria Mousavizadeh Tehrani 
1822e44d2e94SPouria Mousavizadeh Tehrani ret:
1823e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
1824e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve vni is invalid: %u", vni);
1825e44d2e94SPouria Mousavizadeh Tehrani 
1826e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
1827e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
1828e44d2e94SPouria Mousavizadeh Tehrani 
1829e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1830e44d2e94SPouria Mousavizadeh Tehrani }
1831e44d2e94SPouria Mousavizadeh Tehrani 
1832e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_local_addr_nl(struct geneve_softc * sc,struct nl_pstate * npt,struct sockaddr * sa)1833e44d2e94SPouria Mousavizadeh Tehrani geneve_set_local_addr_nl(struct geneve_softc *sc, struct nl_pstate *npt,
1834e44d2e94SPouria Mousavizadeh Tehrani     struct sockaddr *sa)
1835e44d2e94SPouria Mousavizadeh Tehrani {
1836e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union *unsa = (union sockaddr_union *)sa;
1837e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1838e44d2e94SPouria Mousavizadeh Tehrani 
1839e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_check_sockaddr(unsa, sa->sa_len);
1840e44d2e94SPouria Mousavizadeh Tehrani 	if (error != 0)
1841e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1842e44d2e94SPouria Mousavizadeh Tehrani 
1843e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_check_multicast_addr(unsa);
1844e44d2e94SPouria Mousavizadeh Tehrani 	if (error != 0)
1845e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1846e44d2e94SPouria Mousavizadeh Tehrani 
1847*f4e5b45bSJohn Baldwin #ifdef INET6
1848e44d2e94SPouria Mousavizadeh Tehrani 	if (unsa->sa.sa_family == AF_INET6) {
1849e44d2e94SPouria Mousavizadeh Tehrani 		error = sa6_embedscope(&unsa->sin6, V_ip6_use_defzone);
1850e44d2e94SPouria Mousavizadeh Tehrani 		if (error != 0)
1851e44d2e94SPouria Mousavizadeh Tehrani 			goto ret;
1852e44d2e94SPouria Mousavizadeh Tehrani 	}
1853*f4e5b45bSJohn Baldwin #endif
1854e44d2e94SPouria Mousavizadeh Tehrani 
1855e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1856e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc)) {
1857e44d2e94SPouria Mousavizadeh Tehrani 		geneve_sockaddr_in_copy(&sc->gnv_src_addr, &unsa->sa);
1858e44d2e94SPouria Mousavizadeh Tehrani 		geneve_set_hwcaps(sc);
1859e44d2e94SPouria Mousavizadeh Tehrani 	} else
1860e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
1861e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1862e44d2e94SPouria Mousavizadeh Tehrani 
1863e44d2e94SPouria Mousavizadeh Tehrani ret:
1864e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
1865e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "local address is invalid.");
1866e44d2e94SPouria Mousavizadeh Tehrani 
1867e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EAFNOSUPPORT)
1868e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "address family is not supported.");
1869e44d2e94SPouria Mousavizadeh Tehrani 
1870e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
1871e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
1872e44d2e94SPouria Mousavizadeh Tehrani 
1873e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1874e44d2e94SPouria Mousavizadeh Tehrani }
1875e44d2e94SPouria Mousavizadeh Tehrani 
1876e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_remote_addr_nl(struct geneve_softc * sc,struct nl_pstate * npt,struct sockaddr * sa)1877e44d2e94SPouria Mousavizadeh Tehrani geneve_set_remote_addr_nl(struct geneve_softc *sc, struct nl_pstate *npt,
1878e44d2e94SPouria Mousavizadeh Tehrani     struct sockaddr *sa)
1879e44d2e94SPouria Mousavizadeh Tehrani {
1880e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union *unsa = (union sockaddr_union *)sa;
1881e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1882e44d2e94SPouria Mousavizadeh Tehrani 
1883e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_check_sockaddr(unsa, sa->sa_len);
1884e44d2e94SPouria Mousavizadeh Tehrani 	if (error != 0)
1885e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1886e44d2e94SPouria Mousavizadeh Tehrani 
1887*f4e5b45bSJohn Baldwin #ifdef INET6
1888e44d2e94SPouria Mousavizadeh Tehrani 	if (unsa->sa.sa_family == AF_INET6) {
1889e44d2e94SPouria Mousavizadeh Tehrani 		error = sa6_embedscope(&unsa->sin6, V_ip6_use_defzone);
1890e44d2e94SPouria Mousavizadeh Tehrani 		if (error != 0)
1891e44d2e94SPouria Mousavizadeh Tehrani 			goto ret;
1892e44d2e94SPouria Mousavizadeh Tehrani 	}
1893*f4e5b45bSJohn Baldwin #endif
1894e44d2e94SPouria Mousavizadeh Tehrani 
1895e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1896e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc)) {
1897e44d2e94SPouria Mousavizadeh Tehrani 		geneve_sockaddr_in_copy(&sc->gnv_dst_addr, &unsa->sa);
1898e44d2e94SPouria Mousavizadeh Tehrani 		geneve_setup_interface_hdrlen(sc);
1899e44d2e94SPouria Mousavizadeh Tehrani 	} else
1900e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
1901e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1902e44d2e94SPouria Mousavizadeh Tehrani 
1903e44d2e94SPouria Mousavizadeh Tehrani ret:
1904e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
1905e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "remote address is invalid.");
1906e44d2e94SPouria Mousavizadeh Tehrani 
1907e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EAFNOSUPPORT)
1908e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "address family is not supported.");
1909e44d2e94SPouria Mousavizadeh Tehrani 
1910e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
1911e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
1912e44d2e94SPouria Mousavizadeh Tehrani 
1913e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1914e44d2e94SPouria Mousavizadeh Tehrani }
1915e44d2e94SPouria Mousavizadeh Tehrani 
1916e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_local_port_nl(struct geneve_softc * sc,struct nl_pstate * npt,uint16_t port)1917e44d2e94SPouria Mousavizadeh Tehrani geneve_set_local_port_nl(struct geneve_softc *sc, struct nl_pstate *npt, uint16_t port)
1918e44d2e94SPouria Mousavizadeh Tehrani {
1919e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1920e44d2e94SPouria Mousavizadeh Tehrani 
1921e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
1922e44d2e94SPouria Mousavizadeh Tehrani 	if (port == 0 || port > UINT16_MAX) {
1923e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
1924e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1925e44d2e94SPouria Mousavizadeh Tehrani 	}
1926e44d2e94SPouria Mousavizadeh Tehrani 
1927e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1928e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc) == 0) {
1929e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WUNLOCK(sc);
1930e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
1931e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1932e44d2e94SPouria Mousavizadeh Tehrani 	}
1933e44d2e94SPouria Mousavizadeh Tehrani 
1934e44d2e94SPouria Mousavizadeh Tehrani 	switch (sc->gnv_src_addr.sa.sa_family) {
1935e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET:
1936e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_src_addr.sin.sin_port = htons(port);
1937e44d2e94SPouria Mousavizadeh Tehrani 		break;
1938e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET6:
1939e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_src_addr.sin6.sin6_port = htons(port);
1940e44d2e94SPouria Mousavizadeh Tehrani 		break;
1941e44d2e94SPouria Mousavizadeh Tehrani 	}
1942e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1943e44d2e94SPouria Mousavizadeh Tehrani 
1944e44d2e94SPouria Mousavizadeh Tehrani ret:
1945e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
1946e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "local port is invalid: %u", port);
1947e44d2e94SPouria Mousavizadeh Tehrani 
1948e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
1949e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
1950e44d2e94SPouria Mousavizadeh Tehrani 
1951e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1952e44d2e94SPouria Mousavizadeh Tehrani }
1953e44d2e94SPouria Mousavizadeh Tehrani 
1954e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_remote_port_nl(struct geneve_softc * sc,struct nl_pstate * npt,uint16_t port)1955e44d2e94SPouria Mousavizadeh Tehrani geneve_set_remote_port_nl(struct geneve_softc *sc, struct nl_pstate *npt, uint16_t port)
1956e44d2e94SPouria Mousavizadeh Tehrani {
1957e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1958e44d2e94SPouria Mousavizadeh Tehrani 
1959e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
1960e44d2e94SPouria Mousavizadeh Tehrani 	if (port == 0 || port > UINT16_MAX) {
1961e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
1962e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1963e44d2e94SPouria Mousavizadeh Tehrani 	}
1964e44d2e94SPouria Mousavizadeh Tehrani 
1965e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
1966e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc) == 0) {
1967e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WUNLOCK(sc);
1968e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
1969e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
1970e44d2e94SPouria Mousavizadeh Tehrani 	}
1971e44d2e94SPouria Mousavizadeh Tehrani 
1972e44d2e94SPouria Mousavizadeh Tehrani 	switch (sc->gnv_dst_addr.sa.sa_family) {
1973e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET:
1974e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_dst_addr.sin.sin_port = htons(port);
1975e44d2e94SPouria Mousavizadeh Tehrani 		break;
1976e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET6:
1977e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_dst_addr.sin6.sin6_port = htons(port);
1978e44d2e94SPouria Mousavizadeh Tehrani 		break;
1979e44d2e94SPouria Mousavizadeh Tehrani 	}
1980e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
1981e44d2e94SPouria Mousavizadeh Tehrani 
1982e44d2e94SPouria Mousavizadeh Tehrani ret:
1983e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
1984e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "remote port is invalid: %u", port);
1985e44d2e94SPouria Mousavizadeh Tehrani 
1986e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
1987e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
1988e44d2e94SPouria Mousavizadeh Tehrani 
1989e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
1990e44d2e94SPouria Mousavizadeh Tehrani }
1991e44d2e94SPouria Mousavizadeh Tehrani 
1992e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_port_range_nl(struct geneve_softc * sc,struct nl_pstate * npt,struct ifla_geneve_port_range port_range)1993e44d2e94SPouria Mousavizadeh Tehrani geneve_set_port_range_nl(struct geneve_softc *sc, struct nl_pstate *npt,
1994e44d2e94SPouria Mousavizadeh Tehrani     struct ifla_geneve_port_range port_range)
1995e44d2e94SPouria Mousavizadeh Tehrani {
1996e44d2e94SPouria Mousavizadeh Tehrani 	int error;
1997e44d2e94SPouria Mousavizadeh Tehrani 
1998e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
1999e44d2e94SPouria Mousavizadeh Tehrani 	if (port_range.low <= 0 || port_range.high > UINT16_MAX ||
2000e44d2e94SPouria Mousavizadeh Tehrani 	    port_range.high < port_range.low) {
2001e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
2002e44d2e94SPouria Mousavizadeh Tehrani 		goto ret;
2003e44d2e94SPouria Mousavizadeh Tehrani 	}
2004e44d2e94SPouria Mousavizadeh Tehrani 
2005e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2006e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc)) {
2007e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_min_port = port_range.low;
2008e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_max_port = port_range.high;
2009e44d2e94SPouria Mousavizadeh Tehrani 	} else
2010e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
2011e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2012e44d2e94SPouria Mousavizadeh Tehrani 
2013e44d2e94SPouria Mousavizadeh Tehrani ret:
2014e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
2015e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "port range is invalid: %u-%u",
2016e44d2e94SPouria Mousavizadeh Tehrani 		    port_range.low, port_range.high);
2017e44d2e94SPouria Mousavizadeh Tehrani 
2018e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
2019e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
2020e44d2e94SPouria Mousavizadeh Tehrani 
2021e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2022e44d2e94SPouria Mousavizadeh Tehrani }
2023e44d2e94SPouria Mousavizadeh Tehrani 
2024e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_df_nl(struct geneve_softc * sc,struct nl_pstate * npt,enum ifla_geneve_df df)2025e44d2e94SPouria Mousavizadeh Tehrani geneve_set_df_nl(struct geneve_softc *sc, struct nl_pstate *npt,
2026e44d2e94SPouria Mousavizadeh Tehrani     enum ifla_geneve_df df)
2027e44d2e94SPouria Mousavizadeh Tehrani {
2028e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2029e44d2e94SPouria Mousavizadeh Tehrani 
2030e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
2031e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2032e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc))
2033e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_df = df;
2034e44d2e94SPouria Mousavizadeh Tehrani 	else
2035e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
2036e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2037e44d2e94SPouria Mousavizadeh Tehrani 
2038e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
2039e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
2040e44d2e94SPouria Mousavizadeh Tehrani 
2041e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2042e44d2e94SPouria Mousavizadeh Tehrani }
2043e44d2e94SPouria Mousavizadeh Tehrani 
2044e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_ttl_nl(struct geneve_softc * sc,struct nl_pstate * npt __unused,uint8_t ttl)2045e44d2e94SPouria Mousavizadeh Tehrani geneve_set_ttl_nl(struct geneve_softc *sc, struct nl_pstate *npt __unused,
2046e44d2e94SPouria Mousavizadeh Tehrani     uint8_t ttl)
2047e44d2e94SPouria Mousavizadeh Tehrani {
2048e44d2e94SPouria Mousavizadeh Tehrani 
2049e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2050e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ttl = ttl;
2051e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_im4o != NULL)
2052e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im4o->imo_multicast_ttl = sc->gnv_ttl;
2053e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_im6o != NULL)
2054e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_im6o->im6o_multicast_hlim = sc->gnv_ttl;
2055e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2056e44d2e94SPouria Mousavizadeh Tehrani 
2057e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2058e44d2e94SPouria Mousavizadeh Tehrani }
2059e44d2e94SPouria Mousavizadeh Tehrani 
2060e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_ttl_inherit_nl(struct geneve_softc * sc,struct nl_pstate * npt __unused,bool inherit)2061e44d2e94SPouria Mousavizadeh Tehrani geneve_set_ttl_inherit_nl(struct geneve_softc *sc,
2062e44d2e94SPouria Mousavizadeh Tehrani     struct nl_pstate *npt __unused, bool inherit)
2063e44d2e94SPouria Mousavizadeh Tehrani {
2064e44d2e94SPouria Mousavizadeh Tehrani 
2065e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2066e44d2e94SPouria Mousavizadeh Tehrani 	if (inherit)
2067e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags |= GENEVE_FLAG_TTL_INHERIT;
2068e44d2e94SPouria Mousavizadeh Tehrani 	else
2069e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags &= ~GENEVE_FLAG_TTL_INHERIT;
2070e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2071e44d2e94SPouria Mousavizadeh Tehrani 
2072e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2073e44d2e94SPouria Mousavizadeh Tehrani }
2074e44d2e94SPouria Mousavizadeh Tehrani 
2075e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_dscp_inherit_nl(struct geneve_softc * sc,struct nl_pstate * npt __unused,bool inherit)2076e44d2e94SPouria Mousavizadeh Tehrani geneve_set_dscp_inherit_nl(struct geneve_softc *sc,
2077e44d2e94SPouria Mousavizadeh Tehrani     struct nl_pstate *npt __unused, bool inherit)
2078e44d2e94SPouria Mousavizadeh Tehrani {
2079e44d2e94SPouria Mousavizadeh Tehrani 
2080e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2081e44d2e94SPouria Mousavizadeh Tehrani 	if (inherit)
2082e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags |= GENEVE_FLAG_DSCP_INHERIT;
2083e44d2e94SPouria Mousavizadeh Tehrani 	else
2084e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags &= ~GENEVE_FLAG_DSCP_INHERIT;
2085e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2086e44d2e94SPouria Mousavizadeh Tehrani 
2087e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2088e44d2e94SPouria Mousavizadeh Tehrani }
2089e44d2e94SPouria Mousavizadeh Tehrani 
2090e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_collect_metadata_nl(struct geneve_softc * sc,struct nl_pstate * npt __unused,bool external)2091e44d2e94SPouria Mousavizadeh Tehrani geneve_set_collect_metadata_nl(struct geneve_softc *sc,
2092e44d2e94SPouria Mousavizadeh Tehrani     struct nl_pstate *npt __unused, bool external)
2093e44d2e94SPouria Mousavizadeh Tehrani {
2094e44d2e94SPouria Mousavizadeh Tehrani 
2095e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2096e44d2e94SPouria Mousavizadeh Tehrani 	if (external)
2097e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags |= GENEVE_FLAG_COLLECT_METADATA;
2098e44d2e94SPouria Mousavizadeh Tehrani 	else
2099e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags &= ~GENEVE_FLAG_COLLECT_METADATA;
2100e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2101e44d2e94SPouria Mousavizadeh Tehrani 
2102e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2103e44d2e94SPouria Mousavizadeh Tehrani }
2104e44d2e94SPouria Mousavizadeh Tehrani 
2105e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_learn_nl(struct geneve_softc * sc,struct nl_pstate * npt,bool learn)2106e44d2e94SPouria Mousavizadeh Tehrani geneve_set_learn_nl(struct geneve_softc *sc, struct nl_pstate *npt,
2107e44d2e94SPouria Mousavizadeh Tehrani     bool learn)
2108e44d2e94SPouria Mousavizadeh Tehrani {
2109e44d2e94SPouria Mousavizadeh Tehrani 
2110e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2111e44d2e94SPouria Mousavizadeh Tehrani 	if (learn)
2112e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags |= GENEVE_FLAG_LEARN;
2113e44d2e94SPouria Mousavizadeh Tehrani 	else
2114e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_flags &= ~GENEVE_FLAG_LEARN;
2115e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2116e44d2e94SPouria Mousavizadeh Tehrani 
2117e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2118e44d2e94SPouria Mousavizadeh Tehrani }
2119e44d2e94SPouria Mousavizadeh Tehrani 
2120e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_ftable_max_nl(struct geneve_softc * sc,struct nl_pstate * npt,uint32_t max)2121e44d2e94SPouria Mousavizadeh Tehrani geneve_set_ftable_max_nl(struct geneve_softc *sc, struct nl_pstate *npt,
2122e44d2e94SPouria Mousavizadeh Tehrani     uint32_t max)
2123e44d2e94SPouria Mousavizadeh Tehrani {
2124e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2125e44d2e94SPouria Mousavizadeh Tehrani 
2126e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
2127e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2128e44d2e94SPouria Mousavizadeh Tehrani 	if (max <= GENEVE_FTABLE_MAX)
2129e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_ftable_max = max;
2130e44d2e94SPouria Mousavizadeh Tehrani 	else
2131e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
2132e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2133e44d2e94SPouria Mousavizadeh Tehrani 
2134e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
2135e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt,
2136e44d2e94SPouria Mousavizadeh Tehrani 		    "maximum number of entries in the table can not be more than %u",
2137e44d2e94SPouria Mousavizadeh Tehrani 		    GENEVE_FTABLE_MAX);
2138e44d2e94SPouria Mousavizadeh Tehrani 
2139e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2140e44d2e94SPouria Mousavizadeh Tehrani }
2141e44d2e94SPouria Mousavizadeh Tehrani 
2142e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_ftable_timeout_nl(struct geneve_softc * sc,struct nl_pstate * npt,uint32_t timeout)2143e44d2e94SPouria Mousavizadeh Tehrani geneve_set_ftable_timeout_nl(struct geneve_softc *sc, struct nl_pstate *npt,
2144e44d2e94SPouria Mousavizadeh Tehrani     uint32_t timeout)
2145e44d2e94SPouria Mousavizadeh Tehrani {
2146e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2147e44d2e94SPouria Mousavizadeh Tehrani 
2148e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
2149e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2150e44d2e94SPouria Mousavizadeh Tehrani 	if (timeout <= GENEVE_FTABLE_MAX_TIMEOUT)
2151e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_ftable_timeout = timeout;
2152e44d2e94SPouria Mousavizadeh Tehrani 	else
2153e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
2154e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2155e44d2e94SPouria Mousavizadeh Tehrani 
2156e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EINVAL)
2157e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt,
2158e44d2e94SPouria Mousavizadeh Tehrani 		    "maximum timeout for stale entries in the table can not be more than %u",
2159e44d2e94SPouria Mousavizadeh Tehrani 		    GENEVE_FTABLE_MAX_TIMEOUT);
2160e44d2e94SPouria Mousavizadeh Tehrani 
2161e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2162e44d2e94SPouria Mousavizadeh Tehrani }
2163e44d2e94SPouria Mousavizadeh Tehrani 
2164e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_mc_if_nl(struct geneve_softc * sc,struct nl_pstate * npt,char * ifname)2165e44d2e94SPouria Mousavizadeh Tehrani geneve_set_mc_if_nl(struct geneve_softc *sc, struct nl_pstate *npt,
2166e44d2e94SPouria Mousavizadeh Tehrani     char *ifname)
2167e44d2e94SPouria Mousavizadeh Tehrani {
2168e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2169e44d2e94SPouria Mousavizadeh Tehrani 
2170e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
2171e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
2172e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_can_change_config(sc)) {
2173e44d2e94SPouria Mousavizadeh Tehrani 		strlcpy(sc->gnv_mc_ifname, ifname, IFNAMSIZ);
2174e44d2e94SPouria Mousavizadeh Tehrani 		geneve_set_hwcaps(sc);
2175e44d2e94SPouria Mousavizadeh Tehrani 	} else
2176e44d2e94SPouria Mousavizadeh Tehrani 		error = EBUSY;
2177e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
2178e44d2e94SPouria Mousavizadeh Tehrani 
2179e44d2e94SPouria Mousavizadeh Tehrani 	if (error == EBUSY)
2180e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve interface is busy.");
2181e44d2e94SPouria Mousavizadeh Tehrani 
2182e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2183e44d2e94SPouria Mousavizadeh Tehrani }
2184e44d2e94SPouria Mousavizadeh Tehrani 
2185e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_flush_ftable_nl(struct geneve_softc * sc,struct nl_pstate * npt,bool flush)2186e44d2e94SPouria Mousavizadeh Tehrani geneve_flush_ftable_nl(struct geneve_softc *sc, struct nl_pstate *npt,
2187e44d2e94SPouria Mousavizadeh Tehrani     bool flush)
2188e44d2e94SPouria Mousavizadeh Tehrani {
2189e44d2e94SPouria Mousavizadeh Tehrani 
2190e44d2e94SPouria Mousavizadeh Tehrani 	return (geneve_flush_ftable(sc, flush));
2191e44d2e94SPouria Mousavizadeh Tehrani }
2192e44d2e94SPouria Mousavizadeh Tehrani 
2193e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_get_local_addr_nl(struct geneve_softc * sc,struct nl_writer * nw)2194e44d2e94SPouria Mousavizadeh Tehrani geneve_get_local_addr_nl(struct geneve_softc *sc, struct nl_writer *nw)
2195e44d2e94SPouria Mousavizadeh Tehrani {
2196e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr *sa;
2197e44d2e94SPouria Mousavizadeh Tehrani 
2198e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
2199e44d2e94SPouria Mousavizadeh Tehrani 
2200e44d2e94SPouria Mousavizadeh Tehrani 	sa = &sc->gnv_src_addr.sa;
2201e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_INET) {
2202e44d2e94SPouria Mousavizadeh Tehrani 		const struct in_addr *in4 = &SATOCONSTSIN(sa)->sin_addr;
2203e44d2e94SPouria Mousavizadeh Tehrani 		nlattr_add_in_addr(nw, IFLA_GENEVE_LOCAL, in4);
2204e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
2205e44d2e94SPouria Mousavizadeh Tehrani 		const struct in6_addr *in6 = &SATOCONSTSIN6(sa)->sin6_addr;
2206e44d2e94SPouria Mousavizadeh Tehrani 		nlattr_add_in6_addr(nw, IFLA_GENEVE_LOCAL, in6);
2207e44d2e94SPouria Mousavizadeh Tehrani 	}
2208e44d2e94SPouria Mousavizadeh Tehrani }
2209e44d2e94SPouria Mousavizadeh Tehrani 
2210e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_get_remote_addr_nl(struct geneve_softc * sc,struct nl_writer * nw)2211e44d2e94SPouria Mousavizadeh Tehrani geneve_get_remote_addr_nl(struct geneve_softc *sc, struct nl_writer *nw)
2212e44d2e94SPouria Mousavizadeh Tehrani {
2213e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr *sa;
2214e44d2e94SPouria Mousavizadeh Tehrani 
2215e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
2216e44d2e94SPouria Mousavizadeh Tehrani 
2217e44d2e94SPouria Mousavizadeh Tehrani 	sa = &sc->gnv_dst_addr.sa;
2218e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_INET) {
2219e44d2e94SPouria Mousavizadeh Tehrani 		const struct in_addr *in4 = &SATOCONSTSIN(sa)->sin_addr;
2220e44d2e94SPouria Mousavizadeh Tehrani 		nlattr_add_in_addr(nw, IFLA_GENEVE_REMOTE, in4);
2221e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
2222e44d2e94SPouria Mousavizadeh Tehrani 		const struct in6_addr *in6 = &SATOCONSTSIN6(sa)->sin6_addr;
2223e44d2e94SPouria Mousavizadeh Tehrani 		nlattr_add_in6_addr(nw, IFLA_GENEVE_REMOTE, in6);
2224e44d2e94SPouria Mousavizadeh Tehrani 	}
2225e44d2e94SPouria Mousavizadeh Tehrani }
2226e44d2e94SPouria Mousavizadeh Tehrani 
2227e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)2228e44d2e94SPouria Mousavizadeh Tehrani geneve_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
2229e44d2e94SPouria Mousavizadeh Tehrani {
2230e44d2e94SPouria Mousavizadeh Tehrani 	struct rm_priotracker tracker;
2231e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
2232e44d2e94SPouria Mousavizadeh Tehrani 	struct siocsifcapnv_driver_data *drv_ioctl_data, drv_ioctl_data_d;
2233e44d2e94SPouria Mousavizadeh Tehrani 	struct ifreq *ifr;
2234e44d2e94SPouria Mousavizadeh Tehrani 	int max, error;
2235e44d2e94SPouria Mousavizadeh Tehrani 
2236e44d2e94SPouria Mousavizadeh Tehrani 	CURVNET_ASSERT_SET();
2237e44d2e94SPouria Mousavizadeh Tehrani 
2238e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
2239e44d2e94SPouria Mousavizadeh Tehrani 	sc = ifp->if_softc;
2240e44d2e94SPouria Mousavizadeh Tehrani 	ifr = (struct ifreq *)data;
2241e44d2e94SPouria Mousavizadeh Tehrani 
2242e44d2e94SPouria Mousavizadeh Tehrani 	switch (cmd) {
2243e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCADDMULTI:
2244e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCDELMULTI:
2245e44d2e94SPouria Mousavizadeh Tehrani 		break;
2246e44d2e94SPouria Mousavizadeh Tehrani 
2247e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCGDRVSPEC:
2248e44d2e94SPouria Mousavizadeh Tehrani 		break;
2249e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSDRVSPEC:
2250e44d2e94SPouria Mousavizadeh Tehrani 		error = priv_check(curthread, PRIV_NET_GENEVE);
2251e44d2e94SPouria Mousavizadeh Tehrani 		if (error)
2252e44d2e94SPouria Mousavizadeh Tehrani 			return (error);
2253e44d2e94SPouria Mousavizadeh Tehrani 		break;
2254e44d2e94SPouria Mousavizadeh Tehrani 	}
2255e44d2e94SPouria Mousavizadeh Tehrani 
2256e44d2e94SPouria Mousavizadeh Tehrani 	switch (cmd) {
2257e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSIFFLAGS:
2258e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_ioctl_ifflags(sc);
2259e44d2e94SPouria Mousavizadeh Tehrani 		break;
2260e44d2e94SPouria Mousavizadeh Tehrani 
2261e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSIFMEDIA:
2262e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCGIFMEDIA:
2263e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_proto == GENEVE_PROTO_ETHER)
2264e44d2e94SPouria Mousavizadeh Tehrani 			error = ifmedia_ioctl(ifp, ifr, &sc->gnv_media, cmd);
2265e44d2e94SPouria Mousavizadeh Tehrani 		else
2266e44d2e94SPouria Mousavizadeh Tehrani 			error = EINVAL;
2267e44d2e94SPouria Mousavizadeh Tehrani 		break;
2268e44d2e94SPouria Mousavizadeh Tehrani 
2269e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSIFMTU:
2270e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_proto == GENEVE_PROTO_ETHER)
2271e44d2e94SPouria Mousavizadeh Tehrani 			max = GENEVE_MAX_MTU;
2272e44d2e94SPouria Mousavizadeh Tehrani 		else
2273e44d2e94SPouria Mousavizadeh Tehrani 			max = GENEVE_MAX_L3MTU;
2274e44d2e94SPouria Mousavizadeh Tehrani 
2275e44d2e94SPouria Mousavizadeh Tehrani 		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > max)
2276e44d2e94SPouria Mousavizadeh Tehrani 			error = EINVAL;
2277e44d2e94SPouria Mousavizadeh Tehrani 		else {
2278e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_WLOCK(sc);
2279e44d2e94SPouria Mousavizadeh Tehrani 			ifp->if_mtu = ifr->ifr_mtu;
2280e44d2e94SPouria Mousavizadeh Tehrani 			sc->gnv_flags |= GENEVE_FLAG_USER_MTU;
2281e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_WUNLOCK(sc);
2282e44d2e94SPouria Mousavizadeh Tehrani 		}
2283e44d2e94SPouria Mousavizadeh Tehrani 		break;
2284e44d2e94SPouria Mousavizadeh Tehrani 
2285e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCGIFCAPNV:
2286e44d2e94SPouria Mousavizadeh Tehrani 		break;
2287e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSIFCAP:
2288e44d2e94SPouria Mousavizadeh Tehrani 		drv_ioctl_data = &drv_ioctl_data_d;
2289e44d2e94SPouria Mousavizadeh Tehrani 		drv_ioctl_data->reqcap = ifr->ifr_reqcap;
2290e44d2e94SPouria Mousavizadeh Tehrani 		drv_ioctl_data->reqcap2 = if_getcapenable2(ifp);
2291e44d2e94SPouria Mousavizadeh Tehrani 		drv_ioctl_data->nvcap = NULL;
2292e44d2e94SPouria Mousavizadeh Tehrani 		/* FALLTHROUGH */
2293e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSIFCAPNV:
2294e44d2e94SPouria Mousavizadeh Tehrani 		if (cmd == SIOCSIFCAPNV)
2295e44d2e94SPouria Mousavizadeh Tehrani 			drv_ioctl_data = (struct siocsifcapnv_driver_data *)data;
2296e44d2e94SPouria Mousavizadeh Tehrani 
2297e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WLOCK(sc);
2298e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_reqcap(sc, ifp, drv_ioctl_data->reqcap,
2299e44d2e94SPouria Mousavizadeh Tehrani 		    drv_ioctl_data->reqcap2);
2300e44d2e94SPouria Mousavizadeh Tehrani 		if (error == 0)
2301e44d2e94SPouria Mousavizadeh Tehrani 			geneve_set_hwcaps(sc);
2302e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_WUNLOCK(sc);
2303e44d2e94SPouria Mousavizadeh Tehrani 		break;
2304e44d2e94SPouria Mousavizadeh Tehrani 
2305e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCGTUNFIB:
2306e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_RLOCK(sc, &tracker);
2307e44d2e94SPouria Mousavizadeh Tehrani 		ifr->ifr_fib = sc->gnv_fibnum;
2308e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_RUNLOCK(sc, &tracker);
2309e44d2e94SPouria Mousavizadeh Tehrani 		break;
2310e44d2e94SPouria Mousavizadeh Tehrani 
2311e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSTUNFIB:
2312e44d2e94SPouria Mousavizadeh Tehrani 		if ((error = priv_check(curthread, PRIV_NET_GENEVE)) != 0)
2313e44d2e94SPouria Mousavizadeh Tehrani 			break;
2314e44d2e94SPouria Mousavizadeh Tehrani 
2315e44d2e94SPouria Mousavizadeh Tehrani 		if (ifr->ifr_fib >= rt_numfibs)
2316e44d2e94SPouria Mousavizadeh Tehrani 			error = EINVAL;
2317e44d2e94SPouria Mousavizadeh Tehrani 		else {
2318e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_WLOCK(sc);
2319e44d2e94SPouria Mousavizadeh Tehrani 			sc->gnv_fibnum = ifr->ifr_fib;
2320e44d2e94SPouria Mousavizadeh Tehrani 			GENEVE_WUNLOCK(sc);
2321e44d2e94SPouria Mousavizadeh Tehrani 		}
2322e44d2e94SPouria Mousavizadeh Tehrani 		break;
2323e44d2e94SPouria Mousavizadeh Tehrani 
2324e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCSIFADDR:
2325e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_flags |= IFF_UP;
2326e44d2e94SPouria Mousavizadeh Tehrani 		/* FALLTHROUGH */
2327e44d2e94SPouria Mousavizadeh Tehrani 	case SIOCGIFADDR:
2328e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_proto == GENEVE_PROTO_ETHER)
2329e44d2e94SPouria Mousavizadeh Tehrani 			error = ether_ioctl(ifp, cmd, data);
2330e44d2e94SPouria Mousavizadeh Tehrani 		break;
2331e44d2e94SPouria Mousavizadeh Tehrani 
2332e44d2e94SPouria Mousavizadeh Tehrani 	default:
2333e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_proto == GENEVE_PROTO_ETHER)
2334e44d2e94SPouria Mousavizadeh Tehrani 			error = ether_ioctl(ifp, cmd, data);
2335e44d2e94SPouria Mousavizadeh Tehrani 		else
2336e44d2e94SPouria Mousavizadeh Tehrani 			error = EINVAL;
2337e44d2e94SPouria Mousavizadeh Tehrani 		break;
2338e44d2e94SPouria Mousavizadeh Tehrani 	}
2339e44d2e94SPouria Mousavizadeh Tehrani 
2340e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2341e44d2e94SPouria Mousavizadeh Tehrani }
2342e44d2e94SPouria Mousavizadeh Tehrani 
2343e44d2e94SPouria Mousavizadeh Tehrani static uint16_t
geneve_pick_source_port(struct geneve_softc * sc,struct mbuf * m)2344e44d2e94SPouria Mousavizadeh Tehrani geneve_pick_source_port(struct geneve_softc *sc, struct mbuf *m)
2345e44d2e94SPouria Mousavizadeh Tehrani {
2346e44d2e94SPouria Mousavizadeh Tehrani 	int range;
2347e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t hash;
2348e44d2e94SPouria Mousavizadeh Tehrani 
2349e44d2e94SPouria Mousavizadeh Tehrani 	range = sc->gnv_max_port - sc->gnv_min_port + 1;
2350e44d2e94SPouria Mousavizadeh Tehrani 
2351e44d2e94SPouria Mousavizadeh Tehrani 	/* RFC 8926 Section 3.3-2.2.1 */
2352e44d2e94SPouria Mousavizadeh Tehrani 	if (M_HASHTYPE_ISHASH(m))
2353e44d2e94SPouria Mousavizadeh Tehrani 		hash = m->m_pkthdr.flowid;
2354e44d2e94SPouria Mousavizadeh Tehrani 	else
2355e44d2e94SPouria Mousavizadeh Tehrani 		hash = jenkins_hash(m->m_data, ETHER_HDR_LEN, sc->gnv_port_hash_key);
2356e44d2e94SPouria Mousavizadeh Tehrani 
2357e44d2e94SPouria Mousavizadeh Tehrani 	return (sc->gnv_min_port + (hash % range));
2358e44d2e94SPouria Mousavizadeh Tehrani }
2359e44d2e94SPouria Mousavizadeh Tehrani 
2360e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_encap_header(struct geneve_softc * sc,struct mbuf * m,int ipoff,uint16_t srcport,uint16_t dstport,uint16_t proto)2361e44d2e94SPouria Mousavizadeh Tehrani geneve_encap_header(struct geneve_softc *sc, struct mbuf *m, int ipoff,
2362e44d2e94SPouria Mousavizadeh Tehrani     uint16_t srcport, uint16_t dstport, uint16_t proto)
2363e44d2e94SPouria Mousavizadeh Tehrani {
2364e44d2e94SPouria Mousavizadeh Tehrani 	struct geneveudphdr *hdr;
2365e44d2e94SPouria Mousavizadeh Tehrani 	struct udphdr *udph;
2366e44d2e94SPouria Mousavizadeh Tehrani 	struct genevehdr *gnvh;
2367e44d2e94SPouria Mousavizadeh Tehrani 	int len;
2368e44d2e94SPouria Mousavizadeh Tehrani 
2369e44d2e94SPouria Mousavizadeh Tehrani 	len = m->m_pkthdr.len - ipoff;
2370e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(len >= sizeof(struct geneveudphdr));
2371e44d2e94SPouria Mousavizadeh Tehrani 	hdr = mtodo(m, ipoff);
2372e44d2e94SPouria Mousavizadeh Tehrani 
2373e44d2e94SPouria Mousavizadeh Tehrani 	udph = &hdr->geneve_udp;
2374e44d2e94SPouria Mousavizadeh Tehrani 	udph->uh_sport = srcport;
2375e44d2e94SPouria Mousavizadeh Tehrani 	udph->uh_dport = dstport;
2376e44d2e94SPouria Mousavizadeh Tehrani 	udph->uh_ulen = htons(len);
2377e44d2e94SPouria Mousavizadeh Tehrani 	udph->uh_sum = 0;
2378e44d2e94SPouria Mousavizadeh Tehrani 
2379e44d2e94SPouria Mousavizadeh Tehrani 	gnvh = &hdr->geneve_hdr;
2380e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_ver = 0;
2381e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_optlen = 0;
2382e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_critical = 0;
2383e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_control = 0;
2384e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_flags = 0;
2385e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_proto = proto;
2386e44d2e94SPouria Mousavizadeh Tehrani 	gnvh->geneve_vni = htonl(sc->gnv_vni << GENEVE_HDR_VNI_SHIFT);
2387e44d2e94SPouria Mousavizadeh Tehrani }
2388e44d2e94SPouria Mousavizadeh Tehrani 
2389e44d2e94SPouria Mousavizadeh Tehrani /* Return the CSUM_INNER_* equivalent of CSUM_* caps. */
2390e44d2e94SPouria Mousavizadeh Tehrani static uint32_t
csum_flags_to_inner_flags(uint32_t csum_flags_in,const uint32_t encap)2391e44d2e94SPouria Mousavizadeh Tehrani csum_flags_to_inner_flags(uint32_t csum_flags_in, const uint32_t encap)
2392e44d2e94SPouria Mousavizadeh Tehrani {
2393e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t csum_flags = encap;
2394e44d2e94SPouria Mousavizadeh Tehrani 	const uint32_t v4 = CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP;
2395e44d2e94SPouria Mousavizadeh Tehrani 
2396e44d2e94SPouria Mousavizadeh Tehrani 	/*
2397e44d2e94SPouria Mousavizadeh Tehrani 	 * csum_flags can request either v4 or v6 offload but not both.
2398e44d2e94SPouria Mousavizadeh Tehrani 	 * tcp_output always sets CSUM_TSO (both CSUM_IP_TSO and CSUM_IP6_TSO)
2399e44d2e94SPouria Mousavizadeh Tehrani 	 * so those bits are no good to detect the IP version.  Other bits are
2400e44d2e94SPouria Mousavizadeh Tehrani 	 * always set with CSUM_TSO and we use those to figure out the IP
2401e44d2e94SPouria Mousavizadeh Tehrani 	 * version.
2402e44d2e94SPouria Mousavizadeh Tehrani 	 */
2403e44d2e94SPouria Mousavizadeh Tehrani 	if (csum_flags_in & v4) {
2404e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP)
2405e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP;
2406e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP_UDP)
2407e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP_UDP;
2408e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP_TCP)
2409e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP_TCP;
2410e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP_TSO)
2411e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP_TSO;
2412e44d2e94SPouria Mousavizadeh Tehrani 	} else {
2413e44d2e94SPouria Mousavizadeh Tehrani #ifdef INVARIANTS
2414e44d2e94SPouria Mousavizadeh Tehrani 		const uint32_t v6 = CSUM_IP6_UDP | CSUM_IP6_TCP;
2415e44d2e94SPouria Mousavizadeh Tehrani 		MPASS((csum_flags_in & v6) != 0);
2416e44d2e94SPouria Mousavizadeh Tehrani #endif
2417e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP6_UDP)
2418e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP6_UDP;
2419e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP6_TCP)
2420e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP6_TCP;
2421e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags_in & CSUM_IP6_TSO)
2422e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_INNER_IP6_TSO;
2423e44d2e94SPouria Mousavizadeh Tehrani 	}
2424e44d2e94SPouria Mousavizadeh Tehrani 
2425e44d2e94SPouria Mousavizadeh Tehrani 	return (csum_flags);
2426e44d2e94SPouria Mousavizadeh Tehrani }
2427e44d2e94SPouria Mousavizadeh Tehrani 
2428e44d2e94SPouria Mousavizadeh Tehrani static uint16_t
geneve_get_ethertype(struct mbuf * m)2429e44d2e94SPouria Mousavizadeh Tehrani geneve_get_ethertype(struct mbuf *m)
2430e44d2e94SPouria Mousavizadeh Tehrani {
2431e44d2e94SPouria Mousavizadeh Tehrani 	struct ip *ip;
2432e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_hdr *ip6;
2433e44d2e94SPouria Mousavizadeh Tehrani 
2434e44d2e94SPouria Mousavizadeh Tehrani 	/*
2435e44d2e94SPouria Mousavizadeh Tehrani 	 * We should pullup, but we're only interested in the first byte, so
2436e44d2e94SPouria Mousavizadeh Tehrani 	 * that'll always be contiguous.
2437e44d2e94SPouria Mousavizadeh Tehrani 	 */
2438e44d2e94SPouria Mousavizadeh Tehrani 	ip = mtod(m, struct ip *);
2439e44d2e94SPouria Mousavizadeh Tehrani 	if (ip->ip_v == IPVERSION)
2440e44d2e94SPouria Mousavizadeh Tehrani 		return (ETHERTYPE_IP);
2441e44d2e94SPouria Mousavizadeh Tehrani 
2442e44d2e94SPouria Mousavizadeh Tehrani 	ip6 = mtod(m, struct ip6_hdr *);
2443e44d2e94SPouria Mousavizadeh Tehrani 	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION)
2444e44d2e94SPouria Mousavizadeh Tehrani 		return (ETHERTYPE_IPV6);
2445e44d2e94SPouria Mousavizadeh Tehrani 
2446e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2447e44d2e94SPouria Mousavizadeh Tehrani }
2448e44d2e94SPouria Mousavizadeh Tehrani 
2449e44d2e94SPouria Mousavizadeh Tehrani /* RFC 8926 Section 4.4.2. DSCP, ECN, and TTL */
2450e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_inherit_l3_hdr(struct mbuf * m,struct geneve_softc * sc,uint16_t proto,uint8_t * tos,uint8_t * ttl,u_short * ip_off)2451e44d2e94SPouria Mousavizadeh Tehrani geneve_inherit_l3_hdr(struct mbuf *m, struct geneve_softc *sc, uint16_t proto,
2452e44d2e94SPouria Mousavizadeh Tehrani     uint8_t *tos, uint8_t *ttl, u_short *ip_off)
2453e44d2e94SPouria Mousavizadeh Tehrani {
2454e44d2e94SPouria Mousavizadeh Tehrani 	struct ether_header *eh;
2455e44d2e94SPouria Mousavizadeh Tehrani 	struct ip *ip_inner, iphdr;
2456e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_hdr *ip6_inner, ip6hdr;
2457e44d2e94SPouria Mousavizadeh Tehrani 	int offset;
2458e44d2e94SPouria Mousavizadeh Tehrani 
2459e44d2e94SPouria Mousavizadeh Tehrani 	*tos = 0;
2460e44d2e94SPouria Mousavizadeh Tehrani 	*ttl = sc->gnv_ttl;
2461e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_df == IFLA_GENEVE_DF_SET)
2462e44d2e94SPouria Mousavizadeh Tehrani 		*ip_off = htons(IP_DF);
2463e44d2e94SPouria Mousavizadeh Tehrani 	else
2464e44d2e94SPouria Mousavizadeh Tehrani 		*ip_off = 0;
2465e44d2e94SPouria Mousavizadeh Tehrani 
2466e44d2e94SPouria Mousavizadeh Tehrani 	/* Set offset and address family if proto is ethernet */
2467e44d2e94SPouria Mousavizadeh Tehrani 	if (proto == GENEVE_PROTO_ETHER) {
2468e44d2e94SPouria Mousavizadeh Tehrani 		eh = mtod(m, struct ether_header *);
2469e44d2e94SPouria Mousavizadeh Tehrani 		if (eh->ether_type == htons(ETHERTYPE_IP)) {
2470e44d2e94SPouria Mousavizadeh Tehrani 			if (m->m_pkthdr.len < ETHER_HDR_LEN + sizeof(struct ip)) {
2471e44d2e94SPouria Mousavizadeh Tehrani 				m_freem(m);
2472e44d2e94SPouria Mousavizadeh Tehrani 				return (EINVAL);
2473e44d2e94SPouria Mousavizadeh Tehrani 			}
2474e44d2e94SPouria Mousavizadeh Tehrani 			proto = ETHERTYPE_IP;
2475e44d2e94SPouria Mousavizadeh Tehrani 		} else if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2476e44d2e94SPouria Mousavizadeh Tehrani 			if (m->m_pkthdr.len < ETHER_HDR_LEN + sizeof(struct ip6_hdr)) {
2477e44d2e94SPouria Mousavizadeh Tehrani 				m_freem(m);
2478e44d2e94SPouria Mousavizadeh Tehrani 				return (EINVAL);
2479e44d2e94SPouria Mousavizadeh Tehrani 			}
2480e44d2e94SPouria Mousavizadeh Tehrani 			proto = ETHERTYPE_IPV6;
2481e44d2e94SPouria Mousavizadeh Tehrani 		} else
2482e44d2e94SPouria Mousavizadeh Tehrani 			return (0);
2483e44d2e94SPouria Mousavizadeh Tehrani 
2484e44d2e94SPouria Mousavizadeh Tehrani 		offset = ETHER_HDR_LEN;
2485e44d2e94SPouria Mousavizadeh Tehrani 	} else
2486e44d2e94SPouria Mousavizadeh Tehrani 		offset = 0;
2487e44d2e94SPouria Mousavizadeh Tehrani 
2488e44d2e94SPouria Mousavizadeh Tehrani 	switch (proto) {
2489e44d2e94SPouria Mousavizadeh Tehrani 	case ETHERTYPE_IP:
2490e44d2e94SPouria Mousavizadeh Tehrani 		if (__predict_false(m->m_len < offset + sizeof(struct ip))) {
2491e44d2e94SPouria Mousavizadeh Tehrani 			m_copydata(m, offset, sizeof(struct ip), (caddr_t)&iphdr);
2492e44d2e94SPouria Mousavizadeh Tehrani 			ip_inner = &iphdr;
2493e44d2e94SPouria Mousavizadeh Tehrani 		} else
2494e44d2e94SPouria Mousavizadeh Tehrani 			ip_inner = mtodo(m, offset);
2495e44d2e94SPouria Mousavizadeh Tehrani 
2496e44d2e94SPouria Mousavizadeh Tehrani 		*tos = ip_inner->ip_tos;
2497e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_flags & GENEVE_FLAG_TTL_INHERIT)
2498e44d2e94SPouria Mousavizadeh Tehrani 			*ttl = ip_inner->ip_ttl;
2499e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_df == IFLA_GENEVE_DF_INHERIT)
2500e44d2e94SPouria Mousavizadeh Tehrani 			*ip_off = ip_inner->ip_off;
2501e44d2e94SPouria Mousavizadeh Tehrani 		break;
2502e44d2e94SPouria Mousavizadeh Tehrani 
2503e44d2e94SPouria Mousavizadeh Tehrani 	case ETHERTYPE_IPV6:
2504e44d2e94SPouria Mousavizadeh Tehrani 		if (__predict_false(m->m_len < offset + sizeof(struct ip6_hdr))) {
2505e44d2e94SPouria Mousavizadeh Tehrani 			m_copydata(m, offset, sizeof(struct ip6_hdr), (caddr_t)&ip6hdr);
2506e44d2e94SPouria Mousavizadeh Tehrani 			ip6_inner = &ip6hdr;
2507e44d2e94SPouria Mousavizadeh Tehrani 		} else
2508e44d2e94SPouria Mousavizadeh Tehrani 			ip6_inner = mtodo(m, offset);
2509e44d2e94SPouria Mousavizadeh Tehrani 
2510e44d2e94SPouria Mousavizadeh Tehrani 		*tos = IPV6_TRAFFIC_CLASS(ip6_inner);
2511e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_flags & GENEVE_FLAG_TTL_INHERIT)
2512e44d2e94SPouria Mousavizadeh Tehrani 			*ttl = ip6_inner->ip6_hlim;
2513e44d2e94SPouria Mousavizadeh Tehrani 		break;
2514e44d2e94SPouria Mousavizadeh Tehrani 	}
2515e44d2e94SPouria Mousavizadeh Tehrani 
2516e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2517e44d2e94SPouria Mousavizadeh Tehrani }
2518e44d2e94SPouria Mousavizadeh Tehrani 
2519*f4e5b45bSJohn Baldwin #ifdef INET
2520e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_encap4(struct geneve_softc * sc,const union sockaddr_union * funsa,struct mbuf * m)2521e44d2e94SPouria Mousavizadeh Tehrani geneve_encap4(struct geneve_softc *sc, const union sockaddr_union *funsa,
2522e44d2e94SPouria Mousavizadeh Tehrani     struct mbuf *m)
2523e44d2e94SPouria Mousavizadeh Tehrani {
2524e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
2525e44d2e94SPouria Mousavizadeh Tehrani 	struct ip *ip;
2526e44d2e94SPouria Mousavizadeh Tehrani 	struct in_addr srcaddr, dstaddr;
2527e44d2e94SPouria Mousavizadeh Tehrani 	struct route route, *ro;
2528e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr_in *sin;
2529e44d2e94SPouria Mousavizadeh Tehrani 	int plen, error;
2530e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t csum_flags;
2531e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t srcport, dstport, proto;
2532e44d2e94SPouria Mousavizadeh Tehrani 	u_short ip_off;
2533e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t tos, ecn, ttl;
2534e44d2e94SPouria Mousavizadeh Tehrani 	bool mcast;
2535e44d2e94SPouria Mousavizadeh Tehrani 
2536e44d2e94SPouria Mousavizadeh Tehrani 	NET_EPOCH_ASSERT();
2537e44d2e94SPouria Mousavizadeh Tehrani 
2538e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
2539e44d2e94SPouria Mousavizadeh Tehrani 	srcaddr = sc->gnv_src_addr.sin.sin_addr;
2540e44d2e94SPouria Mousavizadeh Tehrani 	srcport = htons(geneve_pick_source_port(sc, m));
2541e44d2e94SPouria Mousavizadeh Tehrani 	dstaddr = funsa->sin.sin_addr;
2542e44d2e94SPouria Mousavizadeh Tehrani 	dstport = funsa->sin.sin_port;
2543e44d2e94SPouria Mousavizadeh Tehrani 	plen = m->m_pkthdr.len;
2544e44d2e94SPouria Mousavizadeh Tehrani 
2545e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER)
2546e44d2e94SPouria Mousavizadeh Tehrani 		proto = sc->gnv_proto;
2547e44d2e94SPouria Mousavizadeh Tehrani 	else
2548e44d2e94SPouria Mousavizadeh Tehrani 		proto = geneve_get_ethertype(m);
2549e44d2e94SPouria Mousavizadeh Tehrani 
2550e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_inherit_l3_hdr(m, sc, proto, &tos, &ttl, &ip_off);
2551e44d2e94SPouria Mousavizadeh Tehrani 	if (error) {
2552e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2553e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
2554e44d2e94SPouria Mousavizadeh Tehrani 	}
2555e44d2e94SPouria Mousavizadeh Tehrani 
2556e44d2e94SPouria Mousavizadeh Tehrani 	M_PREPEND(m, sizeof(struct ip) + sizeof(struct geneveudphdr), M_NOWAIT);
2557e44d2e94SPouria Mousavizadeh Tehrani 	if (m == NULL) {
2558e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2559e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOBUFS);
2560e44d2e94SPouria Mousavizadeh Tehrani 	}
2561e44d2e94SPouria Mousavizadeh Tehrani 	ip = mtod(m, struct ip *);
2562e44d2e94SPouria Mousavizadeh Tehrani 
2563e44d2e94SPouria Mousavizadeh Tehrani 	ecn = (tos & IPTOS_ECN_MASK);
2564e44d2e94SPouria Mousavizadeh Tehrani 	ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &ecn);
2565e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_DSCP_INHERIT)
2566e44d2e94SPouria Mousavizadeh Tehrani 		ip->ip_tos |= (tos & ~IPTOS_ECN_MASK);
2567e44d2e94SPouria Mousavizadeh Tehrani 
2568e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_len = htons(m->m_pkthdr.len);
2569e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_off = ip_off;
2570e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_ttl = ttl;
2571e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_p = IPPROTO_UDP;
2572e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_sum = 0;
2573e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_src = srcaddr;
2574e44d2e94SPouria Mousavizadeh Tehrani 	ip->ip_dst = dstaddr;
2575e44d2e94SPouria Mousavizadeh Tehrani 
2576e44d2e94SPouria Mousavizadeh Tehrani 	geneve_encap_header(sc, m, sizeof(struct ip), srcport, dstport, htons(proto));
2577e44d2e94SPouria Mousavizadeh Tehrani 	mcast = (m->m_flags & (M_MCAST | M_BCAST));
2578e44d2e94SPouria Mousavizadeh Tehrani 	m->m_flags &= ~(M_MCAST | M_BCAST);
2579e44d2e94SPouria Mousavizadeh Tehrani 
2580e44d2e94SPouria Mousavizadeh Tehrani 	m->m_pkthdr.csum_flags &= CSUM_FLAGS_TX;
2581e44d2e94SPouria Mousavizadeh Tehrani 	if (m->m_pkthdr.csum_flags != 0) {
2582e44d2e94SPouria Mousavizadeh Tehrani 		/*
2583e44d2e94SPouria Mousavizadeh Tehrani 		 * HW checksum (L3 and/or L4) or TSO has been requested.
2584e44d2e94SPouria Mousavizadeh Tehrani 		 * Look up the ifnet for the outbound route and verify that the
2585e44d2e94SPouria Mousavizadeh Tehrani 		 * outbound ifnet can perform the requested operation on the inner frame.
2586e44d2e94SPouria Mousavizadeh Tehrani 		 */
2587e44d2e94SPouria Mousavizadeh Tehrani 		memset(&route, 0, sizeof(route));
2588e44d2e94SPouria Mousavizadeh Tehrani 		ro = &route;
2589e44d2e94SPouria Mousavizadeh Tehrani 		sin = (struct sockaddr_in *)&ro->ro_dst;
2590e44d2e94SPouria Mousavizadeh Tehrani 		sin->sin_family = AF_INET;
2591e44d2e94SPouria Mousavizadeh Tehrani 		sin->sin_len = sizeof(*sin);
2592e44d2e94SPouria Mousavizadeh Tehrani 		sin->sin_addr = ip->ip_dst;
2593e44d2e94SPouria Mousavizadeh Tehrani 		ro->ro_nh = fib4_lookup(M_GETFIB(m), ip->ip_dst, 0, NHR_NONE, 0);
2594e44d2e94SPouria Mousavizadeh Tehrani 		if (ro->ro_nh == NULL) {
2595e44d2e94SPouria Mousavizadeh Tehrani 			m_freem(m);
2596e44d2e94SPouria Mousavizadeh Tehrani 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2597e44d2e94SPouria Mousavizadeh Tehrani 			return (EHOSTUNREACH);
2598e44d2e94SPouria Mousavizadeh Tehrani 		}
2599e44d2e94SPouria Mousavizadeh Tehrani 
2600e44d2e94SPouria Mousavizadeh Tehrani 		csum_flags = csum_flags_to_inner_flags(m->m_pkthdr.csum_flags,
2601e44d2e94SPouria Mousavizadeh Tehrani 		    CSUM_ENCAP_GENEVE);
2602e44d2e94SPouria Mousavizadeh Tehrani 		if ((csum_flags & ro->ro_nh->nh_ifp->if_hwassist) != csum_flags) {
2603e44d2e94SPouria Mousavizadeh Tehrani 			if (ppsratecheck(&sc->err_time, &sc->err_pps, 1)) {
2604e44d2e94SPouria Mousavizadeh Tehrani 				const struct ifnet *nh_ifp = ro->ro_nh->nh_ifp;
2605e44d2e94SPouria Mousavizadeh Tehrani 
2606e44d2e94SPouria Mousavizadeh Tehrani 				if_printf(ifp, "interface %s is missing hwcaps "
2607e44d2e94SPouria Mousavizadeh Tehrani 				    "0x%08x, csum_flags 0x%08x -> 0x%08x, "
2608e44d2e94SPouria Mousavizadeh Tehrani 				    "hwassist 0x%08x\n", nh_ifp->if_xname,
2609e44d2e94SPouria Mousavizadeh Tehrani 				    csum_flags & ~(uint32_t)nh_ifp->if_hwassist,
2610e44d2e94SPouria Mousavizadeh Tehrani 				    m->m_pkthdr.csum_flags, csum_flags,
2611e44d2e94SPouria Mousavizadeh Tehrani 				    (uint32_t)nh_ifp->if_hwassist);
2612e44d2e94SPouria Mousavizadeh Tehrani 			}
2613e44d2e94SPouria Mousavizadeh Tehrani 			m_freem(m);
2614e44d2e94SPouria Mousavizadeh Tehrani 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2615e44d2e94SPouria Mousavizadeh Tehrani 			return (ENXIO);
2616e44d2e94SPouria Mousavizadeh Tehrani 		}
2617e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_flags = csum_flags;
2618e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags & (CSUM_INNER_IP | CSUM_INNER_IP_UDP |
2619e44d2e94SPouria Mousavizadeh Tehrani 		    CSUM_INNER_IP6_UDP | CSUM_INNER_IP_TCP | CSUM_INNER_IP6_TCP)) {
2620e44d2e94SPouria Mousavizadeh Tehrani 			counter_u64_add(sc->gnv_stats.txcsum, 1);
2621e44d2e94SPouria Mousavizadeh Tehrani 			if (csum_flags & CSUM_INNER_TSO)
2622e44d2e94SPouria Mousavizadeh Tehrani 				counter_u64_add(sc->gnv_stats.tso, 1);
2623e44d2e94SPouria Mousavizadeh Tehrani 		}
2624e44d2e94SPouria Mousavizadeh Tehrani 	} else
2625e44d2e94SPouria Mousavizadeh Tehrani 		ro = NULL;
2626e44d2e94SPouria Mousavizadeh Tehrani 
2627e44d2e94SPouria Mousavizadeh Tehrani 	error = ip_output(m, NULL, ro, 0, sc->gnv_im4o, NULL);
2628e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0) {
2629e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
2630e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OBYTES, plen);
2631e44d2e94SPouria Mousavizadeh Tehrani 		if (mcast)
2632e44d2e94SPouria Mousavizadeh Tehrani 			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
2633e44d2e94SPouria Mousavizadeh Tehrani 	} else
2634e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2635e44d2e94SPouria Mousavizadeh Tehrani 
2636e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2637e44d2e94SPouria Mousavizadeh Tehrani }
2638*f4e5b45bSJohn Baldwin #endif
2639e44d2e94SPouria Mousavizadeh Tehrani 
2640*f4e5b45bSJohn Baldwin #ifdef INET6
2641e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_encap6(struct geneve_softc * sc,const union sockaddr_union * funsa,struct mbuf * m)2642e44d2e94SPouria Mousavizadeh Tehrani geneve_encap6(struct geneve_softc *sc, const union sockaddr_union *funsa,
2643e44d2e94SPouria Mousavizadeh Tehrani     struct mbuf *m)
2644e44d2e94SPouria Mousavizadeh Tehrani {
2645e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
2646e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_hdr *ip6;
2647e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_pktopts opts;
2648e44d2e94SPouria Mousavizadeh Tehrani 	struct sockaddr_in6 *sin6;
2649e44d2e94SPouria Mousavizadeh Tehrani 	struct route_in6 route, *ro;
2650e44d2e94SPouria Mousavizadeh Tehrani 	const struct in6_addr *srcaddr, *dstaddr;
2651e44d2e94SPouria Mousavizadeh Tehrani 	int plen, error;
2652e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t csum_flags;
2653e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t srcport, dstport, proto;
2654e44d2e94SPouria Mousavizadeh Tehrani 	u_short ip6_df;
2655e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t tos, ecn, etos, ttl;
2656e44d2e94SPouria Mousavizadeh Tehrani 	bool mcast;
2657e44d2e94SPouria Mousavizadeh Tehrani 
2658e44d2e94SPouria Mousavizadeh Tehrani 	NET_EPOCH_ASSERT();
2659e44d2e94SPouria Mousavizadeh Tehrani 
2660e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
2661e44d2e94SPouria Mousavizadeh Tehrani 	srcaddr = &sc->gnv_src_addr.sin6.sin6_addr;
2662e44d2e94SPouria Mousavizadeh Tehrani 	srcport = htons(geneve_pick_source_port(sc, m));
2663e44d2e94SPouria Mousavizadeh Tehrani 	dstaddr = &funsa->sin6.sin6_addr;
2664e44d2e94SPouria Mousavizadeh Tehrani 	dstport = funsa->sin6.sin6_port;
2665e44d2e94SPouria Mousavizadeh Tehrani 	plen = m->m_pkthdr.len;
2666e44d2e94SPouria Mousavizadeh Tehrani 
2667e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER)
2668e44d2e94SPouria Mousavizadeh Tehrani 		proto = sc->gnv_proto;
2669e44d2e94SPouria Mousavizadeh Tehrani 	else
2670e44d2e94SPouria Mousavizadeh Tehrani 		proto = geneve_get_ethertype(m);
2671e44d2e94SPouria Mousavizadeh Tehrani 
2672e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_inherit_l3_hdr(m, sc, proto, &tos, &ttl, &ip6_df);
2673e44d2e94SPouria Mousavizadeh Tehrani 	if (error) {
2674e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2675e44d2e94SPouria Mousavizadeh Tehrani 			return (error);
2676e44d2e94SPouria Mousavizadeh Tehrani 	}
2677e44d2e94SPouria Mousavizadeh Tehrani 
2678e44d2e94SPouria Mousavizadeh Tehrani 	ip6_initpktopts(&opts);
2679e44d2e94SPouria Mousavizadeh Tehrani 	if (ip6_df)
2680e44d2e94SPouria Mousavizadeh Tehrani 		opts.ip6po_flags = IP6PO_DONTFRAG;
2681e44d2e94SPouria Mousavizadeh Tehrani 
2682e44d2e94SPouria Mousavizadeh Tehrani 	M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct geneveudphdr), M_NOWAIT);
2683e44d2e94SPouria Mousavizadeh Tehrani 	if (m == NULL) {
2684e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2685e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOBUFS);
2686e44d2e94SPouria Mousavizadeh Tehrani 	}
2687e44d2e94SPouria Mousavizadeh Tehrani 
2688e44d2e94SPouria Mousavizadeh Tehrani 	ip6 = mtod(m, struct ip6_hdr *);
2689e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_flow = 0;
2690e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_vfc = IPV6_VERSION;
2691e44d2e94SPouria Mousavizadeh Tehrani 
2692e44d2e94SPouria Mousavizadeh Tehrani 	ecn = (tos & IPTOS_ECN_MASK);
2693e44d2e94SPouria Mousavizadeh Tehrani 	ip_ecn_ingress(ECN_ALLOWED, &etos, &ecn);
2694e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_flow |= htonl((u_int32_t)etos << IPV6_FLOWLABEL_LEN);
2695e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_DSCP_INHERIT)
2696e44d2e94SPouria Mousavizadeh Tehrani 		ip6->ip6_flow |= htonl((u_int32_t)tos << IPV6_FLOWLABEL_LEN);
2697e44d2e94SPouria Mousavizadeh Tehrani 
2698e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_plen = 0;
2699e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_nxt = IPPROTO_UDP;
2700e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_hlim = ttl;
2701e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_src = *srcaddr;
2702e44d2e94SPouria Mousavizadeh Tehrani 	ip6->ip6_dst = *dstaddr;
2703e44d2e94SPouria Mousavizadeh Tehrani 
2704e44d2e94SPouria Mousavizadeh Tehrani 	geneve_encap_header(sc, m, sizeof(struct ip6_hdr), srcport, dstport,
2705e44d2e94SPouria Mousavizadeh Tehrani 	    htons(proto));
2706e44d2e94SPouria Mousavizadeh Tehrani 	mcast = (m->m_flags & (M_MCAST | M_BCAST));
2707e44d2e94SPouria Mousavizadeh Tehrani 	m->m_flags &= ~(M_MCAST | M_BCAST);
2708e44d2e94SPouria Mousavizadeh Tehrani 
2709e44d2e94SPouria Mousavizadeh Tehrani 	ro = NULL;
2710e44d2e94SPouria Mousavizadeh Tehrani 	m->m_pkthdr.csum_flags &= CSUM_FLAGS_TX;
2711e44d2e94SPouria Mousavizadeh Tehrani 	if (mcast || m->m_pkthdr.csum_flags != 0) {
2712e44d2e94SPouria Mousavizadeh Tehrani 		/*
2713e44d2e94SPouria Mousavizadeh Tehrani 		 * HW checksum (L3 and/or L4) or TSO has been requested.  Look
2714e44d2e94SPouria Mousavizadeh Tehrani 		 * up the ifnet for the outbound route and verify that the
2715e44d2e94SPouria Mousavizadeh Tehrani 		 * outbound ifnet can perform the requested operation on the
2716e44d2e94SPouria Mousavizadeh Tehrani 		 * inner frame.
2717e44d2e94SPouria Mousavizadeh Tehrani 		 * XXX: There's a rare scenario with ipv6 over multicast
2718e44d2e94SPouria Mousavizadeh Tehrani 		 * underlay where, when mc_ifname is set, it causes panics
2719e44d2e94SPouria Mousavizadeh Tehrani 		 * inside a jail. We'll force geneve to select its own outbound
2720e44d2e94SPouria Mousavizadeh Tehrani 		 * interface to avoid this.
2721e44d2e94SPouria Mousavizadeh Tehrani 		 */
2722e44d2e94SPouria Mousavizadeh Tehrani 		memset(&route, 0, sizeof(route));
2723e44d2e94SPouria Mousavizadeh Tehrani 		ro = &route;
2724e44d2e94SPouria Mousavizadeh Tehrani 		sin6 = (struct sockaddr_in6 *)&ro->ro_dst;
2725e44d2e94SPouria Mousavizadeh Tehrani 		sin6->sin6_family = AF_INET6;
2726e44d2e94SPouria Mousavizadeh Tehrani 		sin6->sin6_len = sizeof(*sin6);
2727e44d2e94SPouria Mousavizadeh Tehrani 		sin6->sin6_addr = ip6->ip6_dst;
2728e44d2e94SPouria Mousavizadeh Tehrani 		ro->ro_nh = fib6_lookup(M_GETFIB(m), &ip6->ip6_dst, 0, NHR_NONE, 0);
2729e44d2e94SPouria Mousavizadeh Tehrani 		if (ro->ro_nh == NULL) {
2730e44d2e94SPouria Mousavizadeh Tehrani 			m_freem(m);
2731e44d2e94SPouria Mousavizadeh Tehrani 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2732e44d2e94SPouria Mousavizadeh Tehrani 			return (EHOSTUNREACH);
2733e44d2e94SPouria Mousavizadeh Tehrani 		}
2734e44d2e94SPouria Mousavizadeh Tehrani 	}
2735e44d2e94SPouria Mousavizadeh Tehrani 	if (m->m_pkthdr.csum_flags != 0) {
2736e44d2e94SPouria Mousavizadeh Tehrani 		csum_flags = csum_flags_to_inner_flags(m->m_pkthdr.csum_flags,
2737e44d2e94SPouria Mousavizadeh Tehrani 		    CSUM_ENCAP_GENEVE);
2738e44d2e94SPouria Mousavizadeh Tehrani 		if ((csum_flags & ro->ro_nh->nh_ifp->if_hwassist) != csum_flags) {
2739e44d2e94SPouria Mousavizadeh Tehrani 			if (ppsratecheck(&sc->err_time, &sc->err_pps, 1)) {
2740e44d2e94SPouria Mousavizadeh Tehrani 				const struct ifnet *nh_ifp = ro->ro_nh->nh_ifp;
2741e44d2e94SPouria Mousavizadeh Tehrani 
2742e44d2e94SPouria Mousavizadeh Tehrani 				if_printf(ifp, "interface %s is missing hwcaps "
2743e44d2e94SPouria Mousavizadeh Tehrani 				    "0x%08x, csum_flags 0x%08x -> 0x%08x, "
2744e44d2e94SPouria Mousavizadeh Tehrani 				    "hwassist 0x%08x\n", nh_ifp->if_xname,
2745e44d2e94SPouria Mousavizadeh Tehrani 				    csum_flags & ~(uint32_t)nh_ifp->if_hwassist,
2746e44d2e94SPouria Mousavizadeh Tehrani 				    m->m_pkthdr.csum_flags, csum_flags,
2747e44d2e94SPouria Mousavizadeh Tehrani 				    (uint32_t)nh_ifp->if_hwassist);
2748e44d2e94SPouria Mousavizadeh Tehrani 			}
2749e44d2e94SPouria Mousavizadeh Tehrani 			m_freem(m);
2750e44d2e94SPouria Mousavizadeh Tehrani 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2751e44d2e94SPouria Mousavizadeh Tehrani 			return (ENXIO);
2752e44d2e94SPouria Mousavizadeh Tehrani 		}
2753e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_flags = csum_flags;
2754e44d2e94SPouria Mousavizadeh Tehrani 		if (csum_flags &
2755e44d2e94SPouria Mousavizadeh Tehrani 		    (CSUM_INNER_IP | CSUM_INNER_IP_UDP | CSUM_INNER_IP6_UDP |
2756e44d2e94SPouria Mousavizadeh Tehrani 		    CSUM_INNER_IP_TCP | CSUM_INNER_IP6_TCP)) {
2757e44d2e94SPouria Mousavizadeh Tehrani 			counter_u64_add(sc->gnv_stats.txcsum, 1);
2758e44d2e94SPouria Mousavizadeh Tehrani 			if (csum_flags & CSUM_INNER_TSO)
2759e44d2e94SPouria Mousavizadeh Tehrani 				counter_u64_add(sc->gnv_stats.tso, 1);
2760e44d2e94SPouria Mousavizadeh Tehrani 		}
2761e44d2e94SPouria Mousavizadeh Tehrani 	} else if (ntohs(dstport) != V_zero_checksum_port) {
2762e44d2e94SPouria Mousavizadeh Tehrani 		struct udphdr *hdr = mtodo(m, sizeof(struct ip6_hdr));
2763e44d2e94SPouria Mousavizadeh Tehrani 
2764e44d2e94SPouria Mousavizadeh Tehrani 		hdr->uh_sum = in6_cksum_pseudo(ip6,
2765e44d2e94SPouria Mousavizadeh Tehrani 		    m->m_pkthdr.len - sizeof(struct ip6_hdr), IPPROTO_UDP, 0);
2766e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
2767e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
2768e44d2e94SPouria Mousavizadeh Tehrani 	}
2769e44d2e94SPouria Mousavizadeh Tehrani 	error = ip6_output(m, &opts, ro, 0, sc->gnv_im6o, NULL, NULL);
2770e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0) {
2771e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
2772e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OBYTES, plen);
2773e44d2e94SPouria Mousavizadeh Tehrani 		if (mcast)
2774e44d2e94SPouria Mousavizadeh Tehrani 			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
2775e44d2e94SPouria Mousavizadeh Tehrani 	} else
2776e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2777e44d2e94SPouria Mousavizadeh Tehrani 
2778e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2779e44d2e94SPouria Mousavizadeh Tehrani }
2780*f4e5b45bSJohn Baldwin #endif
2781e44d2e94SPouria Mousavizadeh Tehrani 
2782e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_transmit(struct ifnet * ifp,struct mbuf * m)2783e44d2e94SPouria Mousavizadeh Tehrani geneve_transmit(struct ifnet *ifp, struct mbuf *m)
2784e44d2e94SPouria Mousavizadeh Tehrani {
2785e44d2e94SPouria Mousavizadeh Tehrani 	struct rm_priotracker tracker;
2786e44d2e94SPouria Mousavizadeh Tehrani 	union sockaddr_union unsa;
2787e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
2788e44d2e94SPouria Mousavizadeh Tehrani 	struct gnv_ftable_entry *fe;
2789e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *mcifp;
2790e44d2e94SPouria Mousavizadeh Tehrani 	struct ether_header *eh;
2791e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t af;
2792e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2793e44d2e94SPouria Mousavizadeh Tehrani 
2794e44d2e94SPouria Mousavizadeh Tehrani 	mcifp = NULL;
2795e44d2e94SPouria Mousavizadeh Tehrani 	sc = ifp->if_softc;
2796e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_RLOCK(sc, &tracker);
2797e44d2e94SPouria Mousavizadeh Tehrani 	M_SETFIB(m, sc->gnv_fibnum);
2798e44d2e94SPouria Mousavizadeh Tehrani 
2799e44d2e94SPouria Mousavizadeh Tehrani 	if ((sc->gnv_flags & GENEVE_FLAG_RUNNING) == 0) {
2800e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_RUNLOCK(sc, &tracker);
2801e44d2e94SPouria Mousavizadeh Tehrani 		m_freem(m);
2802e44d2e94SPouria Mousavizadeh Tehrani 		return (ENETDOWN);
2803e44d2e94SPouria Mousavizadeh Tehrani 	}
2804e44d2e94SPouria Mousavizadeh Tehrani 	if (__predict_false(if_tunnel_check_nesting(ifp, m,
2805e44d2e94SPouria Mousavizadeh Tehrani 	    MTAG_GENEVE_LOOP, 1) != 0)) {
2806e44d2e94SPouria Mousavizadeh Tehrani 		GENEVE_RUNLOCK(sc, &tracker);
2807e44d2e94SPouria Mousavizadeh Tehrani 		m_freem(m);
2808e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2809e44d2e94SPouria Mousavizadeh Tehrani 		return (ELOOP);
2810e44d2e94SPouria Mousavizadeh Tehrani 	}
2811e44d2e94SPouria Mousavizadeh Tehrani 
2812e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER) {
2813e44d2e94SPouria Mousavizadeh Tehrani 		fe = NULL;
2814e44d2e94SPouria Mousavizadeh Tehrani 		eh = mtod(m, struct ether_header *);
2815e44d2e94SPouria Mousavizadeh Tehrani 
2816e44d2e94SPouria Mousavizadeh Tehrani 		ETHER_BPF_MTAP(ifp, m);
2817e44d2e94SPouria Mousavizadeh Tehrani 		if ((m->m_flags & (M_BCAST | M_MCAST)) == 0)
2818e44d2e94SPouria Mousavizadeh Tehrani 			fe = geneve_ftable_entry_lookup(sc, eh->ether_dhost);
2819e44d2e94SPouria Mousavizadeh Tehrani 		if (fe == NULL)
2820e44d2e94SPouria Mousavizadeh Tehrani 			fe = &sc->gnv_default_fe;
2821e44d2e94SPouria Mousavizadeh Tehrani 		geneve_sockaddr_copy(&unsa, &fe->gnvfe_raddr.sa);
2822e44d2e94SPouria Mousavizadeh Tehrani 	} else
2823e44d2e94SPouria Mousavizadeh Tehrani 		geneve_sockaddr_copy(&unsa, &sc->gnv_dst_addr.sa);
2824e44d2e94SPouria Mousavizadeh Tehrani 
2825e44d2e94SPouria Mousavizadeh Tehrani 	af = unsa.sa.sa_family;
2826e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_check_multicast_addr(&unsa) != 0)
2827e44d2e94SPouria Mousavizadeh Tehrani 		mcifp = geneve_multicast_if_ref(sc, af);
2828e44d2e94SPouria Mousavizadeh Tehrani 
2829e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_ACQUIRE(sc);
2830e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_RUNLOCK(sc, &tracker);
2831e44d2e94SPouria Mousavizadeh Tehrani 
2832*f4e5b45bSJohn Baldwin 	switch (af) {
2833*f4e5b45bSJohn Baldwin #ifdef INET
2834*f4e5b45bSJohn Baldwin 	case AF_INET:
2835e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_encap4(sc, &unsa, m);
2836*f4e5b45bSJohn Baldwin 		break;
2837*f4e5b45bSJohn Baldwin #endif
2838*f4e5b45bSJohn Baldwin #ifdef INET6
2839*f4e5b45bSJohn Baldwin 	case AF_INET6:
2840e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_encap6(sc, &unsa, m);
2841*f4e5b45bSJohn Baldwin 		break;
2842*f4e5b45bSJohn Baldwin #endif
2843*f4e5b45bSJohn Baldwin 	default:
2844e44d2e94SPouria Mousavizadeh Tehrani 		error = EAFNOSUPPORT;
2845*f4e5b45bSJohn Baldwin 	}
2846e44d2e94SPouria Mousavizadeh Tehrani 
2847e44d2e94SPouria Mousavizadeh Tehrani 	geneve_release(sc);
2848e44d2e94SPouria Mousavizadeh Tehrani 	if (mcifp != NULL)
2849e44d2e94SPouria Mousavizadeh Tehrani 		if_rele(mcifp);
2850e44d2e94SPouria Mousavizadeh Tehrani 
2851e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2852e44d2e94SPouria Mousavizadeh Tehrani }
2853e44d2e94SPouria Mousavizadeh Tehrani 
2854e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_output(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)2855e44d2e94SPouria Mousavizadeh Tehrani geneve_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
2856e44d2e94SPouria Mousavizadeh Tehrani     struct route *ro)
2857e44d2e94SPouria Mousavizadeh Tehrani {
2858e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t af;
2859e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2860e44d2e94SPouria Mousavizadeh Tehrani 
2861e44d2e94SPouria Mousavizadeh Tehrani #ifdef MAC
2862e44d2e94SPouria Mousavizadeh Tehrani 	error = mac_ifnet_check_transmit(ifp, m);
2863e44d2e94SPouria Mousavizadeh Tehrani 	if (error) {
2864e44d2e94SPouria Mousavizadeh Tehrani 		m_freem(m);
2865e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
2866e44d2e94SPouria Mousavizadeh Tehrani 	}
2867e44d2e94SPouria Mousavizadeh Tehrani #endif
2868e44d2e94SPouria Mousavizadeh Tehrani 
2869e44d2e94SPouria Mousavizadeh Tehrani 	/* BPF writes need to be handled specially. */
2870e44d2e94SPouria Mousavizadeh Tehrani 	if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT)
2871e44d2e94SPouria Mousavizadeh Tehrani 		memmove(&af, dst->sa_data, sizeof(af));
2872e44d2e94SPouria Mousavizadeh Tehrani 	else
2873e44d2e94SPouria Mousavizadeh Tehrani 		af = RO_GET_FAMILY(ro, dst);
2874e44d2e94SPouria Mousavizadeh Tehrani 
2875e44d2e94SPouria Mousavizadeh Tehrani 	BPF_MTAP2(ifp, &af, sizeof(af), m);
2876e44d2e94SPouria Mousavizadeh Tehrani 	error = (ifp->if_transmit)(ifp, m);
2877e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
2878e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOBUFS);
2879e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2880e44d2e94SPouria Mousavizadeh Tehrani }
2881e44d2e94SPouria Mousavizadeh Tehrani 
2882e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_next_option(struct geneve_socket * gnvso,struct genevehdr * gnvh,struct mbuf ** m0)2883e44d2e94SPouria Mousavizadeh Tehrani geneve_next_option(struct geneve_socket *gnvso, struct genevehdr *gnvh,
2884e44d2e94SPouria Mousavizadeh Tehrani 	struct mbuf **m0)
2885e44d2e94SPouria Mousavizadeh Tehrani {
2886e44d2e94SPouria Mousavizadeh Tehrani 	int optlen, error;
2887e44d2e94SPouria Mousavizadeh Tehrani 
2888e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
2889e44d2e94SPouria Mousavizadeh Tehrani 	/*
2890e44d2e94SPouria Mousavizadeh Tehrani 	 * We MUST NOT forward the packet if control (O) bit is set
2891e44d2e94SPouria Mousavizadeh Tehrani 	 * and currently there is not standard specification for it.
2892e44d2e94SPouria Mousavizadeh Tehrani 	 * Therefore, we drop it.
2893e44d2e94SPouria Mousavizadeh Tehrani 	 */
2894e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvh->geneve_control)
2895e44d2e94SPouria Mousavizadeh Tehrani 		return (EINVAL);
2896e44d2e94SPouria Mousavizadeh Tehrani 
2897e44d2e94SPouria Mousavizadeh Tehrani 	optlen = gnvh->geneve_optlen;
2898e44d2e94SPouria Mousavizadeh Tehrani 	if (optlen == 0)
2899e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
2900e44d2e94SPouria Mousavizadeh Tehrani 
2901e44d2e94SPouria Mousavizadeh Tehrani 	/*
2902e44d2e94SPouria Mousavizadeh Tehrani 	 * XXX: Geneve options processing
2903e44d2e94SPouria Mousavizadeh Tehrani 	 * We MUST drop the packet if there are options to process
2904e44d2e94SPouria Mousavizadeh Tehrani 	 * and we are not able to process it.
2905e44d2e94SPouria Mousavizadeh Tehrani 	 */
2906e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvh->geneve_critical)
2907e44d2e94SPouria Mousavizadeh Tehrani 		error = EINVAL;
2908e44d2e94SPouria Mousavizadeh Tehrani 
2909e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
2910e44d2e94SPouria Mousavizadeh Tehrani }
2911e44d2e94SPouria Mousavizadeh Tehrani 
2912e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_qflush(struct ifnet * ifp __unused)2913e44d2e94SPouria Mousavizadeh Tehrani geneve_qflush(struct ifnet *ifp __unused)
2914e44d2e94SPouria Mousavizadeh Tehrani {
2915e44d2e94SPouria Mousavizadeh Tehrani }
2916e44d2e94SPouria Mousavizadeh Tehrani 
2917e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_input_csum(struct mbuf * m,struct ifnet * ifp,counter_u64_t rxcsum)2918e44d2e94SPouria Mousavizadeh Tehrani geneve_input_csum(struct mbuf *m, struct ifnet *ifp, counter_u64_t rxcsum)
2919e44d2e94SPouria Mousavizadeh Tehrani {
2920e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t csum_flags;
2921e44d2e94SPouria Mousavizadeh Tehrani 
2922e44d2e94SPouria Mousavizadeh Tehrani 	if ((((ifp->if_capenable & IFCAP_RXCSUM) != 0 &&
2923e44d2e94SPouria Mousavizadeh Tehrani 	    (m->m_pkthdr.csum_flags & CSUM_INNER_L3_CALC) != 0) ||
2924e44d2e94SPouria Mousavizadeh Tehrani 	    ((ifp->if_capenable & IFCAP_RXCSUM_IPV6) != 0 &&
2925e44d2e94SPouria Mousavizadeh Tehrani 	    (m->m_pkthdr.csum_flags & CSUM_INNER_L3_CALC) == 0))) {
2926e44d2e94SPouria Mousavizadeh Tehrani 		csum_flags = 0;
2927e44d2e94SPouria Mousavizadeh Tehrani 
2928e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.csum_flags & CSUM_INNER_L3_CALC)
2929e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_L3_CALC;
2930e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.csum_flags & CSUM_INNER_L3_VALID)
2931e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_L3_VALID;
2932e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.csum_flags & CSUM_INNER_L4_CALC)
2933e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_L4_CALC;
2934e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.csum_flags & CSUM_INNER_L4_VALID)
2935e44d2e94SPouria Mousavizadeh Tehrani 			csum_flags |= CSUM_L4_VALID;
2936e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_flags = csum_flags;
2937e44d2e94SPouria Mousavizadeh Tehrani 		counter_u64_add(rxcsum, 1);
2938e44d2e94SPouria Mousavizadeh Tehrani 	} else {
2939e44d2e94SPouria Mousavizadeh Tehrani 		/* clear everything */
2940e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_flags = 0;
2941e44d2e94SPouria Mousavizadeh Tehrani 		m->m_pkthdr.csum_data = 0;
2942e44d2e94SPouria Mousavizadeh Tehrani 	}
2943e44d2e94SPouria Mousavizadeh Tehrani }
2944e44d2e94SPouria Mousavizadeh Tehrani 
2945e44d2e94SPouria Mousavizadeh Tehrani static uint32_t
geneve_map_etype_to_af(uint32_t ethertype)2946e44d2e94SPouria Mousavizadeh Tehrani geneve_map_etype_to_af(uint32_t ethertype)
2947e44d2e94SPouria Mousavizadeh Tehrani {
2948e44d2e94SPouria Mousavizadeh Tehrani 
2949e44d2e94SPouria Mousavizadeh Tehrani 	if (ethertype == ETHERTYPE_IP)
2950e44d2e94SPouria Mousavizadeh Tehrani 		return (AF_INET);
2951e44d2e94SPouria Mousavizadeh Tehrani 	if (ethertype == ETHERTYPE_IPV6)
2952e44d2e94SPouria Mousavizadeh Tehrani 		return (AF_INET6);
2953e44d2e94SPouria Mousavizadeh Tehrani 	if (ethertype == ETHERTYPE_ARP)
2954e44d2e94SPouria Mousavizadeh Tehrani 		return (AF_LINK);
2955e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
2956e44d2e94SPouria Mousavizadeh Tehrani }
2957e44d2e94SPouria Mousavizadeh Tehrani 
2958e44d2e94SPouria Mousavizadeh Tehrani static bool
geneve_udp_input(struct mbuf * m,int offset,struct inpcb * inpcb,const struct sockaddr * srcsa,void * xgnvso)2959e44d2e94SPouria Mousavizadeh Tehrani geneve_udp_input(struct mbuf *m, int offset, struct inpcb *inpcb,
2960e44d2e94SPouria Mousavizadeh Tehrani     const struct sockaddr *srcsa, void *xgnvso)
2961e44d2e94SPouria Mousavizadeh Tehrani {
2962e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_socket *gnvso;
2963e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_pkt_info info;
2964e44d2e94SPouria Mousavizadeh Tehrani 	struct genevehdr *gnvh, gnvhdr;
2965e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
2966e44d2e94SPouria Mousavizadeh Tehrani 	struct ip *iphdr;
2967e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_hdr *ip6hdr;
2968e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
2969e44d2e94SPouria Mousavizadeh Tehrani 	int32_t plen, af;
2970e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t vni;
2971e44d2e94SPouria Mousavizadeh Tehrani 	uint16_t optlen, proto;
2972e44d2e94SPouria Mousavizadeh Tehrani 	int error;
2973e44d2e94SPouria Mousavizadeh Tehrani 
2974e44d2e94SPouria Mousavizadeh Tehrani 	M_ASSERTPKTHDR(m);
2975e44d2e94SPouria Mousavizadeh Tehrani 	plen = m->m_pkthdr.len;
2976e44d2e94SPouria Mousavizadeh Tehrani 	gnvso = xgnvso;
2977e44d2e94SPouria Mousavizadeh Tehrani 
2978e44d2e94SPouria Mousavizadeh Tehrani 	if (m->m_pkthdr.len < offset + sizeof(struct geneveudphdr))
2979e44d2e94SPouria Mousavizadeh Tehrani 		return (false);
2980e44d2e94SPouria Mousavizadeh Tehrani 
2981e44d2e94SPouria Mousavizadeh Tehrani 	/* Get ECN and TTL values for future processing */
2982e44d2e94SPouria Mousavizadeh Tehrani 	memset(&info, 0, sizeof(info));
2983e44d2e94SPouria Mousavizadeh Tehrani 	info.ethertype = geneve_get_ethertype(m);
2984e44d2e94SPouria Mousavizadeh Tehrani 	if (info.ethertype == ETHERTYPE_IP) {
2985e44d2e94SPouria Mousavizadeh Tehrani 		iphdr = mtodo(m, offset - sizeof(struct ip));
2986e44d2e94SPouria Mousavizadeh Tehrani 		info.ecn = (iphdr->ip_tos & IPTOS_ECN_MASK);
2987e44d2e94SPouria Mousavizadeh Tehrani 		info.ttl = iphdr->ip_ttl;
2988e44d2e94SPouria Mousavizadeh Tehrani 	} else if (info.ethertype == ETHERTYPE_IPV6) {
2989e44d2e94SPouria Mousavizadeh Tehrani 		ip6hdr = mtodo(m, offset - sizeof(struct ip6_hdr));
2990e44d2e94SPouria Mousavizadeh Tehrani 		info.ecn = IPV6_ECN(ip6hdr);
2991e44d2e94SPouria Mousavizadeh Tehrani 		info.ttl = ip6hdr->ip6_hlim;
2992e44d2e94SPouria Mousavizadeh Tehrani 	}
2993e44d2e94SPouria Mousavizadeh Tehrani 
2994e44d2e94SPouria Mousavizadeh Tehrani 	/* Get geneve header */
2995e44d2e94SPouria Mousavizadeh Tehrani 	offset += sizeof(struct udphdr);
2996e44d2e94SPouria Mousavizadeh Tehrani 	if (__predict_false(m->m_len < offset + sizeof(struct genevehdr))) {
2997e44d2e94SPouria Mousavizadeh Tehrani 		m_copydata(m, offset, sizeof(struct genevehdr), (caddr_t)&gnvhdr);
2998e44d2e94SPouria Mousavizadeh Tehrani 		gnvh = &gnvhdr;
2999e44d2e94SPouria Mousavizadeh Tehrani 	} else
3000e44d2e94SPouria Mousavizadeh Tehrani 		gnvh = mtodo(m, offset);
3001e44d2e94SPouria Mousavizadeh Tehrani 
3002e44d2e94SPouria Mousavizadeh Tehrani 	/*
3003e44d2e94SPouria Mousavizadeh Tehrani 	 * Drop if there is a reserved bit or unknown version set in the header.
3004e44d2e94SPouria Mousavizadeh Tehrani 	 * As defined in RFC 8926 3.4
3005e44d2e94SPouria Mousavizadeh Tehrani 	 */
3006e44d2e94SPouria Mousavizadeh Tehrani 	if (gnvh->geneve_ver != htons(GENEVE_VERSION) ||
3007e44d2e94SPouria Mousavizadeh Tehrani 	    gnvh->geneve_vni & ~GENEVE_VNI_MASK)
3008e44d2e94SPouria Mousavizadeh Tehrani 		return (false);
3009e44d2e94SPouria Mousavizadeh Tehrani 
3010e44d2e94SPouria Mousavizadeh Tehrani 	/*
3011e44d2e94SPouria Mousavizadeh Tehrani 	 * The length of the option fields, expressed in 4-byte multiples, not
3012e44d2e94SPouria Mousavizadeh Tehrani 	 * including the 8-byte fixed tunnel header.
3013e44d2e94SPouria Mousavizadeh Tehrani 	 */
3014e44d2e94SPouria Mousavizadeh Tehrani 	optlen = ntohs(gnvh->geneve_optlen) * 4;
3015e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_next_option(gnvso, gnvh, &m);
3016e44d2e94SPouria Mousavizadeh Tehrani 	if (error != 0)
3017e44d2e94SPouria Mousavizadeh Tehrani 		return (false);
3018e44d2e94SPouria Mousavizadeh Tehrani 
3019e44d2e94SPouria Mousavizadeh Tehrani 	vni = ntohl(gnvh->geneve_vni) >> GENEVE_HDR_VNI_SHIFT;
3020e44d2e94SPouria Mousavizadeh Tehrani 	sc = geneve_socket_lookup_softc(gnvso, vni);
3021e44d2e94SPouria Mousavizadeh Tehrani 	if (sc == NULL)
3022e44d2e94SPouria Mousavizadeh Tehrani 		return (false);
3023e44d2e94SPouria Mousavizadeh Tehrani 
3024e44d2e94SPouria Mousavizadeh Tehrani 	if ((sc->gnv_flags & GENEVE_FLAG_RUNNING) == 0)
3025e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
3026e44d2e94SPouria Mousavizadeh Tehrani 
3027e44d2e94SPouria Mousavizadeh Tehrani 	proto = ntohs(gnvh->geneve_proto);
3028e44d2e94SPouria Mousavizadeh Tehrani 	m_adj(m, offset + sizeof(struct genevehdr) + optlen);
3029e44d2e94SPouria Mousavizadeh Tehrani 
3030e44d2e94SPouria Mousavizadeh Tehrani 	/* if next protocol is ethernet, check its ethertype and learn it */
3031e44d2e94SPouria Mousavizadeh Tehrani 	if (proto == GENEVE_PROTO_ETHER) {
3032e44d2e94SPouria Mousavizadeh Tehrani 		offset = ETHER_HDR_LEN;
3033e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_input_ether(sc, &m, srcsa, &info);
3034e44d2e94SPouria Mousavizadeh Tehrani 		if (error != 0)
3035e44d2e94SPouria Mousavizadeh Tehrani 			goto out;
3036e44d2e94SPouria Mousavizadeh Tehrani 	} else {
3037e44d2e94SPouria Mousavizadeh Tehrani 		info.ethertype = proto;
3038e44d2e94SPouria Mousavizadeh Tehrani 		af = geneve_map_etype_to_af(info.ethertype);
3039e44d2e94SPouria Mousavizadeh Tehrani 		offset = 0;
3040e44d2e94SPouria Mousavizadeh Tehrani 	}
3041e44d2e94SPouria Mousavizadeh Tehrani 
3042e44d2e94SPouria Mousavizadeh Tehrani 	error = geneve_input_inherit(sc, &m, offset, &info);
3043e44d2e94SPouria Mousavizadeh Tehrani 	if (error != 0)
3044e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
3045e44d2e94SPouria Mousavizadeh Tehrani 
3046e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
3047e44d2e94SPouria Mousavizadeh Tehrani 	if (ifp == m->m_pkthdr.rcvif)
3048e44d2e94SPouria Mousavizadeh Tehrani 		/* XXX Does not catch more complex loops. */
3049e44d2e94SPouria Mousavizadeh Tehrani 		goto out;
3050e44d2e94SPouria Mousavizadeh Tehrani 
3051e44d2e94SPouria Mousavizadeh Tehrani 	m_clrprotoflags(m);
3052e44d2e94SPouria Mousavizadeh Tehrani 	m->m_pkthdr.rcvif = ifp;
3053e44d2e94SPouria Mousavizadeh Tehrani 	M_SETFIB(m, ifp->if_fib);
3054e44d2e94SPouria Mousavizadeh Tehrani 	geneve_input_csum(m, ifp, sc->gnv_stats.rxcsum);
3055e44d2e94SPouria Mousavizadeh Tehrani 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3056e44d2e94SPouria Mousavizadeh Tehrani 	if_inc_counter(ifp, IFCOUNTER_IBYTES, plen);
3057e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_mc_ifp != NULL)
3058e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
3059e44d2e94SPouria Mousavizadeh Tehrani 
3060e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(m != NULL);
3061e44d2e94SPouria Mousavizadeh Tehrani 
3062e44d2e94SPouria Mousavizadeh Tehrani 	if (proto == GENEVE_PROTO_ETHER)
3063e44d2e94SPouria Mousavizadeh Tehrani 		(*ifp->if_input)(ifp, m);
3064e44d2e94SPouria Mousavizadeh Tehrani 	else {
3065e44d2e94SPouria Mousavizadeh Tehrani 		BPF_MTAP2(ifp, &af, sizeof(af), m);
3066e44d2e94SPouria Mousavizadeh Tehrani 		netisr_dispatch_src(info.isr, (uintptr_t)xgnvso, m);
3067e44d2e94SPouria Mousavizadeh Tehrani 	}
3068e44d2e94SPouria Mousavizadeh Tehrani 
3069e44d2e94SPouria Mousavizadeh Tehrani 	m = NULL;
3070e44d2e94SPouria Mousavizadeh Tehrani out:
3071e44d2e94SPouria Mousavizadeh Tehrani 	geneve_release(sc);
3072e44d2e94SPouria Mousavizadeh Tehrani 	if (m != NULL) {
3073e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
3074e44d2e94SPouria Mousavizadeh Tehrani 		m_freem(m);
3075e44d2e94SPouria Mousavizadeh Tehrani 	}
3076e44d2e94SPouria Mousavizadeh Tehrani 
3077e44d2e94SPouria Mousavizadeh Tehrani 	return (true);
3078e44d2e94SPouria Mousavizadeh Tehrani }
3079e44d2e94SPouria Mousavizadeh Tehrani 
3080e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_input_ether(struct geneve_softc * sc,struct mbuf ** m0,const struct sockaddr * sa,struct geneve_pkt_info * info)3081e44d2e94SPouria Mousavizadeh Tehrani geneve_input_ether(struct geneve_softc *sc, struct mbuf **m0,
3082e44d2e94SPouria Mousavizadeh Tehrani     const struct sockaddr *sa, struct geneve_pkt_info *info)
3083e44d2e94SPouria Mousavizadeh Tehrani {
3084e44d2e94SPouria Mousavizadeh Tehrani 	struct mbuf *m;
3085e44d2e94SPouria Mousavizadeh Tehrani 	struct ether_header *eh;
3086e44d2e94SPouria Mousavizadeh Tehrani 
3087e44d2e94SPouria Mousavizadeh Tehrani 	m = *m0;
3088e44d2e94SPouria Mousavizadeh Tehrani 
3089e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto != GENEVE_PROTO_ETHER)
3090e44d2e94SPouria Mousavizadeh Tehrani 		return (EPROTOTYPE);
3091e44d2e94SPouria Mousavizadeh Tehrani 
3092e44d2e94SPouria Mousavizadeh Tehrani 	if (m->m_pkthdr.len < ETHER_HDR_LEN)
3093e44d2e94SPouria Mousavizadeh Tehrani 		return (EINVAL);
3094e44d2e94SPouria Mousavizadeh Tehrani 
3095e44d2e94SPouria Mousavizadeh Tehrani 	if (m->m_len < ETHER_HDR_LEN &&
3096e44d2e94SPouria Mousavizadeh Tehrani 	    (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
3097e44d2e94SPouria Mousavizadeh Tehrani 		*m0 = NULL;
3098e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOBUFS);
3099e44d2e94SPouria Mousavizadeh Tehrani 	}
3100e44d2e94SPouria Mousavizadeh Tehrani 
3101e44d2e94SPouria Mousavizadeh Tehrani 	eh = mtod(m, struct ether_header *);
3102e44d2e94SPouria Mousavizadeh Tehrani 	info->ethertype = ntohs(eh->ether_type);
3103e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_LEARN)
3104e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_learn(sc, sa, eh->ether_shost);
3105e44d2e94SPouria Mousavizadeh Tehrani 
3106e44d2e94SPouria Mousavizadeh Tehrani 	*m0 = m;
3107e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3108e44d2e94SPouria Mousavizadeh Tehrani }
3109e44d2e94SPouria Mousavizadeh Tehrani 
3110e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_input_inherit(struct geneve_softc * sc,struct mbuf ** m0,int offset,struct geneve_pkt_info * info)3111e44d2e94SPouria Mousavizadeh Tehrani geneve_input_inherit(struct geneve_softc *sc, struct mbuf **m0,
3112e44d2e94SPouria Mousavizadeh Tehrani     int offset, struct geneve_pkt_info *info)
3113e44d2e94SPouria Mousavizadeh Tehrani {
3114e44d2e94SPouria Mousavizadeh Tehrani 	struct mbuf *m;
3115e44d2e94SPouria Mousavizadeh Tehrani 	struct ip *iphdr;
3116e44d2e94SPouria Mousavizadeh Tehrani 	struct ip6_hdr *ip6hdr;
3117e44d2e94SPouria Mousavizadeh Tehrani 	uint8_t itos;
3118e44d2e94SPouria Mousavizadeh Tehrani 
3119e44d2e94SPouria Mousavizadeh Tehrani 	m = *m0;
3120e44d2e94SPouria Mousavizadeh Tehrani 
3121e44d2e94SPouria Mousavizadeh Tehrani 	switch (info->ethertype) {
3122e44d2e94SPouria Mousavizadeh Tehrani 	case ETHERTYPE_IP:
3123e44d2e94SPouria Mousavizadeh Tehrani 		offset += sizeof(struct ip);
3124e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.len < offset)
3125e44d2e94SPouria Mousavizadeh Tehrani 			return (EINVAL);
3126e44d2e94SPouria Mousavizadeh Tehrani 
3127e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_len < offset &&
3128e44d2e94SPouria Mousavizadeh Tehrani 		    (m = m_pullup(m, offset)) == NULL) {
3129e44d2e94SPouria Mousavizadeh Tehrani 			*m0 = NULL;
3130e44d2e94SPouria Mousavizadeh Tehrani 			return (ENOBUFS);
3131e44d2e94SPouria Mousavizadeh Tehrani 		}
3132e44d2e94SPouria Mousavizadeh Tehrani 		iphdr = mtodo(m, offset - sizeof(struct ip));
3133e44d2e94SPouria Mousavizadeh Tehrani 
3134e44d2e94SPouria Mousavizadeh Tehrani 		if (ip_ecn_egress(ECN_COMPLETE, &info->ecn, &iphdr->ip_tos) == 0) {
3135e44d2e94SPouria Mousavizadeh Tehrani 			*m0 = NULL;
3136e44d2e94SPouria Mousavizadeh Tehrani 			return (ENOBUFS);
3137e44d2e94SPouria Mousavizadeh Tehrani 		}
3138e44d2e94SPouria Mousavizadeh Tehrani 
3139e44d2e94SPouria Mousavizadeh Tehrani 		if ((sc->gnv_flags & GENEVE_FLAG_TTL_INHERIT) != 0 && info->ttl > 0)
3140e44d2e94SPouria Mousavizadeh Tehrani 			iphdr->ip_ttl = info->ttl;
3141e44d2e94SPouria Mousavizadeh Tehrani 
3142e44d2e94SPouria Mousavizadeh Tehrani 		info->isr = NETISR_IP;
3143e44d2e94SPouria Mousavizadeh Tehrani 		break;
3144e44d2e94SPouria Mousavizadeh Tehrani 
3145e44d2e94SPouria Mousavizadeh Tehrani 	case ETHERTYPE_IPV6:
3146e44d2e94SPouria Mousavizadeh Tehrani 		offset += sizeof(struct ip6_hdr);
3147e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.len < offset)
3148e44d2e94SPouria Mousavizadeh Tehrani 			return (EINVAL);
3149e44d2e94SPouria Mousavizadeh Tehrani 
3150e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_len < offset &&
3151e44d2e94SPouria Mousavizadeh Tehrani 		    (m = m_pullup(m, offset)) == NULL) {
3152e44d2e94SPouria Mousavizadeh Tehrani 			*m0 = NULL;
3153e44d2e94SPouria Mousavizadeh Tehrani 			return (ENOBUFS);
3154e44d2e94SPouria Mousavizadeh Tehrani 		}
3155e44d2e94SPouria Mousavizadeh Tehrani 		ip6hdr = mtodo(m, offset - sizeof(struct ip6_hdr));
3156e44d2e94SPouria Mousavizadeh Tehrani 
3157e44d2e94SPouria Mousavizadeh Tehrani 		itos = (ntohl(ip6hdr->ip6_flow) >> IPV6_FLOWLABEL_LEN) & 0xff;
3158e44d2e94SPouria Mousavizadeh Tehrani 		if (ip_ecn_egress(ECN_COMPLETE, &info->ecn, &itos) == 0) {
3159e44d2e94SPouria Mousavizadeh Tehrani 			*m0 = NULL;
3160e44d2e94SPouria Mousavizadeh Tehrani 			return (ENOBUFS);
3161e44d2e94SPouria Mousavizadeh Tehrani 		}
3162e44d2e94SPouria Mousavizadeh Tehrani 		ip6hdr->ip6_flow |= htonl((uint32_t)itos << IPV6_FLOWLABEL_LEN);
3163e44d2e94SPouria Mousavizadeh Tehrani 
3164e44d2e94SPouria Mousavizadeh Tehrani 		if ((sc->gnv_flags & GENEVE_FLAG_TTL_INHERIT) && (info->ttl > 0))
3165e44d2e94SPouria Mousavizadeh Tehrani 			ip6hdr->ip6_hlim = info->ttl;
3166e44d2e94SPouria Mousavizadeh Tehrani 
3167e44d2e94SPouria Mousavizadeh Tehrani 		info->isr = NETISR_IPV6;
3168e44d2e94SPouria Mousavizadeh Tehrani 		break;
3169e44d2e94SPouria Mousavizadeh Tehrani 
3170e44d2e94SPouria Mousavizadeh Tehrani 	case ETHERTYPE_ARP:
3171e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_proto == GENEVE_PROTO_INHERIT)
3172e44d2e94SPouria Mousavizadeh Tehrani 			return (EINVAL);
3173e44d2e94SPouria Mousavizadeh Tehrani 
3174e44d2e94SPouria Mousavizadeh Tehrani 		offset += sizeof(struct arphdr);
3175e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_pkthdr.len < offset)
3176e44d2e94SPouria Mousavizadeh Tehrani 			return (EINVAL);
3177e44d2e94SPouria Mousavizadeh Tehrani 
3178e44d2e94SPouria Mousavizadeh Tehrani 		if (m->m_len < offset &&
3179e44d2e94SPouria Mousavizadeh Tehrani 		    (m = m_pullup(m, offset)) == NULL) {
3180e44d2e94SPouria Mousavizadeh Tehrani 			*m0 = NULL;
3181e44d2e94SPouria Mousavizadeh Tehrani 			return (ENOBUFS);
3182e44d2e94SPouria Mousavizadeh Tehrani 		}
3183e44d2e94SPouria Mousavizadeh Tehrani 		info->isr = NETISR_ARP;
3184e44d2e94SPouria Mousavizadeh Tehrani 		break;
3185e44d2e94SPouria Mousavizadeh Tehrani 
3186e44d2e94SPouria Mousavizadeh Tehrani 	default:
3187e44d2e94SPouria Mousavizadeh Tehrani 		if_inc_counter(sc->gnv_ifp, IFCOUNTER_NOPROTO, 1);
3188e44d2e94SPouria Mousavizadeh Tehrani 		return (EINVAL);
3189e44d2e94SPouria Mousavizadeh Tehrani 	}
3190e44d2e94SPouria Mousavizadeh Tehrani 
3191e44d2e94SPouria Mousavizadeh Tehrani 	*m0 = m;
3192e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3193e44d2e94SPouria Mousavizadeh Tehrani }
3194e44d2e94SPouria Mousavizadeh Tehrani 
3195e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_stats_alloc(struct geneve_softc * sc)3196e44d2e94SPouria Mousavizadeh Tehrani geneve_stats_alloc(struct geneve_softc *sc)
3197e44d2e94SPouria Mousavizadeh Tehrani {
3198e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_statistics *stats = &sc->gnv_stats;
3199e44d2e94SPouria Mousavizadeh Tehrani 
3200e44d2e94SPouria Mousavizadeh Tehrani 	stats->txcsum = counter_u64_alloc(M_WAITOK);
3201e44d2e94SPouria Mousavizadeh Tehrani 	stats->tso = counter_u64_alloc(M_WAITOK);
3202e44d2e94SPouria Mousavizadeh Tehrani 	stats->rxcsum = counter_u64_alloc(M_WAITOK);
3203e44d2e94SPouria Mousavizadeh Tehrani }
3204e44d2e94SPouria Mousavizadeh Tehrani 
3205e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_stats_free(struct geneve_softc * sc)3206e44d2e94SPouria Mousavizadeh Tehrani geneve_stats_free(struct geneve_softc *sc)
3207e44d2e94SPouria Mousavizadeh Tehrani {
3208e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_statistics *stats = &sc->gnv_stats;
3209e44d2e94SPouria Mousavizadeh Tehrani 
3210e44d2e94SPouria Mousavizadeh Tehrani 	counter_u64_free(stats->txcsum);
3211e44d2e94SPouria Mousavizadeh Tehrani 	counter_u64_free(stats->tso);
3212e44d2e94SPouria Mousavizadeh Tehrani 	counter_u64_free(stats->rxcsum);
3213e44d2e94SPouria Mousavizadeh Tehrani }
3214e44d2e94SPouria Mousavizadeh Tehrani 
3215e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_set_default_config(struct geneve_softc * sc)3216e44d2e94SPouria Mousavizadeh Tehrani geneve_set_default_config(struct geneve_softc *sc)
3217e44d2e94SPouria Mousavizadeh Tehrani {
3218e44d2e94SPouria Mousavizadeh Tehrani 
3219e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_flags |= GENEVE_FLAG_LEARN;
3220e44d2e94SPouria Mousavizadeh Tehrani 
3221e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_vni = GENEVE_VNI_MAX;
3222e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ttl = V_ip_defttl;
3223e44d2e94SPouria Mousavizadeh Tehrani 
3224e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_src_addr.sin.sin_port = htons(GENEVE_UDPPORT);
3225e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_dst_addr.sin.sin_port = htons(GENEVE_UDPPORT);
3226e44d2e94SPouria Mousavizadeh Tehrani 
3227e44d2e94SPouria Mousavizadeh Tehrani 	/*
3228e44d2e94SPouria Mousavizadeh Tehrani 	 * RFC 8926 Section 3.3, the entire 16-bit range MAY
3229e44d2e94SPouria Mousavizadeh Tehrani 	 * be used to maximize entropy.
3230e44d2e94SPouria Mousavizadeh Tehrani 	 */
3231e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_min_port = V_ipport_firstauto;
3232e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_max_port = V_ipport_lastauto;
3233e44d2e94SPouria Mousavizadeh Tehrani 
3234e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_proto = GENEVE_PROTO_ETHER;
3235e44d2e94SPouria Mousavizadeh Tehrani 
3236e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable_max = GENEVE_FTABLE_MAX;
3237e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ftable_timeout = GENEVE_FTABLE_TIMEOUT;
3238e44d2e94SPouria Mousavizadeh Tehrani }
3239e44d2e94SPouria Mousavizadeh Tehrani 
3240e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_set_reqcap(struct geneve_softc * sc,struct ifnet * ifp,int reqcap,int reqcap2)3241e44d2e94SPouria Mousavizadeh Tehrani geneve_set_reqcap(struct geneve_softc *sc, struct ifnet *ifp, int reqcap,
3242e44d2e94SPouria Mousavizadeh Tehrani     int reqcap2)
3243e44d2e94SPouria Mousavizadeh Tehrani {
3244e44d2e94SPouria Mousavizadeh Tehrani 	int mask = reqcap ^ ifp->if_capenable;
3245e44d2e94SPouria Mousavizadeh Tehrani 
3246e44d2e94SPouria Mousavizadeh Tehrani 	/* Disable TSO if tx checksums are disabled. */
3247e44d2e94SPouria Mousavizadeh Tehrani 	if (mask & IFCAP_TXCSUM && !(reqcap & IFCAP_TXCSUM) &&
3248e44d2e94SPouria Mousavizadeh Tehrani 	    reqcap & IFCAP_TSO4) {
3249e44d2e94SPouria Mousavizadeh Tehrani 		reqcap &= ~IFCAP_TSO4;
3250e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "tso4 disabled due to -txcsum.\n");
3251e44d2e94SPouria Mousavizadeh Tehrani 	}
3252e44d2e94SPouria Mousavizadeh Tehrani 	if (mask & IFCAP_TXCSUM_IPV6 && !(reqcap & IFCAP_TXCSUM_IPV6) &&
3253e44d2e94SPouria Mousavizadeh Tehrani 	    reqcap & IFCAP_TSO6) {
3254e44d2e94SPouria Mousavizadeh Tehrani 		reqcap &= ~IFCAP_TSO6;
3255e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "tso6 disabled due to -txcsum6.\n");
3256e44d2e94SPouria Mousavizadeh Tehrani 	}
3257e44d2e94SPouria Mousavizadeh Tehrani 
3258e44d2e94SPouria Mousavizadeh Tehrani 	/* Do not enable TSO if tx checksums are disabled. */
3259e44d2e94SPouria Mousavizadeh Tehrani 	if (mask & IFCAP_TSO4 && reqcap & IFCAP_TSO4 &&
3260e44d2e94SPouria Mousavizadeh Tehrani 	    !(reqcap & IFCAP_TXCSUM)) {
3261e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "enable txcsum first.\n");
3262e44d2e94SPouria Mousavizadeh Tehrani 		return (EAGAIN);
3263e44d2e94SPouria Mousavizadeh Tehrani 	}
3264e44d2e94SPouria Mousavizadeh Tehrani 	if (mask & IFCAP_TSO6 && reqcap & IFCAP_TSO6 &&
3265e44d2e94SPouria Mousavizadeh Tehrani 	    !(reqcap & IFCAP_TXCSUM_IPV6)) {
3266e44d2e94SPouria Mousavizadeh Tehrani 		if_printf(ifp, "enable txcsum6 first.\n");
3267e44d2e94SPouria Mousavizadeh Tehrani 		return (EAGAIN);
3268e44d2e94SPouria Mousavizadeh Tehrani 	}
3269e44d2e94SPouria Mousavizadeh Tehrani 
3270e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_reqcap = reqcap;
3271e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_reqcap2 = reqcap2;
3272e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3273e44d2e94SPouria Mousavizadeh Tehrani }
3274e44d2e94SPouria Mousavizadeh Tehrani 
3275e44d2e94SPouria Mousavizadeh Tehrani /*
3276e44d2e94SPouria Mousavizadeh Tehrani  * A GENEVE interface inherits the capabilities of the genevedev or the interface
3277e44d2e94SPouria Mousavizadeh Tehrani  * hosting the genevelocal address.
3278e44d2e94SPouria Mousavizadeh Tehrani  */
3279e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_set_hwcaps(struct geneve_softc * sc)3280e44d2e94SPouria Mousavizadeh Tehrani geneve_set_hwcaps(struct geneve_softc *sc)
3281e44d2e94SPouria Mousavizadeh Tehrani {
3282e44d2e94SPouria Mousavizadeh Tehrani 	struct epoch_tracker et;
3283e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *p, *ifp;
3284e44d2e94SPouria Mousavizadeh Tehrani 	struct ifaddr *ifa;
3285e44d2e94SPouria Mousavizadeh Tehrani 	u_long hwa;
3286e44d2e94SPouria Mousavizadeh Tehrani 	int cap, ena;
3287e44d2e94SPouria Mousavizadeh Tehrani 	bool rel;
3288e44d2e94SPouria Mousavizadeh Tehrani 
3289e44d2e94SPouria Mousavizadeh Tehrani 	/* reset caps */
3290e44d2e94SPouria Mousavizadeh Tehrani 	ifp = sc->gnv_ifp;
3291e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_capabilities &= GENEVE_BASIC_IFCAPS;
3292e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_capenable &= GENEVE_BASIC_IFCAPS;
3293e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_hwassist = 0;
3294e44d2e94SPouria Mousavizadeh Tehrani 
3295e44d2e94SPouria Mousavizadeh Tehrani 	NET_EPOCH_ENTER(et);
3296e44d2e94SPouria Mousavizadeh Tehrani 	CURVNET_SET(ifp->if_vnet);
3297e44d2e94SPouria Mousavizadeh Tehrani 
3298e44d2e94SPouria Mousavizadeh Tehrani 	p = NULL;
3299e44d2e94SPouria Mousavizadeh Tehrani 	rel = false;
3300e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_mc_ifname[0] != '\0') {
3301e44d2e94SPouria Mousavizadeh Tehrani 		rel = true;
3302e44d2e94SPouria Mousavizadeh Tehrani 		p = ifunit_ref(sc->gnv_mc_ifname);
3303e44d2e94SPouria Mousavizadeh Tehrani 	} else if (geneve_sockaddr_in_any(&sc->gnv_src_addr) == 0) {
3304e44d2e94SPouria Mousavizadeh Tehrani 		if (sc->gnv_src_addr.sa.sa_family == AF_INET) {
3305e44d2e94SPouria Mousavizadeh Tehrani 			struct sockaddr_in in4 = sc->gnv_src_addr.sin;
3306e44d2e94SPouria Mousavizadeh Tehrani 
3307e44d2e94SPouria Mousavizadeh Tehrani 			in4.sin_port = 0;
3308e44d2e94SPouria Mousavizadeh Tehrani 			ifa = ifa_ifwithaddr((struct sockaddr *)&in4);
3309e44d2e94SPouria Mousavizadeh Tehrani 			if (ifa != NULL)
3310e44d2e94SPouria Mousavizadeh Tehrani 				p = ifa->ifa_ifp;
3311e44d2e94SPouria Mousavizadeh Tehrani 		} else if (sc->gnv_src_addr.sa.sa_family == AF_INET6) {
3312e44d2e94SPouria Mousavizadeh Tehrani 			struct sockaddr_in6 in6 = sc->gnv_src_addr.sin6;
3313e44d2e94SPouria Mousavizadeh Tehrani 
3314e44d2e94SPouria Mousavizadeh Tehrani 			in6.sin6_port = 0;
3315e44d2e94SPouria Mousavizadeh Tehrani 			ifa = ifa_ifwithaddr((struct sockaddr *)&in6);
3316e44d2e94SPouria Mousavizadeh Tehrani 			if (ifa != NULL)
3317e44d2e94SPouria Mousavizadeh Tehrani 				p = ifa->ifa_ifp;
3318e44d2e94SPouria Mousavizadeh Tehrani 		}
3319e44d2e94SPouria Mousavizadeh Tehrani 	}
3320e44d2e94SPouria Mousavizadeh Tehrani 	if (p == NULL) {
3321e44d2e94SPouria Mousavizadeh Tehrani 		CURVNET_RESTORE();
3322e44d2e94SPouria Mousavizadeh Tehrani 		NET_EPOCH_EXIT(et);
3323e44d2e94SPouria Mousavizadeh Tehrani 		return;
3324e44d2e94SPouria Mousavizadeh Tehrani 	}
3325e44d2e94SPouria Mousavizadeh Tehrani 
3326e44d2e94SPouria Mousavizadeh Tehrani 	cap = ena = hwa = 0;
3327e44d2e94SPouria Mousavizadeh Tehrani 
3328e44d2e94SPouria Mousavizadeh Tehrani 	/* checksum offload */
3329e44d2e94SPouria Mousavizadeh Tehrani 	if ((p->if_capabilities2 & IFCAP2_BIT(IFCAP2_GENEVE_HWCSUM)) != 0)
3330e44d2e94SPouria Mousavizadeh Tehrani 		cap |= p->if_capabilities & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6);
3331e44d2e94SPouria Mousavizadeh Tehrani 	if ((p->if_capenable2 & IFCAP2_BIT(IFCAP2_GENEVE_HWCSUM)) != 0) {
3332e44d2e94SPouria Mousavizadeh Tehrani 		ena |= sc->gnv_reqcap & p->if_capenable & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6);
3333e44d2e94SPouria Mousavizadeh Tehrani 		if (ena & IFCAP_TXCSUM) {
3334e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP)
3335e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP;
3336e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP_UDP)
3337e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP_UDP;
3338e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP_TCP)
3339e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP_TCP;
3340e44d2e94SPouria Mousavizadeh Tehrani 		}
3341e44d2e94SPouria Mousavizadeh Tehrani 		if (ena & IFCAP_TXCSUM_IPV6) {
3342e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP6_UDP)
3343e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP6_UDP;
3344e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP6_TCP)
3345e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP6_TCP;
3346e44d2e94SPouria Mousavizadeh Tehrani 		}
3347e44d2e94SPouria Mousavizadeh Tehrani 	}
3348e44d2e94SPouria Mousavizadeh Tehrani 
3349e44d2e94SPouria Mousavizadeh Tehrani 	/* hardware TSO */
3350e44d2e94SPouria Mousavizadeh Tehrani 	if ((p->if_capabilities2 & IFCAP2_BIT(IFCAP2_GENEVE_HWTSO)) != 0) {
3351e44d2e94SPouria Mousavizadeh Tehrani 		cap |= p->if_capabilities & IFCAP_TSO;
3352e44d2e94SPouria Mousavizadeh Tehrani 		if (p->if_hw_tsomax > IP_MAXPACKET - ifp->if_hdrlen)
3353e44d2e94SPouria Mousavizadeh Tehrani 			ifp->if_hw_tsomax = IP_MAXPACKET - ifp->if_hdrlen;
3354e44d2e94SPouria Mousavizadeh Tehrani 		else
3355e44d2e94SPouria Mousavizadeh Tehrani 			ifp->if_hw_tsomax = p->if_hw_tsomax;
3356e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_hw_tsomaxsegcount = p->if_hw_tsomaxsegcount - 1;
3357e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_hw_tsomaxsegsize = p->if_hw_tsomaxsegsize;
3358e44d2e94SPouria Mousavizadeh Tehrani 	}
3359e44d2e94SPouria Mousavizadeh Tehrani 	if ((p->if_capenable2 & IFCAP2_BIT(IFCAP2_GENEVE_HWTSO)) != 0) {
3360e44d2e94SPouria Mousavizadeh Tehrani 		ena |= sc->gnv_reqcap & p->if_capenable & IFCAP_TSO;
3361e44d2e94SPouria Mousavizadeh Tehrani 		if (ena & IFCAP_TSO) {
3362e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP_TSO)
3363e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP_TSO;
3364e44d2e94SPouria Mousavizadeh Tehrani 			if (p->if_hwassist & CSUM_INNER_IP6_TSO)
3365e44d2e94SPouria Mousavizadeh Tehrani 				hwa |= CSUM_IP6_TSO;
3366e44d2e94SPouria Mousavizadeh Tehrani 		}
3367e44d2e94SPouria Mousavizadeh Tehrani 	}
3368e44d2e94SPouria Mousavizadeh Tehrani 
3369e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_capabilities |= cap;
3370e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_capenable |= ena;
3371e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_hwassist |= hwa;
3372e44d2e94SPouria Mousavizadeh Tehrani 	if (rel)
3373e44d2e94SPouria Mousavizadeh Tehrani 		if_rele(p);
3374e44d2e94SPouria Mousavizadeh Tehrani 
3375e44d2e94SPouria Mousavizadeh Tehrani 	CURVNET_RESTORE();
3376e44d2e94SPouria Mousavizadeh Tehrani 	NET_EPOCH_EXIT(et);
3377e44d2e94SPouria Mousavizadeh Tehrani }
3378e44d2e94SPouria Mousavizadeh Tehrani 
3379e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_clone_create_nl(struct if_clone * ifc,char * name,size_t len,struct ifc_data_nl * ifd)3380e44d2e94SPouria Mousavizadeh Tehrani geneve_clone_create_nl(struct if_clone *ifc, char *name, size_t len,
3381e44d2e94SPouria Mousavizadeh Tehrani     struct ifc_data_nl *ifd)
3382e44d2e94SPouria Mousavizadeh Tehrani {
3383e44d2e94SPouria Mousavizadeh Tehrani 	struct nl_parsed_link *lattrs = ifd->lattrs;
3384e44d2e94SPouria Mousavizadeh Tehrani 	struct nl_pstate *npt = ifd->npt;
3385e44d2e94SPouria Mousavizadeh Tehrani 	struct nl_parsed_geneve attrs = {};
3386e44d2e94SPouria Mousavizadeh Tehrani 	int error;
3387e44d2e94SPouria Mousavizadeh Tehrani 
3388e44d2e94SPouria Mousavizadeh Tehrani 	if ((lattrs->ifla_idata == NULL) ||
3389e44d2e94SPouria Mousavizadeh Tehrani 	    (!nl_has_attr(ifd->bm, IFLA_LINKINFO))) {
3390e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "geneve protocol is required");
3391e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOTSUP);
3392e44d2e94SPouria Mousavizadeh Tehrani 	}
3393e44d2e94SPouria Mousavizadeh Tehrani 
3394e44d2e94SPouria Mousavizadeh Tehrani 	error = nl_parse_nested(lattrs->ifla_idata, &geneve_create_parser, npt, &attrs);
3395e44d2e94SPouria Mousavizadeh Tehrani 	if (error != 0)
3396e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
3397e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_check_proto(attrs.ifla_proto)) {
3398e44d2e94SPouria Mousavizadeh Tehrani 		nlmsg_report_err_msg(npt, "Unsupported ethertype: 0x%04X", attrs.ifla_proto);
3399e44d2e94SPouria Mousavizadeh Tehrani 		return (ENOTSUP);
3400e44d2e94SPouria Mousavizadeh Tehrani 	}
3401e44d2e94SPouria Mousavizadeh Tehrani 
3402e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_params gnvp = { .ifla_proto = attrs.ifla_proto };
3403e44d2e94SPouria Mousavizadeh Tehrani 	struct ifc_data ifd_new = {
3404e44d2e94SPouria Mousavizadeh Tehrani 		.flags = IFC_F_SYSSPACE,
3405e44d2e94SPouria Mousavizadeh Tehrani 		.unit = ifd->unit,
3406e44d2e94SPouria Mousavizadeh Tehrani 		.params = &gnvp
3407e44d2e94SPouria Mousavizadeh Tehrani 	};
3408e44d2e94SPouria Mousavizadeh Tehrani 
3409e44d2e94SPouria Mousavizadeh Tehrani 	return (geneve_clone_create(ifc, name, len, &ifd_new, &ifd->ifp));
3410e44d2e94SPouria Mousavizadeh Tehrani }
3411e44d2e94SPouria Mousavizadeh Tehrani 
3412e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_clone_modify_nl(struct ifnet * ifp,struct ifc_data_nl * ifd)3413e44d2e94SPouria Mousavizadeh Tehrani geneve_clone_modify_nl(struct ifnet *ifp, struct ifc_data_nl *ifd)
3414e44d2e94SPouria Mousavizadeh Tehrani {
3415e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc = ifp->if_softc;
3416e44d2e94SPouria Mousavizadeh Tehrani 	struct nl_parsed_link *lattrs = ifd->lattrs;
3417e44d2e94SPouria Mousavizadeh Tehrani 	struct nl_pstate *npt = ifd->npt;
3418e44d2e94SPouria Mousavizadeh Tehrani 	struct nl_parsed_geneve params;
3419e44d2e94SPouria Mousavizadeh Tehrani 	struct nlattr *attrs = lattrs->ifla_idata;
3420e44d2e94SPouria Mousavizadeh Tehrani 	struct nlattr_bmask bm;
3421e44d2e94SPouria Mousavizadeh Tehrani 	int error = 0;
3422e44d2e94SPouria Mousavizadeh Tehrani 
3423e44d2e94SPouria Mousavizadeh Tehrani 	if ((attrs == NULL) ||
3424e44d2e94SPouria Mousavizadeh Tehrani 	    (nl_has_attr(ifd->bm, IFLA_LINKINFO) == 0)) {
3425e44d2e94SPouria Mousavizadeh Tehrani 		error = nl_modify_ifp_generic(ifp, lattrs, ifd->bm, npt);
3426e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
3427e44d2e94SPouria Mousavizadeh Tehrani 	}
3428e44d2e94SPouria Mousavizadeh Tehrani 
3429e44d2e94SPouria Mousavizadeh Tehrani 	error = priv_check(curthread, PRIV_NET_GENEVE);
3430e44d2e94SPouria Mousavizadeh Tehrani 	if (error)
3431e44d2e94SPouria Mousavizadeh Tehrani 		return (error);
3432e44d2e94SPouria Mousavizadeh Tehrani 
3433e44d2e94SPouria Mousavizadeh Tehrani 	/* make sure ignored attributes by nl_parse will not cause panics */
3434e44d2e94SPouria Mousavizadeh Tehrani 	memset(&params, 0, sizeof(params));
3435e44d2e94SPouria Mousavizadeh Tehrani 
3436e44d2e94SPouria Mousavizadeh Tehrani 	nl_get_attrs_bmask_raw(NLA_DATA(attrs), NLA_DATA_LEN(attrs), &bm);
3437e44d2e94SPouria Mousavizadeh Tehrani 	error = nl_parse_nested(attrs, &geneve_modify_parser, npt, &params);
3438e44d2e94SPouria Mousavizadeh Tehrani 
3439e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_ID))
3440e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_vni_nl(sc, npt, params.ifla_vni);
3441e44d2e94SPouria Mousavizadeh Tehrani 
3442e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_LOCAL))
3443e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_local_addr_nl(sc, npt, params.ifla_local);
3444e44d2e94SPouria Mousavizadeh Tehrani 
3445e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_REMOTE))
3446e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_remote_addr_nl(sc, npt, params.ifla_remote);
3447e44d2e94SPouria Mousavizadeh Tehrani 
3448e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_LOCAL_PORT))
3449e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_local_port_nl(sc, npt, params.ifla_local_port);
3450e44d2e94SPouria Mousavizadeh Tehrani 
3451e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_PORT))
3452e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_remote_port_nl(sc, npt, params.ifla_remote_port);
3453e44d2e94SPouria Mousavizadeh Tehrani 
3454e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_PORT_RANGE))
3455e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_port_range_nl(sc, npt, params.ifla_port_range);
3456e44d2e94SPouria Mousavizadeh Tehrani 
3457e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_DF))
3458e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_df_nl(sc, npt, params.ifla_df);
3459e44d2e94SPouria Mousavizadeh Tehrani 
3460e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_TTL))
3461e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_ttl_nl(sc, npt, params.ifla_ttl);
3462e44d2e94SPouria Mousavizadeh Tehrani 
3463e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_TTL_INHERIT))
3464e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_ttl_inherit_nl(sc, npt, params.ifla_ttl_inherit);
3465e44d2e94SPouria Mousavizadeh Tehrani 
3466e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_DSCP_INHERIT))
3467e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_dscp_inherit_nl(sc, npt, params.ifla_dscp_inherit);
3468e44d2e94SPouria Mousavizadeh Tehrani 
3469e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_COLLECT_METADATA))
3470e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_collect_metadata_nl(sc, npt, params.ifla_external);
3471e44d2e94SPouria Mousavizadeh Tehrani 
3472e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_FTABLE_LEARN))
3473e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_learn_nl(sc, npt, params.ifla_ftable_learn);
3474e44d2e94SPouria Mousavizadeh Tehrani 
3475e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_FTABLE_FLUSH))
3476e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_flush_ftable_nl(sc, npt, params.ifla_ftable_flush);
3477e44d2e94SPouria Mousavizadeh Tehrani 
3478e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_FTABLE_MAX))
3479e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_ftable_max_nl(sc, npt, params.ifla_ftable_max);
3480e44d2e94SPouria Mousavizadeh Tehrani 
3481e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_FTABLE_TIMEOUT))
3482e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_ftable_timeout_nl(sc, npt, params.ifla_ftable_timeout);
3483e44d2e94SPouria Mousavizadeh Tehrani 
3484e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0 && nl_has_attr(&bm, IFLA_GENEVE_MC_IFNAME))
3485e44d2e94SPouria Mousavizadeh Tehrani 		error = geneve_set_mc_if_nl(sc, npt, params.ifla_mc_ifname);
3486e44d2e94SPouria Mousavizadeh Tehrani 
3487e44d2e94SPouria Mousavizadeh Tehrani 	if (error == 0)
3488e44d2e94SPouria Mousavizadeh Tehrani 		error = nl_modify_ifp_generic(ifp, lattrs, ifd->bm, npt);
3489e44d2e94SPouria Mousavizadeh Tehrani 
3490e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
3491e44d2e94SPouria Mousavizadeh Tehrani }
3492e44d2e94SPouria Mousavizadeh Tehrani 
3493e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_clone_dump_nl(struct ifnet * ifp,struct nl_writer * nw)3494e44d2e94SPouria Mousavizadeh Tehrani geneve_clone_dump_nl(struct ifnet *ifp, struct nl_writer *nw)
3495e44d2e94SPouria Mousavizadeh Tehrani {
3496e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
3497e44d2e94SPouria Mousavizadeh Tehrani 	struct rm_priotracker tracker;
3498e44d2e94SPouria Mousavizadeh Tehrani 	int off, off2;
3499e44d2e94SPouria Mousavizadeh Tehrani 
3500e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_LINK, ifp->if_index);
3501e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_string(nw, IFLA_IFNAME, ifp->if_xname);
3502e44d2e94SPouria Mousavizadeh Tehrani 
3503e44d2e94SPouria Mousavizadeh Tehrani 	off = nlattr_add_nested(nw, IFLA_LINKINFO);
3504e44d2e94SPouria Mousavizadeh Tehrani 	if (off == 0)
3505e44d2e94SPouria Mousavizadeh Tehrani 		return;
3506e44d2e94SPouria Mousavizadeh Tehrani 
3507e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_string(nw, IFLA_INFO_KIND, "geneve");
3508e44d2e94SPouria Mousavizadeh Tehrani 	off2 = nlattr_add_nested(nw, IFLA_INFO_DATA);
3509e44d2e94SPouria Mousavizadeh Tehrani 	if (off2 == 0) {
3510e44d2e94SPouria Mousavizadeh Tehrani 		nlattr_set_len(nw, off);
3511e44d2e94SPouria Mousavizadeh Tehrani 		return;
3512e44d2e94SPouria Mousavizadeh Tehrani 	}
3513e44d2e94SPouria Mousavizadeh Tehrani 
3514e44d2e94SPouria Mousavizadeh Tehrani 	sc = ifp->if_softc;
3515e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_RLOCK(sc, &tracker);
3516e44d2e94SPouria Mousavizadeh Tehrani 
3517e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_ID, sc->gnv_vni);
3518e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u16(nw, IFLA_GENEVE_PROTOCOL, sc->gnv_proto);
3519e44d2e94SPouria Mousavizadeh Tehrani 	geneve_get_local_addr_nl(sc, nw);
3520e44d2e94SPouria Mousavizadeh Tehrani 	geneve_get_remote_addr_nl(sc, nw);
3521e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u16(nw, IFLA_GENEVE_LOCAL_PORT, geneve_get_local_port(sc));
3522e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u16(nw, IFLA_GENEVE_PORT, geneve_get_remote_port(sc));
3523e44d2e94SPouria Mousavizadeh Tehrani 
3524e44d2e94SPouria Mousavizadeh Tehrani 	const struct ifla_geneve_port_range port_range = {
3525e44d2e94SPouria Mousavizadeh Tehrani 		.low = sc->gnv_min_port,
3526e44d2e94SPouria Mousavizadeh Tehrani 		.high = sc->gnv_max_port
3527e44d2e94SPouria Mousavizadeh Tehrani 	};
3528e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add(nw, IFLA_GENEVE_PORT_RANGE, sizeof(port_range), &port_range);
3529e44d2e94SPouria Mousavizadeh Tehrani 
3530e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u8(nw, IFLA_GENEVE_DF, (uint8_t)sc->gnv_df);
3531e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u8(nw, IFLA_GENEVE_TTL, sc->gnv_ttl);
3532e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_bool(nw, IFLA_GENEVE_TTL_INHERIT,
3533e44d2e94SPouria Mousavizadeh Tehrani 	    sc->gnv_flags & GENEVE_FLAG_TTL_INHERIT);
3534e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_bool(nw, IFLA_GENEVE_DSCP_INHERIT,
3535e44d2e94SPouria Mousavizadeh Tehrani 	    sc->gnv_flags & GENEVE_FLAG_DSCP_INHERIT);
3536e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_bool(nw, IFLA_GENEVE_COLLECT_METADATA,
3537e44d2e94SPouria Mousavizadeh Tehrani 	    sc->gnv_flags & GENEVE_FLAG_COLLECT_METADATA);
3538e44d2e94SPouria Mousavizadeh Tehrani 
3539e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_bool(nw, IFLA_GENEVE_FTABLE_LEARN,
3540e44d2e94SPouria Mousavizadeh Tehrani 	    sc->gnv_flags & GENEVE_FLAG_LEARN);
3541e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_FTABLE_MAX, sc->gnv_ftable_max);
3542e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_FTABLE_TIMEOUT, sc->gnv_ftable_timeout);
3543e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_FTABLE_COUNT, sc->gnv_ftable_cnt);
3544e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_FTABLE_NOSPACE_CNT, sc->gnv_stats.ftable_nospace);
3545e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_FTABLE_LOCK_UP_FAIL_CNT,
3546e44d2e94SPouria Mousavizadeh Tehrani 	    sc->gnv_stats.ftable_lock_upgrade_failed);
3547e44d2e94SPouria Mousavizadeh Tehrani 
3548e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_string(nw, IFLA_GENEVE_MC_IFNAME, sc->gnv_mc_ifname);
3549e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u32(nw, IFLA_GENEVE_MC_IFINDEX, sc->gnv_mc_ifindex);
3550e44d2e94SPouria Mousavizadeh Tehrani 
3551e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u64(nw, IFLA_GENEVE_TXCSUM_CNT,
3552e44d2e94SPouria Mousavizadeh Tehrani 	    counter_u64_fetch(sc->gnv_stats.txcsum));
3553e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u64(nw, IFLA_GENEVE_TSO_CNT,
3554e44d2e94SPouria Mousavizadeh Tehrani 	    counter_u64_fetch(sc->gnv_stats.tso));
3555e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_add_u64(nw, IFLA_GENEVE_RXCSUM_CNT,
3556e44d2e94SPouria Mousavizadeh Tehrani 	    counter_u64_fetch(sc->gnv_stats.rxcsum));
3557e44d2e94SPouria Mousavizadeh Tehrani 
3558e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_set_len(nw, off2);
3559e44d2e94SPouria Mousavizadeh Tehrani 	nlattr_set_len(nw, off);
3560e44d2e94SPouria Mousavizadeh Tehrani 
3561e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_RUNLOCK(sc, &tracker);
3562e44d2e94SPouria Mousavizadeh Tehrani }
3563e44d2e94SPouria Mousavizadeh Tehrani 
3564e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_clone_create(struct if_clone * ifc,char * name,size_t len,struct ifc_data * ifd,struct ifnet ** ifpp)3565e44d2e94SPouria Mousavizadeh Tehrani geneve_clone_create(struct if_clone *ifc, char *name, size_t len,
3566e44d2e94SPouria Mousavizadeh Tehrani     struct ifc_data *ifd, struct ifnet **ifpp)
3567e44d2e94SPouria Mousavizadeh Tehrani {
3568e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
3569e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_params gnvp;
3570e44d2e94SPouria Mousavizadeh Tehrani 	struct ifnet *ifp;
3571e44d2e94SPouria Mousavizadeh Tehrani 	int error;
3572e44d2e94SPouria Mousavizadeh Tehrani 
3573e44d2e94SPouria Mousavizadeh Tehrani 	sc = malloc(sizeof(struct geneve_softc), M_GENEVE, M_WAITOK | M_ZERO);
3574e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_fibnum = curthread->td_proc->p_fibnum;
3575e44d2e94SPouria Mousavizadeh Tehrani 	geneve_set_default_config(sc);
3576e44d2e94SPouria Mousavizadeh Tehrani 
3577e44d2e94SPouria Mousavizadeh Tehrani 	if (ifd != NULL) {
3578e44d2e94SPouria Mousavizadeh Tehrani 		error = ifc_copyin(ifd, &gnvp, sizeof(gnvp));
3579e44d2e94SPouria Mousavizadeh Tehrani 		if (error != 0 ||
3580e44d2e94SPouria Mousavizadeh Tehrani 		    (error = geneve_check_proto(gnvp.ifla_proto)) != 0) {
3581e44d2e94SPouria Mousavizadeh Tehrani 			free(sc, M_GENEVE);
3582e44d2e94SPouria Mousavizadeh Tehrani 			return (error);
3583e44d2e94SPouria Mousavizadeh Tehrani 		}
3584e44d2e94SPouria Mousavizadeh Tehrani 
3585e44d2e94SPouria Mousavizadeh Tehrani 		sc->gnv_proto = gnvp.ifla_proto;
3586e44d2e94SPouria Mousavizadeh Tehrani 	}
3587e44d2e94SPouria Mousavizadeh Tehrani 
3588e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER) {
3589e44d2e94SPouria Mousavizadeh Tehrani 		ifp = if_alloc(IFT_ETHER);
3590e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_flags |= IFF_SIMPLEX | IFF_BROADCAST;
3591e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_init(sc);
3592e44d2e94SPouria Mousavizadeh Tehrani 		callout_init_rw(&sc->gnv_callout, &sc->gnv_lock, 0);
3593e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sc->gnv_proto == GENEVE_PROTO_INHERIT) {
3594e44d2e94SPouria Mousavizadeh Tehrani 		ifp = if_alloc(IFT_TUNNEL);
3595e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_flags |= IFF_NOARP;
3596e44d2e94SPouria Mousavizadeh Tehrani 	} else {
3597e44d2e94SPouria Mousavizadeh Tehrani 		free(sc, M_GENEVE);
3598e44d2e94SPouria Mousavizadeh Tehrani 		return (EINVAL);
3599e44d2e94SPouria Mousavizadeh Tehrani 	}
3600e44d2e94SPouria Mousavizadeh Tehrani 
3601e44d2e94SPouria Mousavizadeh Tehrani 	geneve_stats_alloc(sc);
3602e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_ifp = ifp;
3603e44d2e94SPouria Mousavizadeh Tehrani 	rm_init(&sc->gnv_lock, "geneverm");
3604e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_port_hash_key = arc4random();
3605e44d2e94SPouria Mousavizadeh Tehrani 
3606e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_softc = sc;
3607e44d2e94SPouria Mousavizadeh Tehrani 	if_initname(ifp, geneve_name, ifd->unit);
3608e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_flags |= IFF_MULTICAST;
3609e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_init = geneve_init;
3610e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_ioctl = geneve_ioctl;
3611e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_transmit = geneve_transmit;
3612e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_qflush = geneve_qflush;
3613e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_capabilities = GENEVE_BASIC_IFCAPS;
3614e44d2e94SPouria Mousavizadeh Tehrani 	ifp->if_capenable = GENEVE_BASIC_IFCAPS;
3615e44d2e94SPouria Mousavizadeh Tehrani 	sc->gnv_reqcap = -1;
3616e44d2e94SPouria Mousavizadeh Tehrani 	geneve_set_hwcaps(sc);
3617e44d2e94SPouria Mousavizadeh Tehrani 
3618e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER) {
3619e44d2e94SPouria Mousavizadeh Tehrani 		ifmedia_init(&sc->gnv_media, 0, geneve_media_change, geneve_media_status);
3620e44d2e94SPouria Mousavizadeh Tehrani 		ifmedia_add(&sc->gnv_media, IFM_ETHER | IFM_AUTO, 0, NULL);
3621e44d2e94SPouria Mousavizadeh Tehrani 		ifmedia_set(&sc->gnv_media, IFM_ETHER | IFM_AUTO);
3622e44d2e94SPouria Mousavizadeh Tehrani 
3623e44d2e94SPouria Mousavizadeh Tehrani 		ether_gen_addr(ifp, &sc->gnv_hwaddr);
3624e44d2e94SPouria Mousavizadeh Tehrani 		ether_ifattach(ifp, sc->gnv_hwaddr.octet);
3625e44d2e94SPouria Mousavizadeh Tehrani 
3626e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_baudrate = 0;
3627e44d2e94SPouria Mousavizadeh Tehrani 	} else {
3628e44d2e94SPouria Mousavizadeh Tehrani 		ifp->if_output = geneve_output;
3629e44d2e94SPouria Mousavizadeh Tehrani 
3630e44d2e94SPouria Mousavizadeh Tehrani 		if_attach(ifp);
3631e44d2e94SPouria Mousavizadeh Tehrani 		bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
3632e44d2e94SPouria Mousavizadeh Tehrani 	}
3633e44d2e94SPouria Mousavizadeh Tehrani 
3634e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WLOCK(sc);
3635e44d2e94SPouria Mousavizadeh Tehrani 	geneve_setup_interface_hdrlen(sc);
3636e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_WUNLOCK(sc);
3637e44d2e94SPouria Mousavizadeh Tehrani 	*ifpp = ifp;
3638e44d2e94SPouria Mousavizadeh Tehrani 
3639e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3640e44d2e94SPouria Mousavizadeh Tehrani }
3641e44d2e94SPouria Mousavizadeh Tehrani 
3642e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_clone_destroy(struct if_clone * ifc,struct ifnet * ifp,uint32_t flags)3643e44d2e94SPouria Mousavizadeh Tehrani geneve_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
3644e44d2e94SPouria Mousavizadeh Tehrani {
3645e44d2e94SPouria Mousavizadeh Tehrani 	struct geneve_softc *sc;
3646e44d2e94SPouria Mousavizadeh Tehrani 
3647e44d2e94SPouria Mousavizadeh Tehrani 	sc = if_getsoftc(ifp);
3648e44d2e94SPouria Mousavizadeh Tehrani 	geneve_teardown(sc);
3649e44d2e94SPouria Mousavizadeh Tehrani 
3650e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_proto == GENEVE_PROTO_ETHER) {
3651e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_flush(sc, 1);
3652e44d2e94SPouria Mousavizadeh Tehrani 
3653e44d2e94SPouria Mousavizadeh Tehrani 		ether_ifdetach(ifp);
3654e44d2e94SPouria Mousavizadeh Tehrani 		if_free(ifp);
3655e44d2e94SPouria Mousavizadeh Tehrani 		ifmedia_removeall(&sc->gnv_media);
3656e44d2e94SPouria Mousavizadeh Tehrani 
3657e44d2e94SPouria Mousavizadeh Tehrani 		geneve_ftable_fini(sc);
3658e44d2e94SPouria Mousavizadeh Tehrani 	} else {
3659e44d2e94SPouria Mousavizadeh Tehrani 		bpfdetach(ifp);
3660e44d2e94SPouria Mousavizadeh Tehrani 		if_detach(ifp);
3661e44d2e94SPouria Mousavizadeh Tehrani 		if_free(ifp);
3662e44d2e94SPouria Mousavizadeh Tehrani 	}
3663e44d2e94SPouria Mousavizadeh Tehrani 
3664e44d2e94SPouria Mousavizadeh Tehrani 	rm_destroy(&sc->gnv_lock);
3665e44d2e94SPouria Mousavizadeh Tehrani 	geneve_stats_free(sc);
3666e44d2e94SPouria Mousavizadeh Tehrani 	free(sc, M_GENEVE);
3667e44d2e94SPouria Mousavizadeh Tehrani 
3668e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3669e44d2e94SPouria Mousavizadeh Tehrani }
3670e44d2e94SPouria Mousavizadeh Tehrani 
3671e44d2e94SPouria Mousavizadeh Tehrani /* BMV: Taken from if_bridge. */
3672e44d2e94SPouria Mousavizadeh Tehrani static uint32_t
geneve_mac_hash(struct geneve_softc * sc,const uint8_t * addr)3673e44d2e94SPouria Mousavizadeh Tehrani geneve_mac_hash(struct geneve_softc *sc, const uint8_t *addr)
3674e44d2e94SPouria Mousavizadeh Tehrani {
3675e44d2e94SPouria Mousavizadeh Tehrani 	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->gnv_ftable_hash_key;
3676e44d2e94SPouria Mousavizadeh Tehrani 
3677e44d2e94SPouria Mousavizadeh Tehrani 	b += addr[5] << 8;
3678e44d2e94SPouria Mousavizadeh Tehrani 	b += addr[4];
3679e44d2e94SPouria Mousavizadeh Tehrani 	a += addr[3] << 24;
3680e44d2e94SPouria Mousavizadeh Tehrani 	a += addr[2] << 16;
3681e44d2e94SPouria Mousavizadeh Tehrani 	a += addr[1] << 8;
3682e44d2e94SPouria Mousavizadeh Tehrani 	a += addr[0];
3683e44d2e94SPouria Mousavizadeh Tehrani 
3684e44d2e94SPouria Mousavizadeh Tehrani /*
3685e44d2e94SPouria Mousavizadeh Tehrani  * The following hash function is adapted from "Hash Functions" by Bob Jenkins
3686e44d2e94SPouria Mousavizadeh Tehrani  * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
3687e44d2e94SPouria Mousavizadeh Tehrani  */
3688e44d2e94SPouria Mousavizadeh Tehrani #define	mix(a, b, c)							\
3689e44d2e94SPouria Mousavizadeh Tehrani do {									\
3690e44d2e94SPouria Mousavizadeh Tehrani 	a -= b; a -= c; a ^= (c >> 13);					\
3691e44d2e94SPouria Mousavizadeh Tehrani 	b -= c; b -= a; b ^= (a << 8);					\
3692e44d2e94SPouria Mousavizadeh Tehrani 	c -= a; c -= b; c ^= (b >> 13);					\
3693e44d2e94SPouria Mousavizadeh Tehrani 	a -= b; a -= c; a ^= (c >> 12);					\
3694e44d2e94SPouria Mousavizadeh Tehrani 	b -= c; b -= a; b ^= (a << 16);					\
3695e44d2e94SPouria Mousavizadeh Tehrani 	c -= a; c -= b; c ^= (b >> 5);					\
3696e44d2e94SPouria Mousavizadeh Tehrani 	a -= b; a -= c; a ^= (c >> 3);					\
3697e44d2e94SPouria Mousavizadeh Tehrani 	b -= c; b -= a; b ^= (a << 10);					\
3698e44d2e94SPouria Mousavizadeh Tehrani 	c -= a; c -= b; c ^= (b >> 15);					\
3699e44d2e94SPouria Mousavizadeh Tehrani } while (0)
3700e44d2e94SPouria Mousavizadeh Tehrani 
3701e44d2e94SPouria Mousavizadeh Tehrani 	mix(a, b, c);
3702e44d2e94SPouria Mousavizadeh Tehrani 
3703e44d2e94SPouria Mousavizadeh Tehrani #undef mix
3704e44d2e94SPouria Mousavizadeh Tehrani 
3705e44d2e94SPouria Mousavizadeh Tehrani 	return (c);
3706e44d2e94SPouria Mousavizadeh Tehrani }
3707e44d2e94SPouria Mousavizadeh Tehrani 
3708e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_media_change(struct ifnet * ifp)3709e44d2e94SPouria Mousavizadeh Tehrani geneve_media_change(struct ifnet *ifp)
3710e44d2e94SPouria Mousavizadeh Tehrani {
3711e44d2e94SPouria Mousavizadeh Tehrani 
3712e44d2e94SPouria Mousavizadeh Tehrani 	/* Ignore. */
3713e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3714e44d2e94SPouria Mousavizadeh Tehrani }
3715e44d2e94SPouria Mousavizadeh Tehrani 
3716e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_media_status(struct ifnet * ifp,struct ifmediareq * ifmr)3717e44d2e94SPouria Mousavizadeh Tehrani geneve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
3718e44d2e94SPouria Mousavizadeh Tehrani {
3719e44d2e94SPouria Mousavizadeh Tehrani 
3720e44d2e94SPouria Mousavizadeh Tehrani 	ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
3721e44d2e94SPouria Mousavizadeh Tehrani 	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
3722e44d2e94SPouria Mousavizadeh Tehrani }
3723e44d2e94SPouria Mousavizadeh Tehrani 
3724e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_sockaddr_cmp(const union sockaddr_union * unsa,const struct sockaddr * sa)3725e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_cmp(const union sockaddr_union *unsa,
3726e44d2e94SPouria Mousavizadeh Tehrani     const struct sockaddr *sa)
3727e44d2e94SPouria Mousavizadeh Tehrani {
3728e44d2e94SPouria Mousavizadeh Tehrani 
3729e44d2e94SPouria Mousavizadeh Tehrani 	return (memcmp(&unsa->sa, sa, unsa->sa.sa_len));
3730e44d2e94SPouria Mousavizadeh Tehrani }
3731e44d2e94SPouria Mousavizadeh Tehrani 
3732e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_sockaddr_copy(union sockaddr_union * dst,const struct sockaddr * sa)3733e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_copy(union sockaddr_union *dst,
3734e44d2e94SPouria Mousavizadeh Tehrani     const struct sockaddr *sa)
3735e44d2e94SPouria Mousavizadeh Tehrani {
3736e44d2e94SPouria Mousavizadeh Tehrani 
3737e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
3738e44d2e94SPouria Mousavizadeh Tehrani 	memset(dst, 0, sizeof(*dst));
3739e44d2e94SPouria Mousavizadeh Tehrani 
3740e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_INET) {
3741e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin = *SATOCONSTSIN(sa);
3742e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin.sin_len = sizeof(struct sockaddr_in);
3743e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
3744e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin6 = *SATOCONSTSIN6(sa);
3745e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
3746e44d2e94SPouria Mousavizadeh Tehrani 	}
3747e44d2e94SPouria Mousavizadeh Tehrani }
3748e44d2e94SPouria Mousavizadeh Tehrani 
3749e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_sockaddr_in_equal(const union sockaddr_union * unsa,const struct sockaddr * sa)3750e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_in_equal(const union sockaddr_union *unsa,
3751e44d2e94SPouria Mousavizadeh Tehrani     const struct sockaddr *sa)
3752e44d2e94SPouria Mousavizadeh Tehrani {
3753e44d2e94SPouria Mousavizadeh Tehrani 	int equal;
3754e44d2e94SPouria Mousavizadeh Tehrani 
3755e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_INET) {
3756e44d2e94SPouria Mousavizadeh Tehrani 		const struct in_addr *in4 = &SATOCONSTSIN(sa)->sin_addr;
3757e44d2e94SPouria Mousavizadeh Tehrani 		equal = in4->s_addr == unsa->sin.sin_addr.s_addr;
3758e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
3759e44d2e94SPouria Mousavizadeh Tehrani 		const struct in6_addr *in6 = &SATOCONSTSIN6(sa)->sin6_addr;
3760e44d2e94SPouria Mousavizadeh Tehrani 		equal = IN6_ARE_ADDR_EQUAL(in6, &unsa->sin6.sin6_addr);
3761e44d2e94SPouria Mousavizadeh Tehrani 	} else
3762e44d2e94SPouria Mousavizadeh Tehrani 		equal = 0;
3763e44d2e94SPouria Mousavizadeh Tehrani 
3764e44d2e94SPouria Mousavizadeh Tehrani 	return (equal);
3765e44d2e94SPouria Mousavizadeh Tehrani }
3766e44d2e94SPouria Mousavizadeh Tehrani 
3767e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_sockaddr_in_copy(union sockaddr_union * dst,const struct sockaddr * sa)3768e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_in_copy(union sockaddr_union *dst,
3769e44d2e94SPouria Mousavizadeh Tehrani     const struct sockaddr *sa)
3770e44d2e94SPouria Mousavizadeh Tehrani {
3771e44d2e94SPouria Mousavizadeh Tehrani 
3772e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
3773e44d2e94SPouria Mousavizadeh Tehrani 
3774e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_INET) {
3775e44d2e94SPouria Mousavizadeh Tehrani 		const struct in_addr *in4 = &SATOCONSTSIN(sa)->sin_addr;
3776e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin.sin_family = AF_INET;
3777e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin.sin_len = sizeof(struct sockaddr_in);
3778e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin.sin_addr = *in4;
3779e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
3780e44d2e94SPouria Mousavizadeh Tehrani 		const struct in6_addr *in6 = &SATOCONSTSIN6(sa)->sin6_addr;
3781e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin6.sin6_family = AF_INET6;
3782e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
3783e44d2e94SPouria Mousavizadeh Tehrani 		dst->sin6.sin6_addr = *in6;
3784e44d2e94SPouria Mousavizadeh Tehrani 	}
3785e44d2e94SPouria Mousavizadeh Tehrani }
3786e44d2e94SPouria Mousavizadeh Tehrani 
3787e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_sockaddr_supported(const union sockaddr_union * gnvaddr,int unspec)3788e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_supported(const union sockaddr_union *gnvaddr, int unspec)
3789e44d2e94SPouria Mousavizadeh Tehrani {
3790e44d2e94SPouria Mousavizadeh Tehrani 	const struct sockaddr *sa;
3791e44d2e94SPouria Mousavizadeh Tehrani 	int supported;
3792e44d2e94SPouria Mousavizadeh Tehrani 
3793e44d2e94SPouria Mousavizadeh Tehrani 	sa = &gnvaddr->sa;
3794e44d2e94SPouria Mousavizadeh Tehrani 	supported = 0;
3795e44d2e94SPouria Mousavizadeh Tehrani 
3796e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_UNSPEC && unspec != 0) {
3797e44d2e94SPouria Mousavizadeh Tehrani 		supported = 1;
3798e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET) {
3799e44d2e94SPouria Mousavizadeh Tehrani 		supported = 1;
3800e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
3801e44d2e94SPouria Mousavizadeh Tehrani 		supported = 1;
3802e44d2e94SPouria Mousavizadeh Tehrani 	}
3803e44d2e94SPouria Mousavizadeh Tehrani 
3804e44d2e94SPouria Mousavizadeh Tehrani 	return (supported);
3805e44d2e94SPouria Mousavizadeh Tehrani }
3806e44d2e94SPouria Mousavizadeh Tehrani 
3807e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_sockaddr_in_any(const union sockaddr_union * gnvaddr)3808e44d2e94SPouria Mousavizadeh Tehrani geneve_sockaddr_in_any(const union sockaddr_union *gnvaddr)
3809e44d2e94SPouria Mousavizadeh Tehrani {
3810e44d2e94SPouria Mousavizadeh Tehrani 	const struct sockaddr *sa;
3811e44d2e94SPouria Mousavizadeh Tehrani 	int any;
3812e44d2e94SPouria Mousavizadeh Tehrani 
3813e44d2e94SPouria Mousavizadeh Tehrani 	sa = &gnvaddr->sa;
3814e44d2e94SPouria Mousavizadeh Tehrani 
3815e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa_family == AF_INET) {
3816e44d2e94SPouria Mousavizadeh Tehrani 		const struct in_addr *in4 = &SATOCONSTSIN(sa)->sin_addr;
3817e44d2e94SPouria Mousavizadeh Tehrani 		any = in4->s_addr == INADDR_ANY;
3818e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa_family == AF_INET6) {
3819e44d2e94SPouria Mousavizadeh Tehrani 		const struct in6_addr *in6 = &SATOCONSTSIN6(sa)->sin6_addr;
3820e44d2e94SPouria Mousavizadeh Tehrani 		any = IN6_IS_ADDR_UNSPECIFIED(in6);
3821e44d2e94SPouria Mousavizadeh Tehrani 	} else
3822e44d2e94SPouria Mousavizadeh Tehrani 		any = -1;
3823e44d2e94SPouria Mousavizadeh Tehrani 
3824e44d2e94SPouria Mousavizadeh Tehrani 	return (any);
3825e44d2e94SPouria Mousavizadeh Tehrani }
3826e44d2e94SPouria Mousavizadeh Tehrani 
3827e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_can_change_config(struct geneve_softc * sc)3828e44d2e94SPouria Mousavizadeh Tehrani geneve_can_change_config(struct geneve_softc *sc)
3829e44d2e94SPouria Mousavizadeh Tehrani {
3830e44d2e94SPouria Mousavizadeh Tehrani 
3831e44d2e94SPouria Mousavizadeh Tehrani 	GENEVE_LOCK_ASSERT(sc);
3832e44d2e94SPouria Mousavizadeh Tehrani 
3833e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_RUNNING)
3834e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
3835e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & (GENEVE_FLAG_INIT | GENEVE_FLAG_TEARDOWN))
3836e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
3837e44d2e94SPouria Mousavizadeh Tehrani 	if (sc->gnv_flags & GENEVE_FLAG_COLLECT_METADATA)
3838e44d2e94SPouria Mousavizadeh Tehrani 		return (0);
3839e44d2e94SPouria Mousavizadeh Tehrani 
3840e44d2e94SPouria Mousavizadeh Tehrani 	return (1);
3841e44d2e94SPouria Mousavizadeh Tehrani }
3842e44d2e94SPouria Mousavizadeh Tehrani 
3843e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_check_proto(uint16_t proto)3844e44d2e94SPouria Mousavizadeh Tehrani geneve_check_proto(uint16_t proto)
3845e44d2e94SPouria Mousavizadeh Tehrani {
3846e44d2e94SPouria Mousavizadeh Tehrani 	int error;
3847e44d2e94SPouria Mousavizadeh Tehrani 
3848e44d2e94SPouria Mousavizadeh Tehrani 	switch (proto) {
3849e44d2e94SPouria Mousavizadeh Tehrani 	case GENEVE_PROTO_ETHER:
3850e44d2e94SPouria Mousavizadeh Tehrani 	case GENEVE_PROTO_INHERIT:
3851e44d2e94SPouria Mousavizadeh Tehrani 		error = 0;
3852e44d2e94SPouria Mousavizadeh Tehrani 		break;
3853e44d2e94SPouria Mousavizadeh Tehrani 
3854e44d2e94SPouria Mousavizadeh Tehrani 	default:
3855e44d2e94SPouria Mousavizadeh Tehrani 		error = EAFNOSUPPORT;
3856e44d2e94SPouria Mousavizadeh Tehrani 		break;
3857e44d2e94SPouria Mousavizadeh Tehrani 	}
3858e44d2e94SPouria Mousavizadeh Tehrani 
3859e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
3860e44d2e94SPouria Mousavizadeh Tehrani }
3861e44d2e94SPouria Mousavizadeh Tehrani 
3862e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_check_multicast_addr(const union sockaddr_union * sa)3863e44d2e94SPouria Mousavizadeh Tehrani geneve_check_multicast_addr(const union sockaddr_union *sa)
3864e44d2e94SPouria Mousavizadeh Tehrani {
3865e44d2e94SPouria Mousavizadeh Tehrani 	int mc;
3866e44d2e94SPouria Mousavizadeh Tehrani 
3867e44d2e94SPouria Mousavizadeh Tehrani 	if (sa->sa.sa_family == AF_INET) {
3868e44d2e94SPouria Mousavizadeh Tehrani 		const struct in_addr *in4 = &SATOCONSTSIN(sa)->sin_addr;
3869e44d2e94SPouria Mousavizadeh Tehrani 		mc = IN_MULTICAST(ntohl(in4->s_addr));
3870e44d2e94SPouria Mousavizadeh Tehrani 	} else if (sa->sa.sa_family == AF_INET6) {
3871e44d2e94SPouria Mousavizadeh Tehrani 		const struct in6_addr *in6 = &SATOCONSTSIN6(sa)->sin6_addr;
3872e44d2e94SPouria Mousavizadeh Tehrani 		mc = IN6_IS_ADDR_MULTICAST(in6);
3873e44d2e94SPouria Mousavizadeh Tehrani 	} else
3874e44d2e94SPouria Mousavizadeh Tehrani 		mc = EINVAL;
3875e44d2e94SPouria Mousavizadeh Tehrani 
3876e44d2e94SPouria Mousavizadeh Tehrani 	return (mc);
3877e44d2e94SPouria Mousavizadeh Tehrani }
3878e44d2e94SPouria Mousavizadeh Tehrani 
3879e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_check_sockaddr(const union sockaddr_union * sa,const int len)3880e44d2e94SPouria Mousavizadeh Tehrani geneve_check_sockaddr(const union sockaddr_union *sa, const int len)
3881e44d2e94SPouria Mousavizadeh Tehrani {
3882e44d2e94SPouria Mousavizadeh Tehrani 	int error;
3883e44d2e94SPouria Mousavizadeh Tehrani 
3884e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
3885e44d2e94SPouria Mousavizadeh Tehrani 	switch (sa->sa.sa_family) {
3886e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET:
3887e44d2e94SPouria Mousavizadeh Tehrani 	case AF_INET6:
3888e44d2e94SPouria Mousavizadeh Tehrani 		if (len < sizeof(struct sockaddr))
3889e44d2e94SPouria Mousavizadeh Tehrani 			error = EINVAL;
3890e44d2e94SPouria Mousavizadeh Tehrani 		break;
3891e44d2e94SPouria Mousavizadeh Tehrani 
3892e44d2e94SPouria Mousavizadeh Tehrani 	default:
3893e44d2e94SPouria Mousavizadeh Tehrani 		error = EAFNOSUPPORT;
3894e44d2e94SPouria Mousavizadeh Tehrani 	}
3895e44d2e94SPouria Mousavizadeh Tehrani 
3896e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
3897e44d2e94SPouria Mousavizadeh Tehrani }
3898e44d2e94SPouria Mousavizadeh Tehrani 
3899e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_prison_remove(void * obj,void * data __unused)3900e44d2e94SPouria Mousavizadeh Tehrani geneve_prison_remove(void *obj, void *data __unused)
3901e44d2e94SPouria Mousavizadeh Tehrani {
3902e44d2e94SPouria Mousavizadeh Tehrani #ifdef VIMAGE
3903e44d2e94SPouria Mousavizadeh Tehrani 	struct prison *pr;
3904e44d2e94SPouria Mousavizadeh Tehrani 
3905e44d2e94SPouria Mousavizadeh Tehrani 	pr = obj;
3906e44d2e94SPouria Mousavizadeh Tehrani 	if (prison_owns_vnet(pr)) {
3907e44d2e94SPouria Mousavizadeh Tehrani 		CURVNET_SET(pr->pr_vnet);
3908e44d2e94SPouria Mousavizadeh Tehrani 		if (V_geneve_cloner != NULL) {
3909e44d2e94SPouria Mousavizadeh Tehrani 			ifc_detach_cloner(V_geneve_cloner);
3910e44d2e94SPouria Mousavizadeh Tehrani 			V_geneve_cloner = NULL;
3911e44d2e94SPouria Mousavizadeh Tehrani 		}
3912e44d2e94SPouria Mousavizadeh Tehrani 		CURVNET_RESTORE();
3913e44d2e94SPouria Mousavizadeh Tehrani 	}
3914e44d2e94SPouria Mousavizadeh Tehrani #endif
3915e44d2e94SPouria Mousavizadeh Tehrani 	return (0);
3916e44d2e94SPouria Mousavizadeh Tehrani }
3917e44d2e94SPouria Mousavizadeh Tehrani 
3918e44d2e94SPouria Mousavizadeh Tehrani static void
vnet_geneve_load(void)3919e44d2e94SPouria Mousavizadeh Tehrani vnet_geneve_load(void)
3920e44d2e94SPouria Mousavizadeh Tehrani {
3921e44d2e94SPouria Mousavizadeh Tehrani 	struct if_clone_addreq_v2 req = {
3922e44d2e94SPouria Mousavizadeh Tehrani 		.version = 2,
3923e44d2e94SPouria Mousavizadeh Tehrani 		.flags = IFC_F_AUTOUNIT,
3924e44d2e94SPouria Mousavizadeh Tehrani 		.match_f = NULL,
3925e44d2e94SPouria Mousavizadeh Tehrani 		.create_f = geneve_clone_create,
3926e44d2e94SPouria Mousavizadeh Tehrani 		.destroy_f = geneve_clone_destroy,
3927e44d2e94SPouria Mousavizadeh Tehrani 		.create_nl_f = geneve_clone_create_nl,
3928e44d2e94SPouria Mousavizadeh Tehrani 		.modify_nl_f = geneve_clone_modify_nl,
3929e44d2e94SPouria Mousavizadeh Tehrani 		.dump_nl_f = geneve_clone_dump_nl,
3930e44d2e94SPouria Mousavizadeh Tehrani 	};
3931e44d2e94SPouria Mousavizadeh Tehrani 	V_geneve_cloner = ifc_attach_cloner(geneve_name, (struct if_clone_addreq *)&req);
3932e44d2e94SPouria Mousavizadeh Tehrani }
3933e44d2e94SPouria Mousavizadeh Tehrani VNET_SYSINIT(vnet_geneve_load, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, vnet_geneve_load, NULL);
3934e44d2e94SPouria Mousavizadeh Tehrani 
3935e44d2e94SPouria Mousavizadeh Tehrani static void
vnet_geneve_unload(void)3936e44d2e94SPouria Mousavizadeh Tehrani vnet_geneve_unload(void)
3937e44d2e94SPouria Mousavizadeh Tehrani {
3938e44d2e94SPouria Mousavizadeh Tehrani 
3939e44d2e94SPouria Mousavizadeh Tehrani 	if (V_geneve_cloner != NULL)
3940e44d2e94SPouria Mousavizadeh Tehrani 		ifc_detach_cloner(V_geneve_cloner);
3941e44d2e94SPouria Mousavizadeh Tehrani }
3942e44d2e94SPouria Mousavizadeh Tehrani VNET_SYSUNINIT(vnet_geneve_unload, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, vnet_geneve_unload, NULL);
3943e44d2e94SPouria Mousavizadeh Tehrani 
3944e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_module_init(void)3945e44d2e94SPouria Mousavizadeh Tehrani geneve_module_init(void)
3946e44d2e94SPouria Mousavizadeh Tehrani {
3947e44d2e94SPouria Mousavizadeh Tehrani 	mtx_init(&geneve_list_mtx, "geneve list", NULL, MTX_DEF);
3948e44d2e94SPouria Mousavizadeh Tehrani 	osd_method_t methods[PR_MAXMETHOD] = {
3949e44d2e94SPouria Mousavizadeh Tehrani 		[PR_METHOD_REMOVE] = geneve_prison_remove,
3950e44d2e94SPouria Mousavizadeh Tehrani 	};
3951e44d2e94SPouria Mousavizadeh Tehrani 
3952e44d2e94SPouria Mousavizadeh Tehrani 	geneve_osd_jail_slot = osd_jail_register(NULL, methods);
3953e44d2e94SPouria Mousavizadeh Tehrani 	NL_VERIFY_PARSERS(all_parsers);
3954e44d2e94SPouria Mousavizadeh Tehrani }
3955e44d2e94SPouria Mousavizadeh Tehrani 
3956e44d2e94SPouria Mousavizadeh Tehrani static void
geneve_module_deinit(void)3957e44d2e94SPouria Mousavizadeh Tehrani geneve_module_deinit(void)
3958e44d2e94SPouria Mousavizadeh Tehrani {
3959e44d2e94SPouria Mousavizadeh Tehrani 	struct if_clone *clone;
3960e44d2e94SPouria Mousavizadeh Tehrani 	VNET_ITERATOR_DECL(vnet_iter);
3961e44d2e94SPouria Mousavizadeh Tehrani 
3962e44d2e94SPouria Mousavizadeh Tehrani 	VNET_LIST_RLOCK();
3963e44d2e94SPouria Mousavizadeh Tehrani 	VNET_FOREACH(vnet_iter) {
3964e44d2e94SPouria Mousavizadeh Tehrani 		clone = VNET_VNET(vnet_iter, geneve_cloner);
3965e44d2e94SPouria Mousavizadeh Tehrani 		if (clone != NULL) {
3966e44d2e94SPouria Mousavizadeh Tehrani 			ifc_detach_cloner(clone);
3967e44d2e94SPouria Mousavizadeh Tehrani 			VNET_VNET(vnet_iter, geneve_cloner) = NULL;
3968e44d2e94SPouria Mousavizadeh Tehrani 		}
3969e44d2e94SPouria Mousavizadeh Tehrani 	}
3970e44d2e94SPouria Mousavizadeh Tehrani 	VNET_LIST_RUNLOCK();
3971e44d2e94SPouria Mousavizadeh Tehrani 	NET_EPOCH_WAIT();
3972e44d2e94SPouria Mousavizadeh Tehrani 	MPASS(LIST_EMPTY(&geneve_socket_list));
3973e44d2e94SPouria Mousavizadeh Tehrani 	mtx_destroy(&geneve_list_mtx);
3974e44d2e94SPouria Mousavizadeh Tehrani 	if (geneve_osd_jail_slot != 0)
3975e44d2e94SPouria Mousavizadeh Tehrani 		osd_jail_deregister(geneve_osd_jail_slot);
3976e44d2e94SPouria Mousavizadeh Tehrani }
3977e44d2e94SPouria Mousavizadeh Tehrani 
3978e44d2e94SPouria Mousavizadeh Tehrani static int
geneve_modevent(module_t mod,int type,void * unused)3979e44d2e94SPouria Mousavizadeh Tehrani geneve_modevent(module_t mod, int type, void *unused)
3980e44d2e94SPouria Mousavizadeh Tehrani {
3981e44d2e94SPouria Mousavizadeh Tehrani 	int error;
3982e44d2e94SPouria Mousavizadeh Tehrani 
3983e44d2e94SPouria Mousavizadeh Tehrani 	error = 0;
3984e44d2e94SPouria Mousavizadeh Tehrani 
3985e44d2e94SPouria Mousavizadeh Tehrani 	switch (type) {
3986e44d2e94SPouria Mousavizadeh Tehrani 	case MOD_LOAD:
3987e44d2e94SPouria Mousavizadeh Tehrani 		geneve_module_init();
3988e44d2e94SPouria Mousavizadeh Tehrani 		break;
3989e44d2e94SPouria Mousavizadeh Tehrani 
3990e44d2e94SPouria Mousavizadeh Tehrani 	case MOD_UNLOAD:
3991e44d2e94SPouria Mousavizadeh Tehrani 		geneve_module_deinit();
3992e44d2e94SPouria Mousavizadeh Tehrani 		break;
3993e44d2e94SPouria Mousavizadeh Tehrani 
3994e44d2e94SPouria Mousavizadeh Tehrani 	default:
3995e44d2e94SPouria Mousavizadeh Tehrani 		error = ENOTSUP;
3996e44d2e94SPouria Mousavizadeh Tehrani 		break;
3997e44d2e94SPouria Mousavizadeh Tehrani 	}
3998e44d2e94SPouria Mousavizadeh Tehrani 
3999e44d2e94SPouria Mousavizadeh Tehrani 	return (error);
4000e44d2e94SPouria Mousavizadeh Tehrani }
4001e44d2e94SPouria Mousavizadeh Tehrani 
4002e44d2e94SPouria Mousavizadeh Tehrani static moduledata_t geneve_mod = {
4003e44d2e94SPouria Mousavizadeh Tehrani 	"if_geneve",
4004e44d2e94SPouria Mousavizadeh Tehrani 	geneve_modevent,
4005e44d2e94SPouria Mousavizadeh Tehrani 	0
4006e44d2e94SPouria Mousavizadeh Tehrani };
4007e44d2e94SPouria Mousavizadeh Tehrani 
4008e44d2e94SPouria Mousavizadeh Tehrani DECLARE_MODULE(if_geneve, geneve_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
4009e44d2e94SPouria Mousavizadeh Tehrani MODULE_VERSION(if_geneve, 1);
4010