diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-06-05 11:35:39 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-06-05 14:16:00 +0200 |
commit | 705e362ea5d6f711e987f5d370467b8873fc2255 (patch) | |
tree | bb2152c95b76783069419dcd1c24014ba0eb3a1b /freebsd/sys/net | |
parent | Add RTEMS-specific getcredhostuuid() (diff) | |
download | rtems-libbsd-705e362ea5d6f711e987f5d370467b8873fc2255.tar.bz2 |
Update to FreeBSD stable/12 2019-06-05
Git mirror commit 78576620f2689e23144a1cf1bf55106cc6abe2b7.
Diffstat (limited to 'freebsd/sys/net')
-rw-r--r-- | freebsd/sys/net/bpf.c | 12 | ||||
-rw-r--r-- | freebsd/sys/net/bridgestp.c | 3 | ||||
-rw-r--r-- | freebsd/sys/net/ethernet.h | 1 | ||||
-rw-r--r-- | freebsd/sys/net/ieee_oui.h | 80 | ||||
-rw-r--r-- | freebsd/sys/net/if.c | 80 | ||||
-rw-r--r-- | freebsd/sys/net/if_bridge.c | 54 | ||||
-rw-r--r-- | freebsd/sys/net/if_ethersubr.c | 38 | ||||
-rw-r--r-- | freebsd/sys/net/if_gre.c | 153 | ||||
-rw-r--r-- | freebsd/sys/net/if_gre.h | 66 | ||||
-rw-r--r-- | freebsd/sys/net/if_lagg.c | 61 | ||||
-rw-r--r-- | freebsd/sys/net/if_stf.c | 1 | ||||
-rw-r--r-- | freebsd/sys/net/if_tap.c | 22 | ||||
-rw-r--r-- | freebsd/sys/net/if_tun.c | 74 | ||||
-rw-r--r-- | freebsd/sys/net/if_var.h | 3 | ||||
-rw-r--r-- | freebsd/sys/net/iflib.h | 4 | ||||
-rw-r--r-- | freebsd/sys/net/pfvar.h | 37 | ||||
-rw-r--r-- | freebsd/sys/net/rtsock.c | 2 |
17 files changed, 557 insertions, 134 deletions
diff --git a/freebsd/sys/net/bpf.c b/freebsd/sys/net/bpf.c index edee632b..33c58c3e 100644 --- a/freebsd/sys/net/bpf.c +++ b/freebsd/sys/net/bpf.c @@ -2695,16 +2695,16 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) { struct bpf_if *bp; - bp = malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); - if (bp == NULL) - panic("bpfattach"); + KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); + + bp = malloc(sizeof(*bp), M_BPF, M_WAITOK | M_ZERO); + rw_init(&bp->bif_lock, "bpf interface lock"); LIST_INIT(&bp->bif_dlist); LIST_INIT(&bp->bif_wlist); bp->bif_ifp = ifp; bp->bif_dlt = dlt; - rw_init(&bp->bif_lock, "bpf interface lock"); - KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); + bp->bif_hdrlen = hdrlen; bp->bif_bpf = driverp; *driverp = bp; @@ -2712,8 +2712,6 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); BPF_UNLOCK(); - bp->bif_hdrlen = hdrlen; - if (bootverbose && IS_DEFAULT_VNET(curvnet)) if_printf(ifp, "bpf attached\n"); } diff --git a/freebsd/sys/net/bridgestp.c b/freebsd/sys/net/bridgestp.c index 49e772b3..b654b04e 100644 --- a/freebsd/sys/net/bridgestp.c +++ b/freebsd/sys/net/bridgestp.c @@ -2275,4 +2275,7 @@ bstp_destroy(struct bstp_port *bp) taskqueue_drain(taskqueue_swi, &bp->bp_statetask); taskqueue_drain(taskqueue_swi, &bp->bp_rtagetask); taskqueue_drain(taskqueue_swi, &bp->bp_mediatask); + + if (bp->bp_bs->bs_root_port == bp) + bstp_assign_roles(bp->bp_bs); } diff --git a/freebsd/sys/net/ethernet.h b/freebsd/sys/net/ethernet.h index fa75c1df..0753e31d 100644 --- a/freebsd/sys/net/ethernet.h +++ b/freebsd/sys/net/ethernet.h @@ -422,6 +422,7 @@ void ether_vlan_mtap(struct bpf_if *, struct mbuf *, struct mbuf *ether_vlanencap(struct mbuf *, uint16_t); bool ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, uint16_t vid, uint8_t pcp); +void ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr); #ifdef _SYS_EVENTHANDLER_H_ /* new ethernet interface attached event */ diff --git a/freebsd/sys/net/ieee_oui.h b/freebsd/sys/net/ieee_oui.h new file mode 100644 index 00000000..f543f561 --- /dev/null +++ b/freebsd/sys/net/ieee_oui.h @@ -0,0 +1,80 @@ +/* - + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + * Author: George V. Neville-Neil + * + */ + +/* Organizationally Unique Identifier assigned by IEEE 14 Nov 2013 */ +#define OUI_FREEBSD_BASE 0x589cfc000000 +#define OUI_FREEBSD(nic) (OUI_FREEBSD_BASE | (nic)) + +/* + * OUIs are most often used to uniquely identify network interfaces + * and occupy the first 3 bytes of both destination and source MAC + * addresses. The following allocations exist so that various + * software systems associated with FreeBSD can have unique IDs in the + * absence of hardware. The use of OUIs for this purpose is not fully + * fleshed out but is now in common use in virtualization technology. + * + * Allocations from this range are expected to be made using COMMON + * SENSE by developers. Do NOT take a large range just because + * they're currently wide open. Take the smallest useful range for + * your system. We have (2^24 - 2) available addresses (see Reserved + * Values below) but that is far from infinite. + * + * In the event of a conflict arbitration of allocation in this file + * is subject to core@ approval. + * + * Applications are differentiated based on the high order bit(s) of + * the remaining three bytes. Our first allocation has all 0s, the + * next allocation has the highest bit set. Allocating in this way + * gives us 254 allocations of 64K addresses. Address blocks can be + * concatenated if necessary. + * + * Reserved Values: 0x000000 and 0xffffff are reserved and MUST NOT BE + * allocated for any reason. + */ + +/* Allocate 20 bits to bhyve */ +#define OUI_FREEBSD_BHYVE_LOW OUI_FREEBSD(0x000001) +#define OUI_FREEBSD_BHYVE_HIGH OUI_FREEBSD(0x0fffff) + +/* + * Allocate 16 bits for a pool to give to various interfaces that need a + * generated address, but don't quite need to slice off a whole section of + * the OUI (e.g. cloned interfaces, one-off NICs of various vendors). + * + * ether_gen_addr should be used to generate an address from this pool. + */ +#define OUI_FREEBSD_GENERATED_MASK 0x10ffff +#define OUI_FREEBSD_GENERATED_LOW OUI_FREEBSD(0x100000) +#define OUI_FREEBSD_GENERATED_HIGH OUI_FREEBSD(OU_FREEBSD_GENERATED_MASK) diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c index 588753f9..5f0329fd 100644 --- a/freebsd/sys/net/if.c +++ b/freebsd/sys/net/if.c @@ -64,6 +64,8 @@ #include <sys/domain.h> #include <sys/jail.h> #include <sys/priv.h> +#include <sys/sched.h> +#include <sys/smp.h> #include <machine/stdarg.h> #include <vm/uma.h> @@ -1763,6 +1765,32 @@ if_data_copy(struct ifnet *ifp, struct if_data *ifd) ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO); } +#ifndef __rtems__ +struct ifnet_read_lock { + struct mtx mtx; /* lock protecting tracker below */ + struct epoch_tracker et; +}; + +DPCPU_DEFINE_STATIC(struct ifnet_read_lock, ifnet_addr_read_lock); +DPCPU_DEFINE_STATIC(struct ifnet_read_lock, ifnet_maddr_read_lock); + +static void +ifnet_read_lock_init(void __unused *arg) +{ + struct ifnet_read_lock *pifrl; + int cpu; + + CPU_FOREACH(cpu) { + pifrl = DPCPU_ID_PTR(cpu, ifnet_addr_read_lock); + mtx_init(&pifrl->mtx, "ifnet_addr_read_lock", NULL, MTX_DEF); + + pifrl = DPCPU_ID_PTR(cpu, ifnet_maddr_read_lock); + mtx_init(&pifrl->mtx, "ifnet_maddr_read_lock", NULL, MTX_DEF); + } +} +SYSINIT(ifnet_read_lock_init, SI_SUB_CPU + 1, SI_ORDER_FIRST, &ifnet_read_lock_init, NULL); +#endif /* __rtems__ */ + /* * Wrapper functions for struct ifnet address list locking macros. These are * used by kernel modules to avoid encoding programming interface or binary @@ -1772,35 +1800,63 @@ if_data_copy(struct ifnet *ifp, struct if_data *ifd) void if_addr_rlock(struct ifnet *ifp) { - MPASS(*(uint64_t *)&ifp->if_addr_et == 0); - epoch_enter_preempt(net_epoch_preempt, &ifp->if_addr_et); +#ifndef __rtems__ + struct ifnet_read_lock *pifrl; + + sched_pin(); + pifrl = DPCPU_PTR(ifnet_addr_read_lock); + mtx_lock(&pifrl->mtx); + epoch_enter_preempt(net_epoch_preempt, &pifrl->et); +#else /* __rtems__ */ + epoch_enter_preempt(net_epoch_preempt, curthread->td_et); +#endif /* __rtems__ */ } void if_addr_runlock(struct ifnet *ifp) { - epoch_exit_preempt(net_epoch_preempt, &ifp->if_addr_et); -#ifdef INVARIANTS - bzero(&ifp->if_addr_et, sizeof(struct epoch_tracker)); -#endif +#ifndef __rtems__ + struct ifnet_read_lock *pifrl; + + pifrl = DPCPU_PTR(ifnet_addr_read_lock); + + epoch_exit_preempt(net_epoch_preempt, &pifrl->et); + mtx_unlock(&pifrl->mtx); + sched_unpin(); +#else /* __rtems__ */ + epoch_exit_preempt(net_epoch_preempt, curthread->td_et); +#endif /* __rtems__ */ } void if_maddr_rlock(if_t ifp) { +#ifndef __rtems__ + struct ifnet_read_lock *pifrl; - MPASS(*(uint64_t *)&ifp->if_maddr_et == 0); - epoch_enter_preempt(net_epoch_preempt, &ifp->if_maddr_et); + sched_pin(); + pifrl = DPCPU_PTR(ifnet_maddr_read_lock); + mtx_lock(&pifrl->mtx); + epoch_enter_preempt(net_epoch_preempt, &pifrl->et); +#else /* __rtems__ */ + epoch_enter_preempt(net_epoch_preempt, curthread->td_et); +#endif /* __rtems__ */ } void if_maddr_runlock(if_t ifp) { +#ifndef __rtems__ + struct ifnet_read_lock *pifrl; - epoch_exit_preempt(net_epoch_preempt, &ifp->if_maddr_et); -#ifdef INVARIANTS - bzero(&ifp->if_maddr_et, sizeof(struct epoch_tracker)); -#endif + pifrl = DPCPU_PTR(ifnet_maddr_read_lock); + + epoch_exit_preempt(net_epoch_preempt, &pifrl->et); + mtx_unlock(&pifrl->mtx); + sched_unpin(); +#else /* __rtems__ */ + epoch_exit_preempt(net_epoch_preempt, curthread->td_et); +#endif /* __rtems__ */ } /* diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c index b5e231b8..4bfb67a8 100644 --- a/freebsd/sys/net/if_bridge.c +++ b/freebsd/sys/net/if_bridge.c @@ -228,7 +228,7 @@ struct bridge_softc { struct bstp_state sc_stp; /* STP state */ uint32_t sc_brtexceeded; /* # of cache drops */ struct ifnet *sc_ifaddr; /* member mac copied from */ - u_char sc_defaddr[6]; /* Default MAC address */ + struct ether_addr sc_defaddr; /* Default MAC address */ }; VNET_DEFINE_STATIC(struct mtx, bridge_list_mtx); @@ -237,7 +237,8 @@ static eventhandler_tag bridge_detach_cookie; int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; -uma_zone_t bridge_rtnode_zone; +VNET_DEFINE_STATIC(uma_zone_t, bridge_rtnode_zone); +#define V_bridge_rtnode_zone VNET(bridge_rtnode_zone) static int bridge_clone_create(struct if_clone *, int, caddr_t); static void bridge_clone_destroy(struct ifnet *); @@ -529,6 +530,9 @@ static void vnet_bridge_init(const void *unused __unused) { + V_bridge_rtnode_zone = uma_zcreate("bridge_rtnode", + sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, 0); BRIDGE_LIST_LOCK_INIT(); LIST_INIT(&V_bridge_list); V_bridge_cloner = if_clone_simple(bridge_name, @@ -544,6 +548,7 @@ vnet_bridge_uninit(const void *unused __unused) if_clone_detach(V_bridge_cloner); V_bridge_cloner = NULL; BRIDGE_LIST_LOCK_DESTROY(); + uma_zdestroy(V_bridge_rtnode_zone); } VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_bridge_uninit, NULL); @@ -554,9 +559,6 @@ bridge_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: - bridge_rtnode_zone = uma_zcreate("bridge_rtnode", - sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, - UMA_ALIGN_PTR, 0); bridge_dn_p = bridge_dummynet; bridge_detach_cookie = EVENTHANDLER_REGISTER( ifnet_departure_event, bridge_ifdetach, NULL, @@ -565,7 +567,6 @@ bridge_modevent(module_t mod, int type, void *data) case MOD_UNLOAD: EVENTHANDLER_DEREGISTER(ifnet_departure_event, bridge_detach_cookie); - uma_zdestroy(bridge_rtnode_zone); bridge_dn_p = NULL; break; default: @@ -672,16 +673,14 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) getcredhostid(curthread->td_ucred, &hostid); do { if (fb || hostid == 0) { - arc4rand(sc->sc_defaddr, ETHER_ADDR_LEN, 1); - sc->sc_defaddr[0] &= ~1;/* clear multicast bit */ - sc->sc_defaddr[0] |= 2; /* set the LAA bit */ + ether_gen_addr(ifp, &sc->sc_defaddr); } else { - sc->sc_defaddr[0] = 0x2; - sc->sc_defaddr[1] = (hostid >> 24) & 0xff; - sc->sc_defaddr[2] = (hostid >> 16) & 0xff; - sc->sc_defaddr[3] = (hostid >> 8 ) & 0xff; - sc->sc_defaddr[4] = hostid & 0xff; - sc->sc_defaddr[5] = ifp->if_dunit & 0xff; + sc->sc_defaddr.octet[0] = 0x2; + sc->sc_defaddr.octet[1] = (hostid >> 24) & 0xff; + sc->sc_defaddr.octet[2] = (hostid >> 16) & 0xff; + sc->sc_defaddr.octet[3] = (hostid >> 8 ) & 0xff; + sc->sc_defaddr.octet[4] = hostid & 0xff; + sc->sc_defaddr.octet[5] = ifp->if_dunit & 0xff; } fb = 1; @@ -689,7 +688,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) BRIDGE_LIST_LOCK(); LIST_FOREACH(sc2, &V_bridge_list, sc_list) { bifp = sc2->sc_ifp; - if (memcmp(sc->sc_defaddr, + if (memcmp(sc->sc_defaddr.octet, IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) { retry = 1; break; @@ -699,7 +698,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) } while (retry == 1); bstp_attach(&sc->sc_stp, &bridge_ops); - ether_ifattach(ifp, sc->sc_defaddr); + ether_ifattach(ifp, sc->sc_defaddr.octet); /* Now undo some of the damage... */ ifp->if_baudrate = 0; ifp->if_type = IFT_BRIDGE; @@ -734,6 +733,9 @@ bridge_clone_destroy(struct ifnet *ifp) bridge_delete_span(sc, bif); } + /* Tear down the routing table. */ + bridge_rtable_fini(sc); + BRIDGE_UNLOCK(sc); callout_drain(&sc->sc_brcallout); @@ -746,9 +748,6 @@ bridge_clone_destroy(struct ifnet *ifp) ether_ifdetach(ifp); if_free(ifp); - /* Tear down the routing table. */ - bridge_rtable_fini(sc); - BRIDGE_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } @@ -1020,7 +1019,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, */ if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) { if (LIST_EMPTY(&sc->sc_iflist)) { - bcopy(sc->sc_defaddr, + bcopy(&sc->sc_defaddr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); sc->sc_ifaddr = NULL; } else { @@ -1191,7 +1190,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) * the default randomly generated one. */ if (V_bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) && - !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) { + !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr.octet, ETHER_ADDR_LEN)) { bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); sc->sc_ifaddr = ifs; EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); @@ -2673,7 +2672,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, * initialize the expiration time and Ethernet * address. */ - brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO); + brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO); if (brt == NULL) return (ENOMEM); @@ -2686,7 +2685,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, brt->brt_vlan = vlan; if ((error = bridge_rtnode_insert(sc, brt)) != 0) { - uma_zfree(bridge_rtnode_zone, brt); + uma_zfree(V_bridge_rtnode_zone, brt); return (error); } brt->brt_dst = bif; @@ -2770,11 +2769,14 @@ bridge_timer(void *arg) BRIDGE_LOCK_ASSERT(sc); + /* Destruction of rtnodes requires a proper vnet context */ + CURVNET_SET(sc->sc_ifp->if_vnet); bridge_rtage(sc); if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, bridge_timer, sc); + CURVNET_RESTORE(); } /* @@ -3032,7 +3034,7 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) LIST_REMOVE(brt, brt_list); sc->sc_brtcnt--; brt->brt_dst->bif_addrcnt--; - uma_zfree(bridge_rtnode_zone, brt); + uma_zfree(V_bridge_rtnode_zone, brt); } /* @@ -3046,6 +3048,7 @@ bridge_rtable_expire(struct ifnet *ifp, int age) struct bridge_softc *sc = ifp->if_bridge; struct bridge_rtnode *brt; + CURVNET_SET(ifp->if_vnet); BRIDGE_LOCK(sc); /* @@ -3064,6 +3067,7 @@ bridge_rtable_expire(struct ifnet *ifp, int age) } } BRIDGE_UNLOCK(sc); + CURVNET_RESTORE(); } /* diff --git a/freebsd/sys/net/if_ethersubr.c b/freebsd/sys/net/if_ethersubr.c index 01e757e5..70b26160 100644 --- a/freebsd/sys/net/if_ethersubr.c +++ b/freebsd/sys/net/if_ethersubr.c @@ -44,11 +44,13 @@ #include <sys/systm.h> #include <sys/bus.h> #include <sys/eventhandler.h> +#include <sys/jail.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/module.h> #include <sys/mbuf.h> +#include <sys/proc.h> #include <sys/priv.h> #include <sys/random.h> #include <sys/socket.h> @@ -56,6 +58,7 @@ #include <sys/sysctl.h> #include <sys/uuid.h> +#include <net/ieee_oui.h> #include <net/if.h> #include <net/if_var.h> #include <net/if_arp.h> @@ -87,6 +90,8 @@ #endif #include <security/mac/mac_framework.h> +#include <crypto/sha1.h> + #ifdef CTASSERT CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2); CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN); @@ -1370,5 +1375,38 @@ ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, return (true); } +/* + * Allocate an address from the FreeBSD Foundation OUI. This uses a + * cryptographic hash function on the containing jail's UUID and the interface + * name to attempt to provide a unique but stable address. Pseudo-interfaces + * which require a MAC address should use this function to allocate + * non-locally-administered addresses. + */ +void +ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr) +{ +#define ETHER_GEN_ADDR_BUFSIZ HOSTUUIDLEN + IFNAMSIZ + 2 + SHA1_CTX ctx; + char buf[ETHER_GEN_ADDR_BUFSIZ]; + char uuid[HOSTUUIDLEN + 1]; + uint64_t addr; + int i, sz; + char digest[SHA1_RESULTLEN]; + + getcredhostuuid(curthread->td_ucred, uuid, sizeof(uuid)); + sz = snprintf(buf, ETHER_GEN_ADDR_BUFSIZ, "%s-%s", uuid, ifp->if_xname); + SHA1Init(&ctx); + SHA1Update(&ctx, buf, sz); + SHA1Final(digest, &ctx); + + addr = ((digest[0] << 16) | (digest[1] << 8) | digest[2]) & + OUI_FREEBSD_GENERATED_MASK; + addr = OUI_FREEBSD(addr); + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + hwaddr->octet[i] = addr >> ((ETHER_ADDR_LEN - i - 1) * 8) & + 0xFF; + } +} + DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); MODULE_VERSION(ether, 1); diff --git a/freebsd/sys/net/if_gre.c b/freebsd/sys/net/if_gre.c index 4fbc105e..5aeb8266 100644 --- a/freebsd/sys/net/if_gre.c +++ b/freebsd/sys/net/if_gre.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> +#include <rtems/bsd/local/opt_rss.h> #include <sys/param.h> #include <sys/kernel.h> @@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <sys/priv.h> #include <sys/proc.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <sys/sockio.h> #include <sys/sx.h> #include <sys/sysctl.h> @@ -67,19 +69,27 @@ __FBSDID("$FreeBSD$"); #include <net/route.h> #include <netinet/in.h> +#include <netinet/in_pcb.h> #ifdef INET #include <netinet/in_var.h> #include <netinet/ip.h> #include <netinet/ip_var.h> +#ifdef RSS +#include <netinet/in_rss.h> +#endif #endif #ifdef INET6 #include <netinet/ip6.h> #include <netinet6/in6_var.h> #include <netinet6/ip6_var.h> +#ifdef RSS +#include <netinet6/in6_rss.h> +#endif #endif #include <netinet/ip_encap.h> +#include <netinet/udp.h> #include <net/bpf.h> #include <net/if_gre.h> @@ -153,6 +163,7 @@ vnet_gre_uninit(const void *unused __unused) #ifdef INET6 in6_gre_uninit(); #endif + /* XXX: epoch_call drain */ } VNET_SYSUNINIT(vnet_gre_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, vnet_gre_uninit, NULL); @@ -272,6 +283,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case GRESKEY: case GRESOPTS: + case GRESPORT: if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) break; if ((error = copyin(ifr_data_get_ptr(ifr), &opt, @@ -287,23 +299,45 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } if (sc->gre_options == opt) break; + } else if (cmd == GRESPORT) { + if (opt != 0 && (opt < V_ipport_hifirstauto || + opt > V_ipport_hilastauto)) { + error = EINVAL; + break; + } + if (sc->gre_port == opt) + break; + if ((sc->gre_options & GRE_UDPENCAP) == 0) { + /* + * UDP encapsulation is not enabled, thus + * there is no need to reattach softc. + */ + sc->gre_port = opt; + break; + } } switch (sc->gre_family) { #ifdef INET case AF_INET: - in_gre_setopts(sc, cmd, opt); + error = in_gre_setopts(sc, cmd, opt); break; #endif #ifdef INET6 case AF_INET6: - in6_gre_setopts(sc, cmd, opt); + error = in6_gre_setopts(sc, cmd, opt); break; #endif default: + /* + * Tunnel is not yet configured. + * We can just change any parameters. + */ if (cmd == GRESKEY) sc->gre_key = opt; - else + if (cmd == GRESOPTS) sc->gre_options = opt; + if (cmd == GRESPORT) + sc->gre_port = opt; break; } /* @@ -319,6 +353,10 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = copyout(&sc->gre_options, ifr_data_get_ptr(ifr), sizeof(sc->gre_options)); break; + case GREGPORT: + error = copyout(&sc->gre_port, ifr_data_get_ptr(ifr), + sizeof(sc->gre_port)); + break; default: error = EINVAL; break; @@ -343,6 +381,7 @@ end: static void gre_delete_tunnel(struct gre_softc *sc) { + struct gre_socket *gs; sx_assert(&gre_ioctl_sx, SA_XLOCKED); if (sc->gre_family != 0) { @@ -352,6 +391,16 @@ gre_delete_tunnel(struct gre_softc *sc) free(sc->gre_hdr, M_GRE); sc->gre_family = 0; } + /* + * If this Tunnel was the last one that could use UDP socket, + * we should unlink socket from hash table and close it. + */ + if ((gs = sc->gre_so) != NULL && CK_LIST_EMPTY(&gs->list)) { + CK_LIST_REMOVE(gs, chain); + soclose(gs->so); + epoch_call(net_epoch_preempt, &gs->epoch_ctx, gre_sofree); + sc->gre_so = NULL; + } GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; if_link_state_change(GRE2IFP(sc), LINK_STATE_DOWN); } @@ -378,7 +427,38 @@ gre_hashdestroy(struct gre_list *hash) } void -gre_updatehdr(struct gre_softc *sc, struct grehdr *gh) +gre_sofree(epoch_context_t ctx) +{ + struct gre_socket *gs; + + gs = __containerof(ctx, struct gre_socket, epoch_ctx); + free(gs, M_GRE); +} + +static __inline uint16_t +gre_cksum_add(uint16_t sum, uint16_t a) +{ + uint16_t res; + + res = sum + a; + return (res + (res < a)); +} + +void +gre_update_udphdr(struct gre_softc *sc, struct udphdr *udp, uint16_t csum) +{ + + sx_assert(&gre_ioctl_sx, SA_XLOCKED); + MPASS(sc->gre_options & GRE_UDPENCAP); + + udp->uh_dport = htons(GRE_UDPPORT); + udp->uh_sport = htons(sc->gre_port); + udp->uh_sum = csum; + udp->uh_ulen = 0; +} + +void +gre_update_hdr(struct gre_softc *sc, struct grehdr *gh) { uint32_t *opts; uint16_t flags; @@ -545,6 +625,52 @@ gre_setseqn(struct grehdr *gh, uint32_t seq) *opts = htonl(seq); } +static uint32_t +gre_flowid(struct gre_softc *sc, struct mbuf *m, uint32_t af) +{ + uint32_t flowid; + + if ((sc->gre_options & GRE_UDPENCAP) == 0 || sc->gre_port != 0) + return (0); +#ifndef RSS + switch (af) { +#ifdef INET + case AF_INET: + flowid = mtod(m, struct ip *)->ip_src.s_addr ^ + mtod(m, struct ip *)->ip_dst.s_addr; + break; +#endif +#ifdef INET6 + case AF_INET6: + flowid = mtod(m, struct ip6_hdr *)->ip6_src.s6_addr32[3] ^ + mtod(m, struct ip6_hdr *)->ip6_dst.s6_addr32[3]; + break; +#endif + default: + flowid = 0; + } +#else /* RSS */ + switch (af) { +#ifdef INET + case AF_INET: + flowid = rss_hash_ip4_2tuple(mtod(m, struct ip *)->ip_src, + mtod(m, struct ip *)->ip_dst); + break; +#endif +#ifdef INET6 + case AF_INET6: + flowid = rss_hash_ip6_2tuple( + &mtod(m, struct ip6_hdr *)->ip6_src, + &mtod(m, struct ip6_hdr *)->ip6_dst); + break; +#endif + default: + flowid = 0; + } +#endif + return (flowid); +} + #define MTAG_GRE 1307983903 static int gre_transmit(struct ifnet *ifp, struct mbuf *m) @@ -552,7 +678,8 @@ gre_transmit(struct ifnet *ifp, struct mbuf *m) GRE_RLOCK_TRACKER; struct gre_softc *sc; struct grehdr *gh; - uint32_t af; + struct udphdr *uh; + uint32_t af, flowid; int error, len; uint16_t proto; @@ -579,6 +706,7 @@ gre_transmit(struct ifnet *ifp, struct mbuf *m) af = m->m_pkthdr.csum_data; BPF_MTAP2(ifp, &af, sizeof(af), m); m->m_flags &= ~(M_BCAST|M_MCAST); + flowid = gre_flowid(sc, m, af); M_SETFIB(m, sc->gre_fibnum); M_PREPEND(m, sc->gre_hlen, M_NOWAIT); if (m == NULL) { @@ -620,6 +748,19 @@ gre_transmit(struct ifnet *ifp, struct mbuf *m) error = ENETDOWN; goto drop; } + if (sc->gre_options & GRE_UDPENCAP) { + uh = (struct udphdr *)mtodo(m, len); + uh->uh_sport |= htons(V_ipport_hifirstauto) | + (flowid >> 16) | (flowid & 0xFFFF); + uh->uh_sport = htons(ntohs(uh->uh_sport) % + V_ipport_hilastauto); + uh->uh_ulen = htons(m->m_pkthdr.len - len); + uh->uh_sum = gre_cksum_add(uh->uh_sum, + htons(m->m_pkthdr.len - len + IPPROTO_UDP)); + m->m_pkthdr.csum_flags = sc->gre_csumflags; + m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); + len += sizeof(struct udphdr); + } gh = (struct grehdr *)mtodo(m, len); gh->gre_proto = proto; if (sc->gre_options & GRE_ENABLE_SEQ) @@ -637,7 +778,7 @@ gre_transmit(struct ifnet *ifp, struct mbuf *m) #endif #ifdef INET6 case AF_INET6: - error = in6_gre_output(m, af, sc->gre_hlen); + error = in6_gre_output(m, af, sc->gre_hlen, flowid); break; #endif default: diff --git a/freebsd/sys/net/if_gre.h b/freebsd/sys/net/if_gre.h index 4b93321a..de3c5979 100644 --- a/freebsd/sys/net/if_gre.h +++ b/freebsd/sys/net/if_gre.h @@ -53,14 +53,35 @@ struct greip { struct ip gi_ip; struct grehdr gi_gre; } __packed; -#endif + +struct greudp { + struct ip gi_ip; + struct udphdr gi_udp; + struct grehdr gi_gre; +} __packed; +#endif /* INET */ #ifdef INET6 struct greip6 { struct ip6_hdr gi6_ip6; struct grehdr gi6_gre; } __packed; -#endif + +struct greudp6 { + struct ip6_hdr gi6_ip6; + struct udphdr gi6_udp; + struct grehdr gi6_gre; +} __packed; +#endif /* INET6 */ + +CK_LIST_HEAD(gre_list, gre_softc); +CK_LIST_HEAD(gre_sockets, gre_socket); +struct gre_socket { + struct socket *so; + struct gre_list list; + CK_LIST_ENTRY(gre_socket) chain; + struct epoch_context epoch_ctx; +}; struct gre_softc { struct ifnet *gre_ifp; @@ -69,22 +90,26 @@ struct gre_softc { uint32_t gre_oseq; uint32_t gre_key; uint32_t gre_options; + uint32_t gre_csumflags; + uint32_t gre_port; u_int gre_fibnum; u_int gre_hlen; /* header size */ union { void *hdr; #ifdef INET - struct greip *gihdr; + struct greip *iphdr; + struct greudp *udphdr; #endif #ifdef INET6 - struct greip6 *gi6hdr; + struct greip6 *ip6hdr; + struct greudp6 *udp6hdr; #endif } gre_uhdr; + struct gre_socket *gre_so; CK_LIST_ENTRY(gre_softc) chain; CK_LIST_ENTRY(gre_softc) srchash; }; -CK_LIST_HEAD(gre_list, gre_softc); MALLOC_DECLARE(M_GRE); #ifndef GRE_HASH_SIZE @@ -98,28 +123,35 @@ MALLOC_DECLARE(M_GRE); #define GRE_WAIT() epoch_wait_preempt(net_epoch_preempt) #define gre_hdr gre_uhdr.hdr -#define gre_gihdr gre_uhdr.gihdr -#define gre_gi6hdr gre_uhdr.gi6hdr -#define gre_oip gre_gihdr->gi_ip -#define gre_oip6 gre_gi6hdr->gi6_ip6 +#define gre_iphdr gre_uhdr.iphdr +#define gre_ip6hdr gre_uhdr.ip6hdr +#define gre_udphdr gre_uhdr.udphdr +#define gre_udp6hdr gre_uhdr.udp6hdr + +#define gre_oip gre_iphdr->gi_ip +#define gre_udp gre_udphdr->gi_udp +#define gre_oip6 gre_ip6hdr->gi6_ip6 +#define gre_udp6 gre_udp6hdr->gi6_udp struct gre_list *gre_hashinit(void); void gre_hashdestroy(struct gre_list *); int gre_input(struct mbuf *, int, int, void *); -void gre_updatehdr(struct gre_softc *, struct grehdr *); +void gre_update_hdr(struct gre_softc *, struct grehdr *); +void gre_update_udphdr(struct gre_softc *, struct udphdr *, uint16_t); +void gre_sofree(epoch_context_t); void in_gre_init(void); void in_gre_uninit(void); -void in_gre_setopts(struct gre_softc *, u_long, uint32_t); +int in_gre_setopts(struct gre_softc *, u_long, uint32_t); int in_gre_ioctl(struct gre_softc *, u_long, caddr_t); int in_gre_output(struct mbuf *, int, int); void in6_gre_init(void); void in6_gre_uninit(void); -void in6_gre_setopts(struct gre_softc *, u_long, uint32_t); +int in6_gre_setopts(struct gre_softc *, u_long, uint32_t); int in6_gre_ioctl(struct gre_softc *, u_long, caddr_t); -int in6_gre_output(struct mbuf *, int, int); +int in6_gre_output(struct mbuf *, int, int, uint32_t); /* * CISCO uses special type for GRE tunnel created as part of WCCP * connection, while in fact those packets are just IPv4 encapsulated @@ -139,9 +171,15 @@ int in6_gre_output(struct mbuf *, int, int); #define GRESKEY _IOW('i', 108, struct ifreq) #define GREGOPTS _IOWR('i', 109, struct ifreq) #define GRESOPTS _IOW('i', 110, struct ifreq) +#define GREGPORT _IOWR('i', 111, struct ifreq) +#define GRESPORT _IOW('i', 112, struct ifreq) + +/* GRE-in-UDP encapsulation destination port as defined in RFC8086 */ +#define GRE_UDPPORT 4754 #define GRE_ENABLE_CSUM 0x0001 #define GRE_ENABLE_SEQ 0x0002 -#define GRE_OPTMASK (GRE_ENABLE_CSUM|GRE_ENABLE_SEQ) +#define GRE_UDPENCAP 0x0004 +#define GRE_OPTMASK (GRE_ENABLE_CSUM|GRE_ENABLE_SEQ|GRE_UDPENCAP) #endif /* _NET_IF_GRE_H_ */ diff --git a/freebsd/sys/net/if_lagg.c b/freebsd/sys/net/if_lagg.c index c9c1e8f9..af6f1667 100644 --- a/freebsd/sys/net/if_lagg.c +++ b/freebsd/sys/net/if_lagg.c @@ -113,6 +113,7 @@ static void lagg_clone_destroy(struct ifnet *); VNET_DEFINE_STATIC(struct if_clone *, lagg_cloner); #define V_lagg_cloner VNET(lagg_cloner) static const char laggname[] = "lagg"; +static MALLOC_DEFINE(M_LAGG, laggname, "802.3AD Link Aggregation Interface"); static void lagg_capabilities(struct lagg_softc *); static int lagg_port_create(struct lagg_softc *, struct ifnet *); @@ -480,10 +481,10 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) struct ifnet *ifp; static const u_char eaddr[6]; /* 00:00:00:00:00:00 */ - sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); + sc = malloc(sizeof(*sc), M_LAGG, M_WAITOK|M_ZERO); ifp = sc->sc_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { - free(sc, M_DEVBUF); + free(sc, M_LAGG); return (ENOSPC); } LAGG_SX_INIT(sc); @@ -570,7 +571,7 @@ lagg_clone_destroy(struct ifnet *ifp) LAGG_LIST_UNLOCK(); LAGG_SX_DESTROY(sc); - free(sc, M_DEVBUF); + free(sc, M_LAGG); } static void @@ -684,7 +685,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) ifr.ifr_mtu = oldmtu; } - lp = malloc(sizeof(struct lagg_port), M_DEVBUF, M_WAITOK|M_ZERO); + lp = malloc(sizeof(struct lagg_port), M_LAGG, M_WAITOK|M_ZERO); lp->lp_softc = sc; /* Check if port is a stacked lagg */ @@ -692,7 +693,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) SLIST_FOREACH(sc_ptr, &V_lagg_list, sc_entries) { if (ifp == sc_ptr->sc_ifp) { LAGG_LIST_UNLOCK(); - free(lp, M_DEVBUF); + free(lp, M_LAGG); if (oldmtu != -1) (*ifp->if_ioctl)(ifp, SIOCSIFMTU, (caddr_t)&ifr); @@ -703,7 +704,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) if (lagg_port_checkstacking(sc_ptr) >= LAGG_MAX_STACKING) { LAGG_LIST_UNLOCK(); - free(lp, M_DEVBUF); + free(lp, M_LAGG); if (oldmtu != -1) (*ifp->if_ioctl)(ifp, SIOCSIFMTU, (caddr_t)&ifr); @@ -751,7 +752,6 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) * is predictable and `ifconfig laggN create ...` command * will lead to the same result each time. */ - LAGG_RLOCK(); CK_SLIST_FOREACH(tlp, &sc->sc_ports, lp_entries) { if (tlp->lp_ifp->if_index < ifp->if_index && ( CK_SLIST_NEXT(tlp, lp_entries) == NULL || @@ -759,7 +759,6 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) ifp->if_index)) break; } - LAGG_RUNLOCK(); if (tlp != NULL) CK_SLIST_INSERT_AFTER(tlp, lp, lp_entries); else @@ -814,7 +813,7 @@ lagg_port_destroy_cb(epoch_context_t ec) ifp = lp->lp_ifp; if_rele(ifp); - free(lp, M_DEVBUF); + free(lp, M_LAGG); } static int @@ -1537,14 +1536,17 @@ lagg_snd_tag_alloc(struct ifnet *ifp, struct lagg_lb *lb; uint32_t p; + LAGG_RLOCK(); switch (sc->sc_proto) { case LAGG_PROTO_FAILOVER: lp = lagg_link_active(sc, sc->sc_primary); break; case LAGG_PROTO_LOADBALANCE: if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) == 0 || - params->hdr.flowtype == M_HASHTYPE_NONE) + params->hdr.flowtype == M_HASHTYPE_NONE) { + LAGG_RUNLOCK(); return (EOPNOTSUPP); + } p = params->hdr.flowid >> sc->flowid_shift; p %= sc->sc_count; lb = (struct lagg_lb *)sc->sc_psc; @@ -1553,16 +1555,22 @@ lagg_snd_tag_alloc(struct ifnet *ifp, break; case LAGG_PROTO_LACP: if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) == 0 || - params->hdr.flowtype == M_HASHTYPE_NONE) + params->hdr.flowtype == M_HASHTYPE_NONE) { + LAGG_RUNLOCK(); return (EOPNOTSUPP); + } lp = lacp_select_tx_port_by_hash(sc, params->hdr.flowid); break; default: + LAGG_RUNLOCK(); return (EOPNOTSUPP); } - if (lp == NULL) + if (lp == NULL) { + LAGG_RUNLOCK(); return (EOPNOTSUPP); + } ifp = lp->lp_ifp; + LAGG_RUNLOCK(); if (ifp == NULL || ifp->if_snd_tag_alloc == NULL || (ifp->if_capenable & IFCAP_TXRTLMT) == 0) return (EOPNOTSUPP); @@ -1586,7 +1594,7 @@ lagg_setmulti(struct lagg_port *lp) CK_STAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); + mc = malloc(sizeof(struct lagg_mc), M_LAGG, M_NOWAIT); if (mc == NULL) { IF_ADDR_WUNLOCK(scifp); return (ENOMEM); @@ -1617,7 +1625,7 @@ lagg_clrmulti(struct lagg_port *lp) SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); if (mc->mc_ifma && lp->lp_detaching == 0) if_delmulti_ifma(mc->mc_ifma); - free(mc, M_DEVBUF); + free(mc, M_LAGG); } return (0); } @@ -1846,12 +1854,20 @@ struct lagg_port * lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp) { struct lagg_port *lp_next, *rval = NULL; - struct epoch_tracker net_et; /* * Search a port which reports an active link state. */ +#ifdef INVARIANTS + /* + * This is called with either LAGG_RLOCK() held or + * LAGG_XLOCK(sc) held. + */ + if (!in_epoch(net_epoch_preempt)) + LAGG_XLOCK_ASSERT(sc); +#endif + if (lp == NULL) goto search; if (LAGG_PORTACTIVE(lp)) { @@ -1864,15 +1880,12 @@ lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp) goto found; } - search: - epoch_enter_preempt(net_epoch_preempt, &net_et); +search: CK_SLIST_FOREACH(lp_next, &sc->sc_ports, lp_entries) { if (LAGG_PORTACTIVE(lp_next)) { - epoch_exit_preempt(net_epoch_preempt, &net_et); return (lp_next); } } - epoch_exit_preempt(net_epoch_preempt, &net_et); found: return (rval); } @@ -1954,7 +1967,7 @@ lagg_bcast_start(struct lagg_softc *sc, struct mbuf *m) struct lagg_port *lp, *last = NULL; struct mbuf *m0; - LAGG_RLOCK(); + LAGG_RLOCK_ASSERT(); CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (!LAGG_PORTACTIVE(lp)) continue; @@ -1975,7 +1988,6 @@ lagg_bcast_start(struct lagg_softc *sc, struct mbuf *m) } last = lp; } - LAGG_RUNLOCK(); if (last == NULL) { m_freem(m); @@ -2061,7 +2073,7 @@ lagg_lb_attach(struct lagg_softc *sc) struct lagg_lb *lb; LAGG_XLOCK_ASSERT(sc); - lb = malloc(sizeof(struct lagg_lb), M_DEVBUF, M_WAITOK | M_ZERO); + lb = malloc(sizeof(struct lagg_lb), M_LAGG, M_WAITOK | M_ZERO); lb->lb_key = m_ether_tcpip_hash_init(); sc->sc_psc = lb; @@ -2076,7 +2088,7 @@ lagg_lb_detach(struct lagg_softc *sc) lb = (struct lagg_lb *)sc->sc_psc; if (lb != NULL) - free(lb, M_DEVBUF); + free(lb, M_LAGG); } static int @@ -2088,7 +2100,7 @@ lagg_lb_porttable(struct lagg_softc *sc, struct lagg_port *lp) rv = 0; bzero(&lb->lb_ports, sizeof(lb->lb_ports)); - LAGG_RLOCK(); + LAGG_XLOCK_ASSERT(sc); CK_SLIST_FOREACH(lp_next, &sc->sc_ports, lp_entries) { if (lp_next == lp) continue; @@ -2101,7 +2113,6 @@ lagg_lb_porttable(struct lagg_softc *sc, struct lagg_port *lp) sc->sc_ifname, lp_next->lp_ifp->if_xname, i); lb->lb_ports[i++] = lp_next; } - LAGG_RUNLOCK(); return (rv); } diff --git a/freebsd/sys/net/if_stf.c b/freebsd/sys/net/if_stf.c index 3ba9f8c0..7185fb8d 100644 --- a/freebsd/sys/net/if_stf.c +++ b/freebsd/sys/net/if_stf.c @@ -730,6 +730,7 @@ stf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } ifp->if_flags |= IFF_UP; + ifp->if_drv_flags |= IFF_DRV_RUNNING; break; case SIOCADDMULTI: diff --git a/freebsd/sys/net/if_tap.c b/freebsd/sys/net/if_tap.c index a540a59a..4ca35b66 100644 --- a/freebsd/sys/net/if_tap.c +++ b/freebsd/sys/net/if_tap.c @@ -43,6 +43,7 @@ #include <sys/param.h> #include <sys/conf.h> +#include <sys/lock.h> #include <sys/fcntl.h> #include <sys/filio.h> #include <sys/jail.h> @@ -57,6 +58,7 @@ #include <sys/signalvar.h> #include <sys/socket.h> #include <sys/sockio.h> +#include <sys/sx.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/ttycom.h> @@ -165,6 +167,9 @@ MALLOC_DECLARE(M_TAP); MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); +static struct sx tap_ioctl_sx; +SX_SYSINIT(tap_ioctl_sx, &tap_ioctl_sx, "tap_ioctl"); + SYSCTL_DECL(_net_link); static SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0, "Ethernet tunnel software network interface"); @@ -177,6 +182,7 @@ SYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RWTUN, &tapdclone, 0, SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); DEV_MODULE(if_tap, tapmodevent, NULL); +MODULE_VERSION(if_tap, 1); static int tap_clone_create(struct if_clone *ifc, int unit, caddr_t params) @@ -219,11 +225,17 @@ tap_destroy(struct tap_softc *tp) struct ifnet *ifp = tp->tap_ifp; CURVNET_SET(ifp->if_vnet); + destroy_dev(tp->tap_dev); seldrain(&tp->tap_rsel); knlist_clear(&tp->tap_rsel.si_note, 0); knlist_destroy(&tp->tap_rsel.si_note); ether_ifdetach(ifp); + + sx_xlock(&tap_ioctl_sx); + ifp->if_softc = NULL; + sx_xunlock(&tap_ioctl_sx); + if_free(ifp); mtx_destroy(&tp->tap_mtx); @@ -606,12 +618,18 @@ tapifinit(void *xtp) static int tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct tap_softc *tp = ifp->if_softc; + struct tap_softc *tp; struct ifreq *ifr = (struct ifreq *)data; struct ifstat *ifs = NULL; struct ifmediareq *ifmr = NULL; int dummy, error = 0; + sx_xlock(&tap_ioctl_sx); + tp = ifp->if_softc; + if (tp == NULL) { + error = ENXIO; + goto bad; + } switch (cmd) { case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ case SIOCADDMULTI: @@ -654,6 +672,8 @@ tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } +bad: + sx_xunlock(&tap_ioctl_sx); return (error); } /* tapifioctl */ diff --git a/freebsd/sys/net/if_tun.c b/freebsd/sys/net/if_tun.c index ee5c78b0..9c11cbc2 100644 --- a/freebsd/sys/net/if_tun.c +++ b/freebsd/sys/net/if_tun.c @@ -22,6 +22,7 @@ #include <rtems/bsd/local/opt_inet6.h> #include <sys/param.h> +#include <sys/lock.h> #include <sys/priv.h> #include <sys/proc.h> #include <sys/systm.h> @@ -32,6 +33,7 @@ #include <sys/fcntl.h> #include <sys/filio.h> #include <sys/sockio.h> +#include <sys/sx.h> #include <sys/ttycom.h> #include <sys/poll.h> #include <sys/selinfo.h> @@ -81,17 +83,13 @@ struct tun_softc { #define TUN_RWAIT 0x0040 #define TUN_ASYNC 0x0080 #define TUN_IFHEAD 0x0100 +#define TUN_DYING 0x0200 #define TUN_READY (TUN_OPEN | TUN_INITED) - /* - * XXXRW: tun_pid is used to exclusively lock /dev/tun. Is this - * actually needed? Can we just return EBUSY if already open? - * Problem is that this involved inherent races when a tun device - * is handed off from one process to another, as opposed to just - * being slightly stale informationally. - */ +#ifndef __rtems__ pid_t tun_pid; /* owning pid */ +#endif /* __rtems__ */ struct ifnet *tun_ifp; /* the interface */ struct sigio *tun_sigio; /* information for async I/O */ struct selinfo tun_rsel; /* read select */ @@ -117,6 +115,9 @@ static struct clonedevs *tunclones; static TAILQ_HEAD(,tun_softc) tunhead = TAILQ_HEAD_INITIALIZER(tunhead); SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); +static struct sx tun_ioctl_sx; +SX_SYSINIT(tun_ioctl_sx, &tun_ioctl_sx, "tun_ioctl"); + SYSCTL_DECL(_net_link); static SYSCTL_NODE(_net_link, OID_AUTO, tun, CTLFLAG_RW, 0, "IP tunnel software network interface."); @@ -274,15 +275,22 @@ tun_destroy(struct tun_softc *tp) struct cdev *dev; mtx_lock(&tp->tun_mtx); + tp->tun_flags |= TUN_DYING; if ((tp->tun_flags & TUN_OPEN) != 0) cv_wait_unlock(&tp->tun_cv, &tp->tun_mtx); else mtx_unlock(&tp->tun_mtx); CURVNET_SET(TUN2IFP(tp)->if_vnet); + dev = tp->tun_dev; bpfdetach(TUN2IFP(tp)); if_detach(TUN2IFP(tp)); + + sx_xlock(&tun_ioctl_sx); + TUN2IFP(tp)->if_softc = NULL; + sx_xunlock(&tun_ioctl_sx); + free_unr(tun_unrhdr, TUN2IFP(tp)->if_dunit); if_free(TUN2IFP(tp)); destroy_dev(dev); @@ -466,27 +474,15 @@ tunopen(struct cdev *dev, int flag, int mode, struct thread *td) tp = dev->si_drv1; } - /* - * XXXRW: This use of tun_pid is subject to error due to the - * fact that a reference to the tunnel can live beyond the - * death of the process that created it. Can we replace this - * with a simple busy flag? - */ mtx_lock(&tp->tun_mtx); -#ifndef __rtems__ - if (tp->tun_pid != 0 && tp->tun_pid != td->td_proc->p_pid) { -#else /* __rtems__ */ - if (tp->tun_pid != 0 && tp->tun_pid != BSD_DEFAULT_PID) { -#endif /* __rtems__ */ + if ((tp->tun_flags & (TUN_OPEN | TUN_DYING)) != 0) { mtx_unlock(&tp->tun_mtx); return (EBUSY); } + #ifndef __rtems__ tp->tun_pid = td->td_proc->p_pid; -#else /* __rtems__ */ - tp->tun_pid = BSD_DEFAULT_PID; #endif /* __rtems__ */ - tp->tun_flags |= TUN_OPEN; ifp = TUN2IFP(tp); if_link_state_change(ifp, LINK_STATE_UP); @@ -510,8 +506,18 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) ifp = TUN2IFP(tp); mtx_lock(&tp->tun_mtx); - tp->tun_flags &= ~TUN_OPEN; - tp->tun_pid = 0; +#ifndef __rtems__ + /* + * Simply close the device if this isn't the controlling process. This + * may happen if, for instance, the tunnel has been handed off to + * another process. The original controller should be able to close it + * without putting us into an inconsistent state. + */ + if (td->td_proc->p_pid != tp->tun_pid) { + mtx_unlock(&tp->tun_mtx); + return (0); + } +#endif /* __rtems__ */ /* * junk all pending output @@ -550,6 +556,10 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) selwakeuppri(&tp->tun_rsel, PZERO + 1); KNOTE_LOCKED(&tp->tun_rsel.si_note, 0); TUNDEBUG (ifp, "closed\n"); + tp->tun_flags &= ~TUN_OPEN; +#ifndef __rtems__ + tp->tun_pid = 0; +#endif /* __rtems__ */ cv_broadcast(&tp->tun_cv); mtx_unlock(&tp->tun_mtx); @@ -598,18 +608,26 @@ static int tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifreq *ifr = (struct ifreq *)data; - struct tun_softc *tp = ifp->if_softc; + struct tun_softc *tp; struct ifstat *ifs; int error = 0; + sx_xlock(&tun_ioctl_sx); + tp = ifp->if_softc; + if (tp == NULL) { + error = ENXIO; + goto bad; + } switch(cmd) { case SIOCGIFSTATUS: ifs = (struct ifstat *)data; mtx_lock(&tp->tun_mtx); +#ifndef __rtems__ if (tp->tun_pid) snprintf(ifs->ascii, sizeof(ifs->ascii), "\tOpened by PID %d\n", tp->tun_pid); else +#endif /* __rtems__ */ ifs->ascii[0] = '\0'; mtx_unlock(&tp->tun_mtx); break; @@ -628,6 +646,8 @@ tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) default: error = EINVAL; } +bad: + sx_xunlock(&tun_ioctl_sx); return (error); } @@ -809,13 +829,11 @@ tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, } break; case TUNSIFPID: - mtx_lock(&tp->tun_mtx); #ifndef __rtems__ + mtx_lock(&tp->tun_mtx); tp->tun_pid = curthread->td_proc->p_pid; -#else /* __rtems__ */ - tp->tun_pid = BSD_DEFAULT_PID; -#endif /* __rtems__ */ mtx_unlock(&tp->tun_mtx); +#endif /* __rtems__ */ break; case FIONBIO: break; diff --git a/freebsd/sys/net/if_var.h b/freebsd/sys/net/if_var.h index 6504837b..87551c4c 100644 --- a/freebsd/sys/net/if_var.h +++ b/freebsd/sys/net/if_var.h @@ -390,8 +390,7 @@ struct ifnet { struct netdump_methods *if_netdump_methods; #endif /* __rtems__ */ struct epoch_context if_epoch_ctx; - struct epoch_tracker if_addr_et; - struct epoch_tracker if_maddr_et; + void *if_unused[4]; #ifndef __rtems__ /* diff --git a/freebsd/sys/net/iflib.h b/freebsd/sys/net/iflib.h index f8524859..f718922e 100644 --- a/freebsd/sys/net/iflib.h +++ b/freebsd/sys/net/iflib.h @@ -248,7 +248,7 @@ struct if_shared_ctx { /* fields necessary for probe */ pci_vendor_info_t *isc_vendor_info; - char *isc_driver_version; + const char *isc_driver_version; /* optional function to transform the read values to match the table*/ void (*isc_parse_devinfo) (uint16_t *device_id, uint16_t *subvendor_id, uint16_t *subdevice_id, uint16_t *rev_id); @@ -381,6 +381,8 @@ void iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN]); void iflib_request_reset(if_ctx_t ctx); uint8_t iflib_in_detach(if_ctx_t ctx); +uint32_t iflib_get_rx_mbuf_sz(if_ctx_t ctx); + /* * If the driver can plug cleanly in to newbus use these */ diff --git a/freebsd/sys/net/pfvar.h b/freebsd/sys/net/pfvar.h index 22159bd9..248c1938 100644 --- a/freebsd/sys/net/pfvar.h +++ b/freebsd/sys/net/pfvar.h @@ -1021,6 +1021,17 @@ struct pfr_tstats { int pfrts_cnt; int pfrts_refcnt[PFR_REFCNT_MAX]; }; + +struct pfr_ktstats { + struct pfr_table pfrts_t; + counter_u64_t pfrkts_packets[PFR_DIR_MAX][PFR_OP_TABLE_MAX]; + counter_u64_t pfrkts_bytes[PFR_DIR_MAX][PFR_OP_TABLE_MAX]; + counter_u64_t pfrkts_match; + counter_u64_t pfrkts_nomatch; + long pfrkts_tzero; + int pfrkts_cnt; + int pfrkts_refcnt[PFR_REFCNT_MAX]; +}; #define pfrts_name pfrts_t.pfrt_name #define pfrts_flags pfrts_t.pfrt_flags @@ -1034,8 +1045,9 @@ union sockaddr_union { #endif /* _SOCKADDR_UNION_DEFINED */ struct pfr_kcounters { - u_int64_t pfrkc_packets[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; - u_int64_t pfrkc_bytes[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; + counter_u64_t pfrkc_packets[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; + counter_u64_t pfrkc_bytes[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; + long pfrkc_tzero; }; SLIST_HEAD(pfr_kentryworkq, pfr_kentry); @@ -1043,8 +1055,7 @@ struct pfr_kentry { struct radix_node pfrke_node[2]; union sockaddr_union pfrke_sa; SLIST_ENTRY(pfr_kentry) pfrke_workq; - struct pfr_kcounters *pfrke_counters; - long pfrke_tzero; + struct pfr_kcounters pfrke_counters; u_int8_t pfrke_af; u_int8_t pfrke_net; u_int8_t pfrke_not; @@ -1054,7 +1065,7 @@ struct pfr_kentry { SLIST_HEAD(pfr_ktableworkq, pfr_ktable); RB_HEAD(pfr_ktablehead, pfr_ktable); struct pfr_ktable { - struct pfr_tstats pfrkt_ts; + struct pfr_ktstats pfrkt_kts; RB_ENTRY(pfr_ktable) pfrkt_tree; SLIST_ENTRY(pfr_ktable) pfrkt_workq; struct radix_node_head *pfrkt_ip4; @@ -1065,18 +1076,18 @@ struct pfr_ktable { long pfrkt_larg; int pfrkt_nflags; }; -#define pfrkt_t pfrkt_ts.pfrts_t +#define pfrkt_t pfrkt_kts.pfrts_t #define pfrkt_name pfrkt_t.pfrt_name #define pfrkt_anchor pfrkt_t.pfrt_anchor #define pfrkt_ruleset pfrkt_t.pfrt_ruleset #define pfrkt_flags pfrkt_t.pfrt_flags -#define pfrkt_cnt pfrkt_ts.pfrts_cnt -#define pfrkt_refcnt pfrkt_ts.pfrts_refcnt -#define pfrkt_packets pfrkt_ts.pfrts_packets -#define pfrkt_bytes pfrkt_ts.pfrts_bytes -#define pfrkt_match pfrkt_ts.pfrts_match -#define pfrkt_nomatch pfrkt_ts.pfrts_nomatch -#define pfrkt_tzero pfrkt_ts.pfrts_tzero +#define pfrkt_cnt pfrkt_kts.pfrkts_cnt +#define pfrkt_refcnt pfrkt_kts.pfrkts_refcnt +#define pfrkt_packets pfrkt_kts.pfrkts_packets +#define pfrkt_bytes pfrkt_kts.pfrkts_bytes +#define pfrkt_match pfrkt_kts.pfrkts_match +#define pfrkt_nomatch pfrkt_kts.pfrkts_nomatch +#define pfrkt_tzero pfrkt_kts.pfrkts_tzero /* keep synced with pfi_kif, used in RB_FIND */ struct pfi_kif_cmp { diff --git a/freebsd/sys/net/rtsock.c b/freebsd/sys/net/rtsock.c index e1b87095..35656e48 100644 --- a/freebsd/sys/net/rtsock.c +++ b/freebsd/sys/net/rtsock.c @@ -627,6 +627,8 @@ route_output(struct mbuf *m, struct socket *so, ...) if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) senderr(EINVAL); + if (rtm->rtm_flags & RTF_RNH_LOCKED) + senderr(EINVAL); info.rti_flags = rtm->rtm_flags; if (info.rti_info[RTAX_DST] == NULL || info.rti_info[RTAX_DST]->sa_family >= AF_MAX || |