summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2019-06-05 11:35:39 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-06-05 14:16:00 +0200
commit705e362ea5d6f711e987f5d370467b8873fc2255 (patch)
treebb2152c95b76783069419dcd1c24014ba0eb3a1b /freebsd/sys/net
parentAdd RTEMS-specific getcredhostuuid() (diff)
downloadrtems-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.c12
-rw-r--r--freebsd/sys/net/bridgestp.c3
-rw-r--r--freebsd/sys/net/ethernet.h1
-rw-r--r--freebsd/sys/net/ieee_oui.h80
-rw-r--r--freebsd/sys/net/if.c80
-rw-r--r--freebsd/sys/net/if_bridge.c54
-rw-r--r--freebsd/sys/net/if_ethersubr.c38
-rw-r--r--freebsd/sys/net/if_gre.c153
-rw-r--r--freebsd/sys/net/if_gre.h66
-rw-r--r--freebsd/sys/net/if_lagg.c61
-rw-r--r--freebsd/sys/net/if_stf.c1
-rw-r--r--freebsd/sys/net/if_tap.c22
-rw-r--r--freebsd/sys/net/if_tun.c74
-rw-r--r--freebsd/sys/net/if_var.h3
-rw-r--r--freebsd/sys/net/iflib.h4
-rw-r--r--freebsd/sys/net/pfvar.h37
-rw-r--r--freebsd/sys/net/rtsock.c2
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 ||