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(¶ms, 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, ¶ms);
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