File: | net/if_vxlan.c |
Warning: | line 677, column 4 Value stored to 'sc_cand' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: if_vxlan.c,v 1.83 2022/01/10 14:07:59 jan Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include "bpfilter.h" |
20 | #include "vxlan.h" |
21 | #include "vlan.h" |
22 | #include "pf.h" |
23 | #include "bridge.h" |
24 | |
25 | #include <sys/param.h> |
26 | #include <sys/systm.h> |
27 | #include <sys/mbuf.h> |
28 | #include <sys/socket.h> |
29 | #include <sys/sockio.h> |
30 | #include <sys/ioctl.h> |
31 | |
32 | #include <net/if.h> |
33 | #include <net/if_var.h> |
34 | #include <net/if_media.h> |
35 | #include <net/route.h> |
36 | |
37 | #if NBPFILTER1 > 0 |
38 | #include <net/bpf.h> |
39 | #endif |
40 | |
41 | #include <netinet/in.h> |
42 | #include <netinet/in_var.h> |
43 | #include <netinet/if_ether.h> |
44 | #include <netinet/ip.h> |
45 | #include <netinet/ip_var.h> |
46 | #include <netinet/udp.h> |
47 | #include <netinet/udp_var.h> |
48 | #include <netinet/in_pcb.h> |
49 | |
50 | #if NPF1 > 0 |
51 | #include <net/pfvar.h> |
52 | #endif |
53 | |
54 | #if NBRIDGE1 > 0 |
55 | #include <net/if_bridge.h> |
56 | #endif |
57 | |
58 | #include <net/if_vxlan.h> |
59 | |
60 | struct vxlan_softc { |
61 | struct arpcom sc_ac; |
62 | struct ifmedia sc_media; |
63 | |
64 | struct ip_moptions sc_imo; |
65 | struct task sc_atask; |
66 | struct task sc_ltask; |
67 | struct task sc_dtask; |
68 | |
69 | struct sockaddr_storage sc_src; |
70 | struct sockaddr_storage sc_dst; |
71 | in_port_t sc_dstport; |
72 | u_int sc_rdomain; |
73 | int64_t sc_vnetid; |
74 | uint16_t sc_df; |
75 | u_int8_t sc_ttl; |
76 | int sc_txhprio; |
77 | |
78 | struct task sc_sendtask; |
79 | |
80 | LIST_ENTRY(vxlan_softc)struct { struct vxlan_softc *le_next; struct vxlan_softc **le_prev ; } sc_entry; |
81 | }; |
82 | |
83 | void vxlanattach(int); |
84 | int vxlanioctl(struct ifnet *, u_long, caddr_t); |
85 | void vxlanstart(struct ifnet *); |
86 | int vxlan_clone_create(struct if_clone *, int); |
87 | int vxlan_clone_destroy(struct ifnet *); |
88 | void vxlan_multicast_cleanup(struct ifnet *); |
89 | int vxlan_multicast_join(struct ifnet *, struct sockaddr *, |
90 | struct sockaddr *); |
91 | int vxlan_media_change(struct ifnet *); |
92 | void vxlan_media_status(struct ifnet *, struct ifmediareq *); |
93 | int vxlan_config(struct ifnet *, struct sockaddr *, struct sockaddr *); |
94 | int vxlan_output(struct ifnet *, struct mbuf *); |
95 | void vxlan_addr_change(void *); |
96 | void vxlan_if_change(void *); |
97 | void vxlan_link_change(void *); |
98 | void vxlan_send_dispatch(void *); |
99 | |
100 | int vxlan_sockaddr_cmp(struct sockaddr *, struct sockaddr *); |
101 | uint16_t vxlan_sockaddr_port(struct sockaddr *); |
102 | |
103 | struct if_clone vxlan_cloner = |
104 | IF_CLONE_INITIALIZER("vxlan", vxlan_clone_create, vxlan_clone_destroy){ .ifc_list = { ((void *)0), ((void *)0) }, .ifc_name = "vxlan" , .ifc_namelen = sizeof("vxlan") - 1, .ifc_create = vxlan_clone_create , .ifc_destroy = vxlan_clone_destroy, }; |
105 | |
106 | int vxlan_enable = 0; |
107 | u_long vxlan_tagmask; |
108 | |
109 | #define VXLAN_TAGHASHSIZE32 32 |
110 | #define VXLAN_TAGHASH(tag)((unsigned int)tag & vxlan_tagmask) ((unsigned int)tag & vxlan_tagmask) |
111 | LIST_HEAD(vxlan_taghash, vxlan_softc)struct vxlan_taghash { struct vxlan_softc *lh_first; } *vxlan_tagh, vxlan_any; |
112 | |
113 | void |
114 | vxlanattach(int count) |
115 | { |
116 | /* Regular vxlan interfaces with a VNI */ |
117 | if ((vxlan_tagh = hashinit(VXLAN_TAGHASHSIZE32, M_DEVBUF2, M_NOWAIT0x0002, |
118 | &vxlan_tagmask)) == NULL((void *)0)) |
119 | panic("vxlanattach: hashinit"); |
120 | |
121 | /* multipoint-to-multipoint interfaces that accept any VNI */ |
122 | LIST_INIT(&vxlan_any)do { ((&vxlan_any)->lh_first) = ((void *)0); } while ( 0); |
123 | |
124 | if_clone_attach(&vxlan_cloner); |
125 | } |
126 | |
127 | int |
128 | vxlan_clone_create(struct if_clone *ifc, int unit) |
129 | { |
130 | struct ifnet *ifp; |
131 | struct vxlan_softc *sc; |
132 | |
133 | sc = malloc(sizeof(*sc), M_DEVBUF2, M_WAITOK0x0001|M_ZERO0x0008); |
134 | sc->sc_imo.imo_membership = mallocarray(IP_MIN_MEMBERSHIPS15, |
135 | sizeof(struct in_multi *), M_IPMOPTS53, M_WAITOK0x0001|M_ZERO0x0008); |
136 | sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS15; |
137 | sc->sc_dstport = htons(VXLAN_PORT)(__uint16_t)(__builtin_constant_p(4789) ? (__uint16_t)(((__uint16_t )(4789) & 0xffU) << 8 | ((__uint16_t)(4789) & 0xff00U ) >> 8) : __swap16md(4789)); |
138 | sc->sc_vnetid = VXLAN_VNI_UNSET0x01ffffff; |
139 | sc->sc_txhprio = IFQ_TOS2PRIO(IPTOS_PREC_ROUTINE)((0x00) >> 5); /* 0 */ |
140 | sc->sc_df = htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t )(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U ) >> 8) : __swap16md(0)); |
141 | task_set(&sc->sc_atask, vxlan_addr_change, sc); |
142 | task_set(&sc->sc_ltask, vxlan_link_change, sc); |
143 | task_set(&sc->sc_dtask, vxlan_if_change, sc); |
144 | task_set(&sc->sc_sendtask, vxlan_send_dispatch, sc); |
145 | |
146 | ifp = &sc->sc_ac.ac_if; |
147 | snprintf(ifp->if_xname, sizeof ifp->if_xname, "vxlan%d", unit); |
148 | ifp->if_flags = IFF_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000; |
149 | ether_fakeaddr(ifp); |
150 | |
151 | ifp->if_softc = sc; |
152 | ifp->if_ioctl = vxlanioctl; |
153 | ifp->if_start = vxlanstart; |
154 | |
155 | ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN65435; |
156 | ifp->if_capabilitiesif_data.ifi_capabilities = IFCAP_VLAN_MTU0x00000010; |
157 | ifp->if_xflags = IFXF_CLONED0x2; |
158 | |
159 | ifmedia_init(&sc->sc_media, 0, vxlan_media_change, |
160 | vxlan_media_status); |
161 | ifmedia_add(&sc->sc_media, IFM_ETHER0x0000000000000100ULL | IFM_AUTO0ULL, 0, NULL((void *)0)); |
162 | ifmedia_set(&sc->sc_media, IFM_ETHER0x0000000000000100ULL | IFM_AUTO0ULL); |
163 | |
164 | if_counters_alloc(ifp); |
165 | if_attach(ifp); |
166 | ether_ifattach(ifp); |
167 | |
168 | #if 0 |
169 | /* |
170 | * Instead of using a decreased MTU of 1450 bytes, prefer |
171 | * to use the default Ethernet-size MTU of 1500 bytes and to |
172 | * increase the MTU of the outer transport interfaces to |
173 | * at least 1550 bytes. The following is disabled by default. |
174 | */ |
175 | ifp->if_mtuif_data.ifi_mtu = ETHERMTU(1518 - ((6 * 2) + 2) - 4) - sizeof(struct ether_header); |
176 | ifp->if_mtuif_data.ifi_mtu -= sizeof(struct vxlanudphdr) + sizeof(struct ipovly); |
177 | #endif |
178 | |
179 | LIST_INSERT_HEAD(&vxlan_tagh[VXLAN_TAGHASH(0)], sc, sc_entry)do { if (((sc)->sc_entry.le_next = (&vxlan_tagh[((unsigned int)0 & vxlan_tagmask)])->lh_first) != ((void *)0)) ( &vxlan_tagh[((unsigned int)0 & vxlan_tagmask)])->lh_first ->sc_entry.le_prev = &(sc)->sc_entry.le_next; (& vxlan_tagh[((unsigned int)0 & vxlan_tagmask)])->lh_first = (sc); (sc)->sc_entry.le_prev = &(&vxlan_tagh[(( unsigned int)0 & vxlan_tagmask)])->lh_first; } while ( 0); |
180 | vxlan_enable++; |
181 | |
182 | return (0); |
183 | } |
184 | |
185 | int |
186 | vxlan_clone_destroy(struct ifnet *ifp) |
187 | { |
188 | struct vxlan_softc *sc = ifp->if_softc; |
189 | |
190 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); |
191 | vxlan_multicast_cleanup(ifp); |
192 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); |
193 | |
194 | vxlan_enable--; |
195 | LIST_REMOVE(sc, sc_entry)do { if ((sc)->sc_entry.le_next != ((void *)0)) (sc)->sc_entry .le_next->sc_entry.le_prev = (sc)->sc_entry.le_prev; *( sc)->sc_entry.le_prev = (sc)->sc_entry.le_next; ((sc)-> sc_entry.le_prev) = ((void *)-1); ((sc)->sc_entry.le_next) = ((void *)-1); } while (0); |
196 | |
197 | ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY((uint64_t) -1)); |
198 | ether_ifdetach(ifp); |
199 | if_detach(ifp); |
200 | |
201 | if (!task_del(net_tq(ifp->if_index), &sc->sc_sendtask)) |
202 | taskq_barrier(net_tq(ifp->if_index)); |
203 | |
204 | free(sc->sc_imo.imo_membership, M_IPMOPTS53, |
205 | sc->sc_imo.imo_max_memberships * sizeof(struct in_multi *)); |
206 | free(sc, M_DEVBUF2, sizeof(*sc)); |
207 | |
208 | return (0); |
209 | } |
210 | |
211 | void |
212 | vxlan_multicast_cleanup(struct ifnet *ifp) |
213 | { |
214 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
215 | struct ip_moptions *imo = &sc->sc_imo; |
216 | struct ifnet *mifp; |
217 | |
218 | mifp = if_get(imo->imo_ifidx); |
219 | if (mifp != NULL((void *)0)) { |
220 | if_addrhook_del(mifp, &sc->sc_atask); |
221 | if_linkstatehook_del(mifp, &sc->sc_ltask); |
222 | if_detachhook_del(mifp, &sc->sc_dtask); |
223 | |
224 | if_put(mifp); |
225 | } |
226 | |
227 | if (imo->imo_num_memberships > 0) { |
228 | in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); |
229 | imo->imo_ifidx = 0; |
230 | } |
231 | } |
232 | |
233 | int |
234 | vxlan_multicast_join(struct ifnet *ifp, struct sockaddr *src, |
235 | struct sockaddr *dst) |
236 | { |
237 | struct vxlan_softc *sc = ifp->if_softc; |
238 | struct ip_moptions *imo = &sc->sc_imo; |
239 | struct sockaddr_in *src4, *dst4; |
240 | #ifdef INET61 |
241 | struct sockaddr_in6 *dst6; |
242 | #endif /* INET6 */ |
243 | struct ifaddr *ifa; |
244 | struct ifnet *mifp; |
245 | |
246 | switch (dst->sa_family) { |
247 | case AF_INET2: |
248 | dst4 = satosin(dst); |
249 | if (!IN_MULTICAST(dst4->sin_addr.s_addr)(((u_int32_t)(dst4->sin_addr.s_addr) & ((u_int32_t) (__uint32_t )(__builtin_constant_p((u_int32_t)(0xf0000000)) ? (__uint32_t )(((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0xf0000000))))) == ((u_int32_t ) (__uint32_t)(__builtin_constant_p((u_int32_t)(0xe0000000)) ? (__uint32_t)(((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff ) << 24 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff00 ) << 8 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff0000 ) >> 8 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff000000 ) >> 24) : __swap32md((u_int32_t)(0xe0000000)))))) |
250 | return (0); |
251 | break; |
252 | #ifdef INET61 |
253 | case AF_INET624: |
254 | dst6 = satosin6(dst); |
255 | if (!IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr)((&dst6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff )) |
256 | return (0); |
257 | |
258 | /* Multicast mode is currently not supported for IPv6 */ |
259 | return (EAFNOSUPPORT47); |
260 | #endif /* INET6 */ |
261 | default: |
262 | return (EAFNOSUPPORT47); |
263 | } |
264 | |
265 | src4 = satosin(src); |
266 | dst4 = satosin(dst); |
267 | |
268 | if (src4->sin_addr.s_addr == INADDR_ANY((u_int32_t) (__uint32_t)(__builtin_constant_p((u_int32_t)(0x00000000 )) ? (__uint32_t)(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000) ) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000 )))) || |
269 | IN_MULTICAST(src4->sin_addr.s_addr)(((u_int32_t)(src4->sin_addr.s_addr) & ((u_int32_t) (__uint32_t )(__builtin_constant_p((u_int32_t)(0xf0000000)) ? (__uint32_t )(((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0xf0000000)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0xf0000000))))) == ((u_int32_t ) (__uint32_t)(__builtin_constant_p((u_int32_t)(0xe0000000)) ? (__uint32_t)(((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff ) << 24 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff00 ) << 8 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff0000 ) >> 8 | ((__uint32_t)((u_int32_t)(0xe0000000)) & 0xff000000 ) >> 24) : __swap32md((u_int32_t)(0xe0000000)))))) |
270 | return (EINVAL22); |
271 | if ((ifa = ifa_ifwithaddr(src, sc->sc_rdomain)) == NULL((void *)0) || |
272 | (mifp = ifa->ifa_ifp) == NULL((void *)0) || |
273 | (mifp->if_flags & IFF_MULTICAST0x8000) == 0) |
274 | return (EADDRNOTAVAIL49); |
275 | |
276 | if ((imo->imo_membership[0] = |
277 | in_addmulti(&dst4->sin_addr, mifp)) == NULL((void *)0)) |
278 | return (ENOBUFS55); |
279 | |
280 | imo->imo_num_memberships++; |
281 | imo->imo_ifidx = mifp->if_index; |
282 | if (sc->sc_ttl > 0) |
283 | imo->imo_ttl = sc->sc_ttl; |
284 | else |
285 | imo->imo_ttl = IP_DEFAULT_MULTICAST_TTL1; |
286 | imo->imo_loop = 0; |
287 | |
288 | /* |
289 | * Use interface hooks to track any changes on the interface |
290 | * that is used to send out the tunnel traffic as multicast. |
291 | */ |
292 | if_addrhook_add(mifp, &sc->sc_atask); |
293 | if_linkstatehook_add(mifp, &sc->sc_ltask); |
294 | if_detachhook_add(mifp, &sc->sc_dtask); |
295 | |
296 | return (0); |
297 | } |
298 | |
299 | void |
300 | vxlanstart(struct ifnet *ifp) |
301 | { |
302 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
303 | |
304 | task_add(net_tq(ifp->if_index), &sc->sc_sendtask); |
305 | } |
306 | |
307 | void |
308 | vxlan_send_dispatch(void *xsc) |
309 | { |
310 | struct vxlan_softc *sc = xsc; |
311 | struct ifnet *ifp = &sc->sc_ac.ac_if; |
312 | struct mbuf *m; |
313 | struct mbuf_list ml; |
314 | |
315 | ml_init(&ml); |
316 | for (;;) { |
317 | m = ifq_dequeue(&ifp->if_snd); |
318 | if (m == NULL((void *)0)) |
319 | break; |
320 | |
321 | #if NBPFILTER1 > 0 |
322 | if (ifp->if_bpf) |
323 | bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT(1 << 1)); |
324 | #endif |
325 | |
326 | ml_enqueue(&ml, m); |
327 | } |
328 | |
329 | if (ml_empty(&ml)((&ml)->ml_len == 0)) |
330 | return; |
331 | |
332 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); |
333 | while ((m = ml_dequeue(&ml)) != NULL((void *)0)) { |
334 | vxlan_output(ifp, m); |
335 | } |
336 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); |
337 | } |
338 | |
339 | |
340 | int |
341 | vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) |
342 | { |
343 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
344 | int reset = 0, error, af; |
345 | socklen_t slen; |
346 | in_port_t port; |
347 | struct vxlan_taghash *tagh; |
348 | |
349 | if (src != NULL((void *)0) && dst != NULL((void *)0)) { |
350 | if ((af = src->sa_family) != dst->sa_family) |
351 | return (EAFNOSUPPORT47); |
352 | } else { |
353 | /* Reset current configuration */ |
354 | af = sc->sc_src.ss_family; |
355 | src = sstosa(&sc->sc_src); |
356 | dst = sstosa(&sc->sc_dst); |
357 | reset = 1; |
358 | } |
359 | |
360 | switch (af) { |
361 | case AF_INET2: |
362 | slen = sizeof(struct sockaddr_in); |
363 | break; |
364 | #ifdef INET61 |
365 | case AF_INET624: |
366 | slen = sizeof(struct sockaddr_in6); |
367 | break; |
368 | #endif /* INET6 */ |
369 | default: |
370 | return (EAFNOSUPPORT47); |
371 | } |
372 | |
373 | if (src->sa_len != slen || dst->sa_len != slen) |
374 | return (EINVAL22); |
375 | |
376 | vxlan_multicast_cleanup(ifp); |
377 | |
378 | /* returns without error if multicast is not configured */ |
379 | if ((error = vxlan_multicast_join(ifp, src, dst)) != 0) |
380 | return (error); |
381 | |
382 | if ((port = vxlan_sockaddr_port(dst)) != 0) |
383 | sc->sc_dstport = port; |
384 | |
385 | if (!reset) { |
386 | bzero(&sc->sc_src, sizeof(sc->sc_src))__builtin_bzero((&sc->sc_src), (sizeof(sc->sc_src)) ); |
387 | bzero(&sc->sc_dst, sizeof(sc->sc_dst))__builtin_bzero((&sc->sc_dst), (sizeof(sc->sc_dst)) ); |
388 | memcpy(&sc->sc_src, src, src->sa_len)__builtin_memcpy((&sc->sc_src), (src), (src->sa_len )); |
389 | memcpy(&sc->sc_dst, dst, dst->sa_len)__builtin_memcpy((&sc->sc_dst), (dst), (dst->sa_len )); |
390 | } |
391 | |
392 | if (sc->sc_vnetid == VXLAN_VNI_ANY-1ULL) { |
393 | /* |
394 | * If the interface accepts any VNI, put it into a separate |
395 | * list that is not part of the main hash. |
396 | */ |
397 | tagh = &vxlan_any; |
398 | } else |
399 | tagh = &vxlan_tagh[VXLAN_TAGHASH(sc->sc_vnetid)((unsigned int)sc->sc_vnetid & vxlan_tagmask)]; |
400 | |
401 | LIST_REMOVE(sc, sc_entry)do { if ((sc)->sc_entry.le_next != ((void *)0)) (sc)->sc_entry .le_next->sc_entry.le_prev = (sc)->sc_entry.le_prev; *( sc)->sc_entry.le_prev = (sc)->sc_entry.le_next; ((sc)-> sc_entry.le_prev) = ((void *)-1); ((sc)->sc_entry.le_next) = ((void *)-1); } while (0); |
402 | LIST_INSERT_HEAD(tagh, sc, sc_entry)do { if (((sc)->sc_entry.le_next = (tagh)->lh_first) != ((void *)0)) (tagh)->lh_first->sc_entry.le_prev = & (sc)->sc_entry.le_next; (tagh)->lh_first = (sc); (sc)-> sc_entry.le_prev = &(tagh)->lh_first; } while (0); |
403 | |
404 | return (0); |
405 | } |
406 | |
407 | int |
408 | vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data) |
409 | { |
410 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
411 | struct ifreq *ifr = (struct ifreq *)data; |
412 | struct if_laddrreq *lifr = (struct if_laddrreq *)data; |
413 | int error = 0; |
414 | |
415 | switch (cmd) { |
416 | case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((12))): |
417 | ifp->if_flags |= IFF_UP0x1; |
418 | /* FALLTHROUGH */ |
419 | |
420 | case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((16))): |
421 | if (ifp->if_flags & IFF_UP0x1) { |
422 | ifp->if_flags |= IFF_RUNNING0x40; |
423 | } else { |
424 | ifp->if_flags &= ~IFF_RUNNING0x40; |
425 | } |
426 | break; |
427 | |
428 | case SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((49))): |
429 | case SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((50))): |
430 | break; |
431 | |
432 | case SIOCGIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifmediareq) & 0x1fff) << 16) | ((('i')) << 8) | ((56))): |
433 | case SIOCSIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((55))): |
434 | error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); |
435 | break; |
436 | |
437 | case SIOCSLIFPHYADDR((unsigned long)0x80000000 | ((sizeof(struct if_laddrreq) & 0x1fff) << 16) | ((('i')) << 8) | ((74))): |
438 | error = vxlan_config(ifp, |
439 | sstosa(&lifr->addr), |
440 | sstosa(&lifr->dstaddr)); |
441 | break; |
442 | |
443 | case SIOCDIFPHYADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((73))): |
444 | vxlan_multicast_cleanup(ifp); |
445 | bzero(&sc->sc_src, sizeof(sc->sc_src))__builtin_bzero((&sc->sc_src), (sizeof(sc->sc_src)) ); |
446 | bzero(&sc->sc_dst, sizeof(sc->sc_dst))__builtin_bzero((&sc->sc_dst), (sizeof(sc->sc_dst)) ); |
447 | sc->sc_dstport = htons(VXLAN_PORT)(__uint16_t)(__builtin_constant_p(4789) ? (__uint16_t)(((__uint16_t )(4789) & 0xffU) << 8 | ((__uint16_t)(4789) & 0xff00U ) >> 8) : __swap16md(4789)); |
448 | break; |
449 | |
450 | case SIOCGLIFPHYADDR(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct if_laddrreq) & 0x1fff) << 16) | ((('i')) << 8) | ((75))): |
451 | if (sc->sc_dst.ss_family == AF_UNSPEC0) { |
452 | error = EADDRNOTAVAIL49; |
453 | break; |
454 | } |
455 | bzero(&lifr->addr, sizeof(lifr->addr))__builtin_bzero((&lifr->addr), (sizeof(lifr->addr)) ); |
456 | bzero(&lifr->dstaddr, sizeof(lifr->dstaddr))__builtin_bzero((&lifr->dstaddr), (sizeof(lifr->dstaddr ))); |
457 | memcpy(&lifr->addr, &sc->sc_src, sc->sc_src.ss_len)__builtin_memcpy((&lifr->addr), (&sc->sc_src), ( sc->sc_src.ss_len)); |
458 | memcpy(&lifr->dstaddr, &sc->sc_dst, sc->sc_dst.ss_len)__builtin_memcpy((&lifr->dstaddr), (&sc->sc_dst ), (sc->sc_dst.ss_len)); |
459 | break; |
460 | |
461 | case SIOCSLIFPHYRTABLE((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((161))): |
462 | if (ifr->ifr_rdomainidifr_ifru.ifru_metric < 0 || |
463 | ifr->ifr_rdomainidifr_ifru.ifru_metric > RT_TABLEID_MAX255 || |
464 | !rtable_exists(ifr->ifr_rdomainidifr_ifru.ifru_metric)) { |
465 | error = EINVAL22; |
466 | break; |
467 | } |
468 | sc->sc_rdomain = ifr->ifr_rdomainidifr_ifru.ifru_metric; |
469 | (void)vxlan_config(ifp, NULL((void *)0), NULL((void *)0)); |
470 | break; |
471 | |
472 | case SIOCGLIFPHYRTABLE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((162))): |
473 | ifr->ifr_rdomainidifr_ifru.ifru_metric = sc->sc_rdomain; |
474 | break; |
475 | |
476 | case SIOCSLIFPHYTTL((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((168))): |
477 | if (ifr->ifr_ttlifr_ifru.ifru_metric < 0 || ifr->ifr_ttlifr_ifru.ifru_metric > 0xff) { |
478 | error = EINVAL22; |
479 | break; |
480 | } |
481 | if (sc->sc_ttl == (u_int8_t)ifr->ifr_ttlifr_ifru.ifru_metric) |
482 | break; |
483 | sc->sc_ttl = (u_int8_t)(ifr->ifr_ttlifr_ifru.ifru_metric); |
484 | (void)vxlan_config(ifp, NULL((void *)0), NULL((void *)0)); |
485 | break; |
486 | |
487 | case SIOCGLIFPHYTTL(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((169))): |
488 | ifr->ifr_ttlifr_ifru.ifru_metric = (int)sc->sc_ttl; |
489 | break; |
490 | |
491 | case SIOCSLIFPHYDF((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((193))): |
492 | /* commit */ |
493 | sc->sc_df = ifr->ifr_dfifr_ifru.ifru_metric ? htons(IP_DF)(__uint16_t)(__builtin_constant_p(0x4000) ? (__uint16_t)(((__uint16_t )(0x4000) & 0xffU) << 8 | ((__uint16_t)(0x4000) & 0xff00U) >> 8) : __swap16md(0x4000)) : htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t )(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U ) >> 8) : __swap16md(0)); |
494 | break; |
495 | case SIOCGLIFPHYDF(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((194))): |
496 | ifr->ifr_dfifr_ifru.ifru_metric = sc->sc_df ? 1 : 0; |
497 | break; |
498 | |
499 | case SIOCSTXHPRIO((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((197))): |
500 | if (ifr->ifr_hdrprioifr_ifru.ifru_metric == IF_HDRPRIO_PACKET-1) |
501 | ; /* fall through */ |
502 | else if (ifr->ifr_hdrprioifr_ifru.ifru_metric < IF_HDRPRIO_MIN0 || |
503 | ifr->ifr_hdrprioifr_ifru.ifru_metric > IF_HDRPRIO_MAX8 - 1) { |
504 | error = EINVAL22; |
505 | break; |
506 | } |
507 | |
508 | sc->sc_txhprio = ifr->ifr_hdrprioifr_ifru.ifru_metric; |
509 | break; |
510 | case SIOCGTXHPRIO(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((198))): |
511 | ifr->ifr_hdrprioifr_ifru.ifru_metric = sc->sc_txhprio; |
512 | break; |
513 | |
514 | case SIOCSVNETID((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((166))): |
515 | if (sc->sc_vnetid == ifr->ifr_vnetidifr_ifru.ifru_vnetid) |
516 | break; |
517 | |
518 | if ((ifr->ifr_vnetidifr_ifru.ifru_vnetid != VXLAN_VNI_ANY-1ULL) && |
519 | (ifr->ifr_vnetidifr_ifru.ifru_vnetid > VXLAN_VNI_MAX0x00ffffff || |
520 | ifr->ifr_vnetidifr_ifru.ifru_vnetid < VXLAN_VNI_MIN0x00000000)) { |
521 | error = EINVAL22; |
522 | break; |
523 | } |
524 | |
525 | sc->sc_vnetid = (int)ifr->ifr_vnetidifr_ifru.ifru_vnetid; |
526 | (void)vxlan_config(ifp, NULL((void *)0), NULL((void *)0)); |
527 | break; |
528 | |
529 | case SIOCGVNETID(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct ifreq) & 0x1fff) << 16) | ((('i')) << 8) | ((167))): |
530 | if ((sc->sc_vnetid != VXLAN_VNI_ANY-1ULL) && |
531 | (sc->sc_vnetid > VXLAN_VNI_MAX0x00ffffff || |
532 | sc->sc_vnetid < VXLAN_VNI_MIN0x00000000)) { |
533 | error = EADDRNOTAVAIL49; |
534 | break; |
535 | } |
536 | |
537 | ifr->ifr_vnetidifr_ifru.ifru_vnetid = sc->sc_vnetid; |
538 | break; |
539 | |
540 | case SIOCDVNETID((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff ) << 16) | ((('i')) << 8) | ((175))): |
541 | sc->sc_vnetid = VXLAN_VNI_UNSET0x01ffffff; |
542 | (void)vxlan_config(ifp, NULL((void *)0), NULL((void *)0)); |
543 | break; |
544 | |
545 | default: |
546 | error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); |
547 | break; |
548 | } |
549 | |
550 | return (error); |
551 | } |
552 | |
553 | int |
554 | vxlan_media_change(struct ifnet *ifp) |
555 | { |
556 | return (0); |
557 | } |
558 | |
559 | void |
560 | vxlan_media_status(struct ifnet *ifp, struct ifmediareq *imr) |
561 | { |
562 | imr->ifm_status = IFM_AVALID0x0000000000000001ULL | IFM_ACTIVE0x0000000000000002ULL; |
563 | } |
564 | |
565 | int |
566 | vxlan_sockaddr_cmp(struct sockaddr *srcsa, struct sockaddr *dstsa) |
567 | { |
568 | struct sockaddr_in *src4, *dst4; |
569 | #ifdef INET61 |
570 | struct sockaddr_in6 *src6, *dst6; |
571 | #endif /* INET6 */ |
572 | |
573 | if (srcsa->sa_family != dstsa->sa_family) |
574 | return (1); |
575 | |
576 | switch (dstsa->sa_family) { |
577 | case AF_INET2: |
578 | src4 = satosin(srcsa); |
579 | dst4 = satosin(dstsa); |
580 | if (src4->sin_addr.s_addr == dst4->sin_addr.s_addr) |
581 | return (0); |
582 | break; |
583 | #ifdef INET61 |
584 | case AF_INET624: |
585 | src6 = satosin6(srcsa); |
586 | dst6 = satosin6(dstsa); |
587 | if (IN6_ARE_ADDR_EQUAL(&src6->sin6_addr, &dst6->sin6_addr)(__builtin_memcmp((&(&src6->sin6_addr)->__u6_addr .__u6_addr8[0]), (&(&dst6->sin6_addr)->__u6_addr .__u6_addr8[0]), (sizeof(struct in6_addr))) == 0) && |
588 | src6->sin6_scope_id == dst6->sin6_scope_id) |
589 | return (0); |
590 | break; |
591 | #endif /* INET6 */ |
592 | } |
593 | |
594 | return (1); |
595 | } |
596 | |
597 | uint16_t |
598 | vxlan_sockaddr_port(struct sockaddr *sa) |
599 | { |
600 | struct sockaddr_in *sin4; |
601 | #ifdef INET61 |
602 | struct sockaddr_in6 *sin6; |
603 | #endif /* INET6 */ |
604 | |
605 | switch (sa->sa_family) { |
606 | case AF_INET2: |
607 | sin4 = satosin(sa); |
608 | return (sin4->sin_port); |
609 | #ifdef INET61 |
610 | case AF_INET624: |
611 | sin6 = satosin6(sa); |
612 | return (sin6->sin6_port); |
613 | #endif /* INET6 */ |
614 | default: |
615 | break; |
616 | } |
617 | |
618 | return (0); |
619 | } |
620 | |
621 | int |
622 | vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen, |
623 | struct sockaddr *srcsa, struct sockaddr *dstsa) |
624 | { |
625 | struct vxlan_softc *sc = NULL((void *)0), *sc_cand = NULL((void *)0); |
626 | struct vxlan_header v; |
627 | int vni; |
628 | struct ifnet *ifp; |
629 | int skip; |
630 | #if NBRIDGE1 > 0 |
631 | struct bridge_tunneltag *brtag; |
632 | #endif |
633 | struct mbuf *n; |
634 | int off; |
635 | |
636 | /* XXX Should verify the UDP port first before copying the packet */ |
637 | skip = iphlen + sizeof(*uh); |
638 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip < sizeof(v)) |
639 | return (0); |
640 | m_copydata(m, skip, sizeof(v), &v); |
641 | skip += sizeof(v); |
642 | |
643 | if (v.vxlan_flags & htonl(VXLAN_RESERVED1)(__uint32_t)(__builtin_constant_p(0xf7ffffff) ? (__uint32_t)( ((__uint32_t)(0xf7ffffff) & 0xff) << 24 | ((__uint32_t )(0xf7ffffff) & 0xff00) << 8 | ((__uint32_t)(0xf7ffffff ) & 0xff0000) >> 8 | ((__uint32_t)(0xf7ffffff) & 0xff000000) >> 24) : __swap32md(0xf7ffffff)) || |
644 | v.vxlan_id & htonl(VXLAN_RESERVED2)(__uint32_t)(__builtin_constant_p(0x000000ff) ? (__uint32_t)( ((__uint32_t)(0x000000ff) & 0xff) << 24 | ((__uint32_t )(0x000000ff) & 0xff00) << 8 | ((__uint32_t)(0x000000ff ) & 0xff0000) >> 8 | ((__uint32_t)(0x000000ff) & 0xff000000) >> 24) : __swap32md(0x000000ff))) |
645 | return (0); |
646 | |
647 | vni = ntohl(v.vxlan_id)(__uint32_t)(__builtin_constant_p(v.vxlan_id) ? (__uint32_t)( ((__uint32_t)(v.vxlan_id) & 0xff) << 24 | ((__uint32_t )(v.vxlan_id) & 0xff00) << 8 | ((__uint32_t)(v.vxlan_id ) & 0xff0000) >> 8 | ((__uint32_t)(v.vxlan_id) & 0xff000000) >> 24) : __swap32md(v.vxlan_id)) >> VXLAN_VNI_S8; |
648 | if ((v.vxlan_flags & htonl(VXLAN_FLAGS_VNI)(__uint32_t)(__builtin_constant_p(0x08000000) ? (__uint32_t)( ((__uint32_t)(0x08000000) & 0xff) << 24 | ((__uint32_t )(0x08000000) & 0xff00) << 8 | ((__uint32_t)(0x08000000 ) & 0xff0000) >> 8 | ((__uint32_t)(0x08000000) & 0xff000000) >> 24) : __swap32md(0x08000000))) == 0) { |
649 | if (vni != 0) |
650 | return (0); |
651 | |
652 | vni = VXLAN_VNI_UNSET0x01ffffff; |
653 | } |
654 | |
655 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
656 | /* First search for a vxlan(4) interface with the packet's VNI */ |
657 | LIST_FOREACH(sc, &vxlan_tagh[VXLAN_TAGHASH(vni)], sc_entry)for((sc) = ((&vxlan_tagh[((unsigned int)vni & vxlan_tagmask )])->lh_first); (sc)!= ((void *)0); (sc) = ((sc)->sc_entry .le_next)) { |
658 | if ((uh->uh_dport == sc->sc_dstport) && |
659 | vni == sc->sc_vnetid && |
660 | sc->sc_rdomain == rtable_l2(m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid)) { |
661 | sc_cand = sc; |
662 | if (vxlan_sockaddr_cmp(srcsa, sstosa(&sc->sc_dst)) == 0) |
663 | goto found; |
664 | } |
665 | } |
666 | |
667 | /* |
668 | * Now loop through all the vxlan(4) interfaces that are configured |
669 | * to accept any VNI and operating in multipoint-to-multipoint mode |
670 | * that is used in combination with bridge(4) or switch(4). |
671 | * If a vxlan(4) interface has been found for the packet's VNI, this |
672 | * code is not reached as the other interface is more specific. |
673 | */ |
674 | LIST_FOREACH(sc, &vxlan_any, sc_entry)for((sc) = ((&vxlan_any)->lh_first); (sc)!= ((void *)0 ); (sc) = ((sc)->sc_entry.le_next)) { |
675 | if ((uh->uh_dport == sc->sc_dstport) && |
676 | (sc->sc_rdomain == rtable_l2(m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid))) { |
677 | sc_cand = sc; |
Value stored to 'sc_cand' is never read | |
678 | goto found; |
679 | } |
680 | } |
681 | |
682 | if (sc_cand) { |
683 | sc = sc_cand; |
684 | goto found; |
685 | } |
686 | |
687 | /* not found */ |
688 | return (0); |
689 | |
690 | found: |
691 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.len < skip + sizeof(struct ether_header)) { |
692 | m_freem(m); |
693 | return (EINVAL22); |
694 | } |
695 | |
696 | m_adj(m, skip); |
697 | ifp = &sc->sc_ac.ac_if; |
698 | |
699 | #if NBRIDGE1 > 0 |
700 | /* Store the tunnel src/dst IP and vni for the bridge or switch */ |
701 | if ((ifp->if_bridgeidx != 0 || ifp->if_switchport != NULL((void *)0)) && |
702 | srcsa->sa_family != AF_UNSPEC0 && |
703 | ((brtag = bridge_tunneltag(m)) != NULL((void *)0))) { |
704 | memcpy(&brtag->brtag_peer.sa, srcsa, srcsa->sa_len)__builtin_memcpy((&brtag->brtag_peer.sa), (srcsa), (srcsa ->sa_len)); |
705 | memcpy(&brtag->brtag_local.sa, dstsa, dstsa->sa_len)__builtin_memcpy((&brtag->brtag_local.sa), (dstsa), (dstsa ->sa_len)); |
706 | brtag->brtag_id = vni; |
707 | } |
708 | #endif |
709 | |
710 | m->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
711 | |
712 | #if NPF1 > 0 |
713 | pf_pkt_addr_changed(m); |
714 | #endif |
715 | if ((m->m_lenm_hdr.mh_len < sizeof(struct ether_header)) && |
716 | (m = m_pullup(m, sizeof(struct ether_header))) == NULL((void *)0)) |
717 | return (ENOBUFS55); |
718 | |
719 | n = m_getptr(m, sizeof(struct ether_header), &off); |
720 | if (n == NULL((void *)0)) { |
721 | m_freem(m); |
722 | return (EINVAL22); |
723 | } |
724 | if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)1) { |
725 | n = m_dup_pkt(m, ETHER_ALIGN2, M_NOWAIT0x0002); |
726 | /* Dispose of the original mbuf chain */ |
727 | m_freem(m); |
728 | if (n == NULL((void *)0)) |
729 | return (ENOBUFS55); |
730 | m = n; |
731 | } |
732 | |
733 | if_vinput(ifp, m); |
734 | |
735 | /* success */ |
736 | return (1); |
737 | } |
738 | |
739 | struct mbuf * |
740 | vxlan_encap4(struct ifnet *ifp, struct mbuf *m, |
741 | struct sockaddr *src, struct sockaddr *dst) |
742 | { |
743 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
744 | struct ip *ip; |
745 | |
746 | /* |
747 | * Remove multicast and broadcast flags or encapsulated packet |
748 | * ends up as multicast or broadcast packet. |
749 | */ |
750 | m->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
751 | |
752 | M_PREPEND(m, sizeof(*ip), M_DONTWAIT)(m) = m_prepend((m), (sizeof(*ip)), (0x0002)); |
753 | if (m == NULL((void *)0)) |
754 | return (NULL((void *)0)); |
755 | |
756 | ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data)); |
757 | ip->ip_v = IPVERSION4; |
758 | ip->ip_hl = sizeof(struct ip) >> 2; |
759 | ip->ip_id = htons(ip_randomid())(__uint16_t)(__builtin_constant_p(ip_randomid()) ? (__uint16_t )(((__uint16_t)(ip_randomid()) & 0xffU) << 8 | ((__uint16_t )(ip_randomid()) & 0xff00U) >> 8) : __swap16md(ip_randomid ())); |
760 | ip->ip_off = sc->sc_df; |
761 | ip->ip_p = IPPROTO_UDP17; |
762 | ip->ip_tos = IFQ_PRIO2TOS(sc->sc_txhprio == IF_HDRPRIO_PACKET ?((sc->sc_txhprio == -1 ? m->M_dat.MH.MH_pkthdr.pf.prio : sc->sc_txhprio) << 5) |
763 | m->m_pkthdr.pf.prio : sc->sc_txhprio)((sc->sc_txhprio == -1 ? m->M_dat.MH.MH_pkthdr.pf.prio : sc->sc_txhprio) << 5); |
764 | ip->ip_len = htons(m->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len ) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr.len) & 0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr.len ) & 0xff00U) >> 8) : __swap16md(m->M_dat.MH.MH_pkthdr .len)); |
765 | |
766 | ip->ip_src = satosin(src)->sin_addr; |
767 | ip->ip_dst = satosin(dst)->sin_addr; |
768 | |
769 | if (sc->sc_ttl > 0) |
770 | ip->ip_ttl = sc->sc_ttl; |
771 | else |
772 | ip->ip_ttl = IPDEFTTL64; |
773 | |
774 | return (m); |
775 | } |
776 | |
777 | #ifdef INET61 |
778 | struct mbuf * |
779 | vxlan_encap6(struct ifnet *ifp, struct mbuf *m, |
780 | struct sockaddr *src, struct sockaddr *dst) |
781 | { |
782 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
783 | struct ip6_hdr *ip6; |
784 | struct in6_addr *in6a; |
785 | uint32_t flow; |
786 | |
787 | /* |
788 | * Remove multicast and broadcast flags or encapsulated packet |
789 | * ends up as multicast or broadcast packet. |
790 | */ |
791 | m->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
792 | |
793 | M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT)(m) = m_prepend((m), (sizeof(struct ip6_hdr)), (0x0002)); |
794 | if (m == NULL((void *)0)) |
795 | return (NULL((void *)0)); |
796 | |
797 | flow = (uint32_t)IFQ_PRIO2TOS(sc->sc_txhprio == IF_HDRPRIO_PACKET ?((sc->sc_txhprio == -1 ? m->M_dat.MH.MH_pkthdr.pf.prio : sc->sc_txhprio) << 5) |
798 | m->m_pkthdr.pf.prio : sc->sc_txhprio)((sc->sc_txhprio == -1 ? m->M_dat.MH.MH_pkthdr.pf.prio : sc->sc_txhprio) << 5) << 20; |
799 | |
800 | ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)); |
801 | ip6->ip6_flowip6_ctlun.ip6_un1.ip6_un1_flow = htonl(flow)(__uint32_t)(__builtin_constant_p(flow) ? (__uint32_t)(((__uint32_t )(flow) & 0xff) << 24 | ((__uint32_t)(flow) & 0xff00 ) << 8 | ((__uint32_t)(flow) & 0xff0000) >> 8 | ((__uint32_t)(flow) & 0xff000000) >> 24) : __swap32md (flow)); |
802 | ip6->ip6_vfcip6_ctlun.ip6_un2_vfc &= ~IPV6_VERSION_MASK0xf0; |
803 | ip6->ip6_vfcip6_ctlun.ip6_un2_vfc |= IPV6_VERSION0x60; |
804 | ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP17; |
805 | ip6->ip6_plenip6_ctlun.ip6_un1.ip6_un1_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr))(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len - sizeof(struct ip6_hdr)) ? (__uint16_t)(((__uint16_t)(m-> M_dat.MH.MH_pkthdr.len - sizeof(struct ip6_hdr)) & 0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr.len - sizeof (struct ip6_hdr)) & 0xff00U) >> 8) : __swap16md(m-> M_dat.MH.MH_pkthdr.len - sizeof(struct ip6_hdr))); |
806 | if (in6_embedscope(&ip6->ip6_src, satosin6(src), NULL((void *)0)) != 0) |
807 | goto drop; |
808 | if (in6_embedscope(&ip6->ip6_dst, satosin6(dst), NULL((void *)0)) != 0) |
809 | goto drop; |
810 | |
811 | if (sc->sc_ttl > 0) |
812 | ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim = sc->sc_ttl; |
813 | else |
814 | ip6->ip6_hlimip6_ctlun.ip6_un1.ip6_un1_hlim = ip6_defhlim; |
815 | |
816 | if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr)((*(const u_int32_t *)(const void *)(&(&satosin6(src) ->sin6_addr)->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t *)(const void *)(&(&satosin6(src) ->sin6_addr)->__u6_addr.__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void *)(&(&satosin6(src) ->sin6_addr)->__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t *)(const void *)(&(&satosin6(src) ->sin6_addr)->__u6_addr.__u6_addr8[12]) == 0))) { |
817 | if (in6_selectsrc(&in6a, satosin6(dst), NULL((void *)0), |
818 | sc->sc_rdomain) != 0) |
819 | goto drop; |
820 | |
821 | ip6->ip6_src = *in6a; |
822 | } |
823 | |
824 | if (sc->sc_df) |
825 | SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT)((m->M_dat.MH.MH_pkthdr.csum_flags) |= (0x1000)); |
826 | |
827 | /* |
828 | * The UDP checksum of VXLAN packets should be set to zero, |
829 | * but the IPv6 UDP checksum is not optional. There is an RFC 6539 |
830 | * to relax the IPv6 UDP checksum requirement for tunnels, but it |
831 | * is currently not supported by most implementations. |
832 | */ |
833 | m->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags |= M_UDP_CSUM_OUT0x0004; |
834 | |
835 | return (m); |
836 | |
837 | drop: |
838 | m_freem(m); |
839 | return (NULL((void *)0)); |
840 | } |
841 | #endif /* INET6 */ |
842 | |
843 | int |
844 | vxlan_output(struct ifnet *ifp, struct mbuf *m) |
845 | { |
846 | struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; |
847 | struct vxlanudphdr *vu; |
848 | struct sockaddr *src, *dst; |
849 | #if NBRIDGE1 > 0 |
850 | struct bridge_tunneltag *brtag; |
851 | #endif |
852 | int error, af; |
853 | uint32_t tag; |
854 | struct mbuf *m0; |
855 | |
856 | /* VXLAN header, needs new mbuf because of alignment issues */ |
857 | MGET(m0, M_DONTWAIT, m->m_type)m0 = m_get((0x0002), (m->m_hdr.mh_type)); |
858 | if (m0 == NULL((void *)0)) { |
859 | ifp->if_oerrorsif_data.ifi_oerrors++; |
860 | return (ENOBUFS55); |
861 | } |
862 | M_MOVE_PKTHDR(m0, m)do { (m0)->m_hdr.mh_flags = ((m0)->m_hdr.mh_flags & (0x0001 | 0x0008)); (m0)->m_hdr.mh_flags |= (m)->m_hdr .mh_flags & (0x0002|0x0004|0x0010|0x0100|0x0200|0x0400|0x4000 | 0x0800|0x0040|0x1000|0x8000|0x0020|0x2000); do { ((m0))-> M_dat.MH.MH_pkthdr = ((m))->M_dat.MH.MH_pkthdr; ((m))-> m_hdr.mh_flags &= ~0x0002; { ((&((m))->M_dat.MH.MH_pkthdr .ph_tags)->slh_first) = ((void *)0); }; ((m))->M_dat.MH .MH_pkthdr.pf.statekey = ((void *)0); } while ( 0); if (((m0) ->m_hdr.mh_flags & 0x0001) == 0) (m0)->m_hdr.mh_data = (m0)->M_dat.MH.MH_dat.MH_databuf; } while ( 0); |
863 | m0->m_nextm_hdr.mh_next = m; |
864 | m = m0; |
865 | m_align(m, sizeof(*vu)); |
866 | m->m_lenm_hdr.mh_len = sizeof(*vu); |
867 | m->m_pkthdrM_dat.MH.MH_pkthdr.len += sizeof(*vu); |
868 | |
869 | src = sstosa(&sc->sc_src); |
870 | dst = sstosa(&sc->sc_dst); |
871 | af = src->sa_family; |
872 | |
873 | vu = mtod(m, struct vxlanudphdr *)((struct vxlanudphdr *)((m)->m_hdr.mh_data)); |
874 | vu->vu_u.uh_sport = sc->sc_dstport; |
875 | vu->vu_u.uh_dport = sc->sc_dstport; |
876 | vu->vu_u.uh_ulen = htons(m->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len ) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr.len) & 0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr.len ) & 0xff00U) >> 8) : __swap16md(m->M_dat.MH.MH_pkthdr .len)); |
877 | vu->vu_u.uh_sum = 0; |
878 | tag = sc->sc_vnetid; |
879 | |
880 | #if NBRIDGE1 > 0 |
881 | if ((brtag = bridge_tunnel(m)) != NULL((void *)0)) { |
882 | dst = &brtag->brtag_peer.sa; |
883 | |
884 | /* If accepting any VNI, source ip address is from brtag */ |
885 | if (sc->sc_vnetid == VXLAN_VNI_ANY-1ULL) { |
886 | src = &brtag->brtag_local.sa; |
887 | tag = (uint32_t)brtag->brtag_id; |
888 | af = src->sa_family; |
889 | } |
890 | |
891 | if (dst->sa_family != af) { |
892 | ifp->if_oerrorsif_data.ifi_oerrors++; |
893 | m_freem(m); |
894 | return (EINVAL22); |
895 | } |
896 | } else |
897 | #endif |
898 | if (sc->sc_vnetid == VXLAN_VNI_ANY-1ULL) { |
899 | /* |
900 | * If accepting any VNI, build the vxlan header only by |
901 | * bridge_tunneltag or drop packet if the tag does not exist. |
902 | */ |
903 | ifp->if_oerrorsif_data.ifi_oerrors++; |
904 | m_freem(m); |
905 | return (ENETUNREACH51); |
906 | } |
907 | |
908 | if (sc->sc_vnetid != VXLAN_VNI_UNSET0x01ffffff) { |
909 | vu->vu_v.vxlan_flags = htonl(VXLAN_FLAGS_VNI)(__uint32_t)(__builtin_constant_p(0x08000000) ? (__uint32_t)( ((__uint32_t)(0x08000000) & 0xff) << 24 | ((__uint32_t )(0x08000000) & 0xff00) << 8 | ((__uint32_t)(0x08000000 ) & 0xff0000) >> 8 | ((__uint32_t)(0x08000000) & 0xff000000) >> 24) : __swap32md(0x08000000)); |
910 | vu->vu_v.vxlan_id = htonl(tag << VXLAN_VNI_S)(__uint32_t)(__builtin_constant_p(tag << 8) ? (__uint32_t )(((__uint32_t)(tag << 8) & 0xff) << 24 | ((__uint32_t )(tag << 8) & 0xff00) << 8 | ((__uint32_t)(tag << 8) & 0xff0000) >> 8 | ((__uint32_t)(tag << 8) & 0xff000000) >> 24) : __swap32md(tag << 8 )); |
911 | } else { |
912 | vu->vu_v.vxlan_flags = htonl(0)(__uint32_t)(__builtin_constant_p(0) ? (__uint32_t)(((__uint32_t )(0) & 0xff) << 24 | ((__uint32_t)(0) & 0xff00) << 8 | ((__uint32_t)(0) & 0xff0000) >> 8 | ( (__uint32_t)(0) & 0xff000000) >> 24) : __swap32md(0 )); |
913 | vu->vu_v.vxlan_id = htonl(0)(__uint32_t)(__builtin_constant_p(0) ? (__uint32_t)(((__uint32_t )(0) & 0xff) << 24 | ((__uint32_t)(0) & 0xff00) << 8 | ((__uint32_t)(0) & 0xff0000) >> 8 | ( (__uint32_t)(0) & 0xff000000) >> 24) : __swap32md(0 )); |
914 | } |
915 | |
916 | switch (af) { |
917 | case AF_INET2: |
918 | m = vxlan_encap4(ifp, m, src, dst); |
919 | break; |
920 | #ifdef INET61 |
921 | case AF_INET624: |
922 | m = vxlan_encap6(ifp, m, src, dst); |
923 | break; |
924 | #endif /* INET6 */ |
925 | default: |
926 | m_freem(m); |
927 | m = NULL((void *)0); |
928 | } |
929 | |
930 | if (m == NULL((void *)0)) { |
931 | ifp->if_oerrorsif_data.ifi_oerrors++; |
932 | return (ENOBUFS55); |
933 | } |
934 | |
935 | #if NBRIDGE1 > 0 |
936 | if (brtag != NULL((void *)0)) |
937 | bridge_tunneluntag(m); |
938 | #endif |
939 | |
940 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid = sc->sc_rdomain; |
941 | |
942 | #if NPF1 > 0 |
943 | pf_pkt_addr_changed(m); |
944 | #endif |
945 | |
946 | switch (af) { |
947 | case AF_INET2: |
948 | error = ip_output(m, NULL((void *)0), NULL((void *)0), IP_RAWOUTPUT0x2, |
949 | &sc->sc_imo, NULL((void *)0), 0); |
950 | break; |
951 | #ifdef INET61 |
952 | case AF_INET624: |
953 | error = ip6_output(m, NULL((void *)0), NULL((void *)0), IPV6_MINMTU0x04, NULL((void *)0), NULL((void *)0)); |
954 | break; |
955 | #endif /* INET6 */ |
956 | default: |
957 | m_freem(m); |
958 | error = EAFNOSUPPORT47; |
959 | } |
960 | |
961 | if (error) |
962 | ifp->if_oerrorsif_data.ifi_oerrors++; |
963 | |
964 | return (error); |
965 | } |
966 | |
967 | void |
968 | vxlan_addr_change(void *arg) |
969 | { |
970 | struct vxlan_softc *sc = arg; |
971 | struct ifnet *ifp = &sc->sc_ac.ac_if; |
972 | int error; |
973 | |
974 | /* |
975 | * Reset the configuration after resume or any possible address |
976 | * configuration changes. |
977 | */ |
978 | if ((error = vxlan_config(ifp, NULL((void *)0), NULL((void *)0)))) { |
979 | /* |
980 | * The source address of the tunnel can temporarily disappear, |
981 | * after a link state change when running the DHCP client, |
982 | * so keep it configured. |
983 | */ |
984 | } |
985 | } |
986 | |
987 | void |
988 | vxlan_if_change(void *arg) |
989 | { |
990 | struct vxlan_softc *sc = arg; |
991 | struct ifnet *ifp = &sc->sc_ac.ac_if; |
992 | |
993 | /* |
994 | * Reset the configuration after the parent interface disappeared. |
995 | */ |
996 | vxlan_multicast_cleanup(ifp); |
997 | memset(&sc->sc_src, 0, sizeof(sc->sc_src))__builtin_memset((&sc->sc_src), (0), (sizeof(sc->sc_src ))); |
998 | memset(&sc->sc_dst, 0, sizeof(sc->sc_dst))__builtin_memset((&sc->sc_dst), (0), (sizeof(sc->sc_dst ))); |
999 | sc->sc_dstport = htons(VXLAN_PORT)(__uint16_t)(__builtin_constant_p(4789) ? (__uint16_t)(((__uint16_t )(4789) & 0xffU) << 8 | ((__uint16_t)(4789) & 0xff00U ) >> 8) : __swap16md(4789)); |
1000 | } |
1001 | |
1002 | void |
1003 | vxlan_link_change(void *arg) |
1004 | { |
1005 | struct vxlan_softc *sc = arg; |
1006 | struct ifnet *ifp = &sc->sc_ac.ac_if; |
1007 | |
1008 | /* |
1009 | * The machine might have lost its multicast associations after |
1010 | * link state changes. This fixes a problem with VMware after |
1011 | * suspend/resume of the host or guest. |
1012 | */ |
1013 | (void)vxlan_config(ifp, NULL((void *)0), NULL((void *)0)); |
1014 | } |