summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net/if.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net/if.c')
-rw-r--r--freebsd/sys/net/if.c1411
1 files changed, 1016 insertions, 395 deletions
diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c
index 2c638a37..8bfa9e21 100644
--- a/freebsd/sys/net/if.c
+++ b/freebsd/sys/net/if.c
@@ -65,12 +65,16 @@
#include <machine/stdarg.h>
#include <vm/uma.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_clone.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/if_var.h>
+#include <net/if_media.h>
+#include <net/if_vlan_var.h>
#include <net/radix.h>
#include <net/route.h>
#include <net/vnet.h>
@@ -97,14 +101,9 @@
#include <compat/freebsd32/freebsd32.h>
#endif
-struct ifindex_entry {
- struct ifnet *ife_ifnet;
-};
-
SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
-TUNABLE_INT("net.link.ifqmaxlen", &ifqmaxlen);
SYSCTL_INT(_net_link, OID_AUTO, ifqmaxlen, CTLFLAG_RDTUN,
&ifqmaxlen, 0, "max send queue size");
@@ -115,6 +114,13 @@ SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW,
&log_link_state_change, 0,
"log interface link state change events");
+/* Log promiscuous mode change events */
+static int log_promisc_mode_change = 1;
+
+SYSCTL_INT(_net_link, OID_AUTO, log_promisc_mode_change, CTLFLAG_RDTUN,
+ &log_promisc_mode_change, 1,
+ "log promiscuous mode change events");
+
/* Interface description */
static unsigned int ifdescr_maxlen = 1024;
SYSCTL_UINT(_net, OID_AUTO, ifdescr_maxlen, CTLFLAG_RW,
@@ -132,18 +138,22 @@ void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
/* These are external hooks for CARP. */
void (*carp_linkstate_p)(struct ifnet *ifp);
+void (*carp_demote_adj_p)(int, char *);
+int (*carp_master_p)(struct ifaddr *);
#if defined(INET) || defined(INET6)
-struct ifnet *(*carp_forus_p)(struct ifnet *ifp, u_char *dhost);
+int (*carp_forus_p)(struct ifnet *ifp, u_char *dhost);
int (*carp_output_p)(struct ifnet *ifp, struct mbuf *m,
- struct sockaddr *sa, struct rtentry *rt);
+ const struct sockaddr *sa);
+int (*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);
+int (*carp_attach_p)(struct ifaddr *, int);
+void (*carp_detach_p)(struct ifaddr *);
#endif
#ifdef INET
-int (*carp_iamatch_p)(struct ifnet *, struct in_ifaddr *, struct in_addr *,
- u_int8_t **);
+int (*carp_iamatch_p)(struct ifaddr *, uint8_t **);
#endif
#ifdef INET6
struct ifaddr *(*carp_iamatch6_p)(struct ifnet *ifp, struct in6_addr *taddr6);
-caddr_t (*carp_macmatch6_p)(struct ifnet *ifp, struct mbuf *m,
+caddr_t (*carp_macmatch6_p)(struct ifnet *ifp, struct mbuf *m,
const struct in6_addr *taddr);
#endif
@@ -158,23 +168,25 @@ static void if_attachdomain(void *);
static void if_attachdomain1(struct ifnet *);
static int ifconf(u_long, caddr_t);
static void if_freemulti(struct ifmultiaddr *);
-static void if_init(void *);
static void if_grow(void);
static void if_input_default(struct ifnet *, struct mbuf *);
+static int if_requestencap_default(struct ifnet *, struct if_encap_req *);
static void if_route(struct ifnet *, int flag, int fam);
static int if_setflag(struct ifnet *, int, int, int *, int);
static int if_transmit(struct ifnet *ifp, struct mbuf *m);
static void if_unroute(struct ifnet *, int flag, int fam);
static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
-static int if_rtdel(struct radix_node *, void *);
static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *);
static int if_delmulti_locked(struct ifnet *, struct ifmultiaddr *, int);
static void do_link_state_change(void *, int);
static int if_getgroup(struct ifgroupreq *, struct ifnet *);
static int if_getgroupmembers(struct ifgroupreq *);
static void if_delgroups(struct ifnet *);
-static void if_attach_internal(struct ifnet *, int);
-static void if_detach_internal(struct ifnet *, int);
+static void if_attach_internal(struct ifnet *, int, struct if_clone *);
+static int if_detach_internal(struct ifnet *, int, struct if_clone **);
+#ifdef VIMAGE
+static void if_vmove(struct ifnet *, struct vnet *);
+#endif
#ifdef INET6
/*
@@ -184,6 +196,10 @@ static void if_detach_internal(struct ifnet *, int);
extern void nd6_setmtu(struct ifnet *);
#endif
+/* ipsec helper hooks */
+VNET_DEFINE(struct hhook_head *, ipsec_hhh_in[HHOOK_IPSEC_COUNT]);
+VNET_DEFINE(struct hhook_head *, ipsec_hhh_out[HHOOK_IPSEC_COUNT]);
+
VNET_DEFINE(int, if_index);
int ifqmaxlen = IFQ_MAXLEN;
VNET_DEFINE(struct ifnethead, ifnet); /* depend on static init XXX */
@@ -192,7 +208,7 @@ VNET_DEFINE(struct ifgrouphead, ifg_head);
static VNET_DEFINE(int, if_indexlim) = 8;
/* Table of ifnet by index. */
-VNET_DEFINE(struct ifindex_entry *, ifindex_table);
+VNET_DEFINE(struct ifnet **, ifindex_table);
#define V_if_indexlim VNET(if_indexlim)
#define V_ifindex_table VNET(ifindex_table)
@@ -207,7 +223,9 @@ VNET_DEFINE(struct ifindex_entry *, ifindex_table);
* inversions and deadlocks.
*/
struct rwlock ifnet_rwlock;
+RW_SYSINIT_FLAGS(ifnet_rw, &ifnet_rwlock, "ifnet_rw", RW_RECURSE);
struct sx ifnet_sxlock;
+SX_SYSINIT_FLAGS(ifnet_sx, &ifnet_sxlock, "ifnet_sx", SX_RECURSE);
/*
* The allocation of network interfaces is a rather non-atomic affair; we
@@ -229,9 +247,9 @@ ifnet_byindex_locked(u_short idx)
if (idx > V_if_index)
return (NULL);
- if (V_ifindex_table[idx].ife_ifnet == IFNET_HOLD)
+ if (V_ifindex_table[idx] == IFNET_HOLD)
return (NULL);
- return (V_ifindex_table[idx].ife_ifnet);
+ return (V_ifindex_table[idx]);
}
struct ifnet *
@@ -265,34 +283,30 @@ ifnet_byindex_ref(u_short idx)
* Allocate an ifindex array entry; return 0 on success or an error on
* failure.
*/
-static int
-ifindex_alloc_locked(u_short *idxp)
+static u_short
+ifindex_alloc(void)
{
u_short idx;
IFNET_WLOCK_ASSERT();
-
retry:
/*
* Try to find an empty slot below V_if_index. If we fail, take the
* next slot.
*/
for (idx = 1; idx <= V_if_index; idx++) {
- if (V_ifindex_table[idx].ife_ifnet == NULL)
+ if (V_ifindex_table[idx] == NULL)
break;
}
/* Catch if_index overflow. */
- if (idx < 1)
- return (ENOSPC);
if (idx >= V_if_indexlim) {
if_grow();
goto retry;
}
if (idx > V_if_index)
V_if_index = idx;
- *idxp = idx;
- return (0);
+ return (idx);
}
static void
@@ -301,9 +315,9 @@ ifindex_free_locked(u_short idx)
IFNET_WLOCK_ASSERT();
- V_ifindex_table[idx].ife_ifnet = NULL;
+ V_ifindex_table[idx] = NULL;
while (V_if_index > 0 &&
- V_ifindex_table[V_if_index].ife_ifnet == NULL)
+ V_ifindex_table[V_if_index] == NULL)
V_if_index--;
}
@@ -322,7 +336,7 @@ ifnet_setbyindex_locked(u_short idx, struct ifnet *ifp)
IFNET_WLOCK_ASSERT();
- V_ifindex_table[idx].ife_ifnet = ifp;
+ V_ifindex_table[idx] = ifp;
}
static void
@@ -337,11 +351,12 @@ ifnet_setbyindex(u_short idx, struct ifnet *ifp)
struct ifaddr *
ifaddr_byindex(u_short idx)
{
- struct ifaddr *ifa;
+ struct ifnet *ifp;
+ struct ifaddr *ifa = NULL;
IFNET_RLOCK_NOSLEEP();
- ifa = ifnet_byindex_locked(idx)->if_addr;
- if (ifa != NULL)
+ ifp = ifnet_byindex_locked(idx);
+ if (ifp != NULL && (ifa = ifp->if_addr) != NULL)
ifa_ref(ifa);
IFNET_RUNLOCK_NOSLEEP();
return (ifa);
@@ -368,17 +383,6 @@ vnet_if_init(const void *unused __unused)
VNET_SYSINIT(vnet_if_init, SI_SUB_INIT_IF, SI_ORDER_SECOND, vnet_if_init,
NULL);
-/* ARGSUSED*/
-static void
-if_init(void *dummy __unused)
-{
-
- IFNET_LOCK_INIT();
- if_clone_init();
-}
-SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL);
-
-
#ifdef VIMAGE
static void
vnet_if_uninit(const void *unused __unused)
@@ -393,6 +397,20 @@ vnet_if_uninit(const void *unused __unused)
}
VNET_SYSUNINIT(vnet_if_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
vnet_if_uninit, NULL);
+
+static void
+vnet_if_return(const void *unused __unused)
+{
+ struct ifnet *ifp, *nifp;
+
+ /* Return all inherited interfaces to their parent vnets. */
+ TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
+ if (ifp->if_home_vnet != ifp->if_vnet)
+ if_vmove(ifp, ifp->if_home_vnet);
+ }
+}
+VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY,
+ vnet_if_return, NULL);
#endif
static void
@@ -400,7 +418,7 @@ if_grow(void)
{
int oldlim;
u_int n;
- struct ifindex_entry *e;
+ struct ifnet **e;
IFNET_WLOCK_ASSERT();
oldlim = V_if_indexlim;
@@ -433,16 +451,15 @@ if_alloc(u_char type)
ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO);
IFNET_WLOCK();
- if (ifindex_alloc_locked(&idx) != 0) {
- IFNET_WUNLOCK();
- free(ifp, M_IFNET);
- return (NULL);
- }
+ idx = ifindex_alloc();
ifnet_setbyindex_locked(idx, IFNET_HOLD);
IFNET_WUNLOCK();
ifp->if_index = idx;
ifp->if_type = type;
ifp->if_alloctype = type;
+#ifdef VIMAGE
+ ifp->if_vnet = curvnet;
+#endif
if (if_com_alloc[type] != NULL) {
ifp->if_l2com = if_com_alloc[type](type, ifp);
if (ifp->if_l2com == NULL) {
@@ -457,7 +474,6 @@ if_alloc(u_char type)
ifp->if_afdata_initialized = 0;
IF_AFDATA_LOCK_INIT(ifp);
TAILQ_INIT(&ifp->if_addrhead);
- TAILQ_INIT(&ifp->if_prefixhead);
TAILQ_INIT(&ifp->if_multiaddrs);
TAILQ_INIT(&ifp->if_groups);
#ifdef MAC
@@ -466,6 +482,9 @@ if_alloc(u_char type)
ifq_init(&ifp->if_snd, ifp);
refcount_init(&ifp->if_refcount, 1); /* Index reference. */
+ for (int i = 0; i < IFCOUNTERS; i++)
+ ifp->if_counters[i] = counter_u64_alloc(M_WAITOK);
+ ifp->if_get_counter = if_get_counter_default;
ifnet_setbyindex(ifp->if_index, ifp);
return (ifp);
}
@@ -494,23 +513,20 @@ if_free_internal(struct ifnet *ifp)
IF_AFDATA_DESTROY(ifp);
IF_ADDR_LOCK_DESTROY(ifp);
ifq_delete(&ifp->if_snd);
+
+ for (int i = 0; i < IFCOUNTERS; i++)
+ counter_u64_free(ifp->if_counters[i]);
+
free(ifp, M_IFNET);
}
/*
- * This version should only be called by intefaces that switch their type
- * after calling if_alloc(). if_free_type() will go away again now that we
- * have if_alloctype to cache the original allocation type. For now, assert
- * that they match, since we require that in practice.
+ * Deregister an interface and free the associated storage.
*/
void
-if_free_type(struct ifnet *ifp, u_char type)
+if_free(struct ifnet *ifp)
{
- KASSERT(ifp->if_alloctype == type,
- ("if_free_type: type (%d) != alloctype (%d)", type,
- ifp->if_alloctype));
-
ifp->if_flags |= IFF_DYING; /* XXX: Locking */
CURVNET_SET_QUIET(ifp->if_vnet);
@@ -527,18 +543,6 @@ if_free_type(struct ifnet *ifp, u_char type)
}
/*
- * This is the normal version of if_free(), used by device drivers to free a
- * detached network interface. The contents of if_free_type() will move into
- * here when if_free_type() goes away.
- */
-void
-if_free(struct ifnet *ifp)
-{
-
- if_free_type(ifp, ifp->if_alloctype);
-}
-
-/*
* Interfaces to keep an ifnet type-stable despite the possibility of the
* driver calling if_free(). If there are additional references, we defer
* freeing the underlying data structure.
@@ -583,12 +587,21 @@ ifq_delete(struct ifaltq *ifq)
}
/*
- * Perform generic interface initalization tasks and attach the interface
+ * Perform generic interface initialization tasks and attach the interface
* to the list of "active" interfaces. If vmove flag is set on entry
* to if_attach_internal(), perform only a limited subset of initialization
* tasks, given that we are moving from one vnet to another an ifnet which
* has already been fully initialized.
*
+ * Note that if_detach_internal() removes group membership unconditionally
+ * even when vmove flag is set, and if_attach_internal() adds only IFG_ALL.
+ * Thus, when if_vmove() is applied to a cloned interface, group membership
+ * is lost while a cloned one always joins a group whose name is
+ * ifc->ifc_name. To recover this after if_detach_internal() and
+ * if_attach_internal(), the cloner should be specified to
+ * if_attach_internal() via ifc. If it is non-NULL, if_attach_internal()
+ * attempts to join a group whose name is ifc->ifc_name.
+ *
* XXX:
* - The decision to return void and thus require this function to
* succeed is questionable.
@@ -599,14 +612,14 @@ void
if_attach(struct ifnet *ifp)
{
- if_attach_internal(ifp, 0);
+ if_attach_internal(ifp, 0, NULL);
}
/*
* Compute the least common TSO limit.
*/
void
-if_hw_tsomax_common(struct ifnet *ifp, struct ifnet_hw_tsomax *pmax)
+if_hw_tsomax_common(if_t ifp, struct ifnet_hw_tsomax *pmax)
{
/*
* 1) If there is no limit currently, take the limit from
@@ -635,7 +648,7 @@ if_hw_tsomax_common(struct ifnet *ifp, struct ifnet_hw_tsomax *pmax)
* Returns zero if no change. Else non-zero.
*/
int
-if_hw_tsomax_update(struct ifnet *ifp, struct ifnet_hw_tsomax *pmax)
+if_hw_tsomax_update(if_t ifp, struct ifnet_hw_tsomax *pmax)
{
int retval = 0;
if (ifp->if_hw_tsomax != pmax->tsomaxbytes) {
@@ -654,7 +667,7 @@ if_hw_tsomax_update(struct ifnet *ifp, struct ifnet_hw_tsomax *pmax)
}
static void
-if_attach_internal(struct ifnet *ifp, int vmove)
+if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
{
unsigned socksize, ifasize;
int namelen, masklen;
@@ -673,9 +686,12 @@ if_attach_internal(struct ifnet *ifp, int vmove)
if_addgroup(ifp, IFG_ALL);
+ /* Restore group membership for cloned interfaces. */
+ if (vmove && ifc != NULL)
+ if_clone_addgroup(ifp, ifc);
+
getmicrotime(&ifp->if_lastchange);
- ifp->if_data.ifi_epoch = time_uptime;
- ifp->if_data.ifi_datalen = sizeof(struct if_data);
+ ifp->if_epoch = time_uptime;
KASSERT((ifp->if_transmit == NULL && ifp->if_qflush == NULL) ||
(ifp->if_transmit != NULL && ifp->if_qflush != NULL),
@@ -687,6 +703,9 @@ if_attach_internal(struct ifnet *ifp, int vmove)
if (ifp->if_input == NULL)
ifp->if_input = if_input_default;
+ if (ifp->if_requestencap == NULL)
+ ifp->if_requestencap = if_requestencap_default;
+
if (!vmove) {
#ifdef MAC
mac_ifnet_create(ifp);
@@ -706,8 +725,7 @@ if_attach_internal(struct ifnet *ifp, int vmove)
socksize = sizeof(*sdl);
socksize = roundup2(socksize, sizeof(long));
ifasize = sizeof(*ifa) + 2 * socksize;
- ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO);
- ifa_init(ifa);
+ ifa = ifa_alloc(ifasize, M_WAITOK);
sdl = (struct sockaddr_dl *)(ifa + 1);
sdl->sdl_len = socksize;
sdl->sdl_family = AF_LINK;
@@ -792,12 +810,9 @@ static void
if_attachdomain(void *dummy)
{
struct ifnet *ifp;
- int s;
- s = splnet();
TAILQ_FOREACH(ifp, &V_ifnet, if_link)
if_attachdomain1(ifp);
- splx(s);
}
SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
if_attachdomain, NULL);
@@ -806,23 +821,16 @@ static void
if_attachdomain1(struct ifnet *ifp)
{
struct domain *dp;
- int s;
-
- s = splnet();
/*
* Since dp->dom_ifattach calls malloc() with M_WAITOK, we
* cannot lock ifp->if_afdata initialization, entirely.
*/
- if (IF_AFDATA_TRYLOCK(ifp) == 0) {
- splx(s);
- return;
- }
+ IF_AFDATA_LOCK(ifp);
if (ifp->if_afdata_initialized >= domain_init_status) {
IF_AFDATA_UNLOCK(ifp);
- splx(s);
- printf("if_attachdomain called more than once on %s\n",
- ifp->if_xname);
+ log(LOG_WARNING, "%s called more than once on %s\n",
+ __func__, ifp->if_xname);
return;
}
ifp->if_afdata_initialized = domain_init_status;
@@ -835,8 +843,6 @@ if_attachdomain1(struct ifnet *ifp)
ifp->if_afdata[dp->dom_family] =
(*dp->dom_ifattach)(ifp);
}
-
- splx(s);
}
/*
@@ -847,6 +853,7 @@ if_purgeaddrs(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
+ /* XXX cannot hold IF_ADDR_WLOCK over called functions. */
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
if (ifa->ifa_addr->sa_family == AF_LINK)
continue;
@@ -871,7 +878,9 @@ if_purgeaddrs(struct ifnet *ifp)
continue;
}
#endif /* INET6 */
+ IF_ADDR_WLOCK(ifp);
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+ IF_ADDR_WUNLOCK(ifp);
ifa_free(ifa);
}
}
@@ -906,20 +915,34 @@ if_detach(struct ifnet *ifp)
{
CURVNET_SET_QUIET(ifp->if_vnet);
- if_detach_internal(ifp, 0);
+ if_detach_internal(ifp, 0, NULL);
CURVNET_RESTORE();
}
-static void
-if_detach_internal(struct ifnet *ifp, int vmove)
+/*
+ * The vmove flag, if set, indicates that we are called from a callpath
+ * that is moving an interface to a different vnet instance.
+ *
+ * The shutdown flag, if set, indicates that we are called in the
+ * process of shutting down a vnet instance. Currently only the
+ * vnet_if_return SYSUNINIT function sets it. Note: we can be called
+ * on a vnet instance shutdown without this flag being set, e.g., when
+ * the cloned interfaces are destoyed as first thing of teardown.
+ */
+static int
+if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
{
struct ifaddr *ifa;
- struct radix_node_head *rnh;
- int i, j;
+ int i;
struct domain *dp;
struct ifnet *iter;
int found = 0;
+#ifdef VIMAGE
+ int shutdown;
+ shutdown = (ifp->if_vnet->vnet_state > SI_SUB_VNET &&
+ ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
+#endif
IFNET_WLOCK();
TAILQ_FOREACH(iter, &V_ifnet, if_link)
if (iter == ifp) {
@@ -927,28 +950,77 @@ if_detach_internal(struct ifnet *ifp, int vmove)
found = 1;
break;
}
-#ifdef VIMAGE
- if (found)
- curvnet->vnet_ifcnt--;
-#endif
IFNET_WUNLOCK();
if (!found) {
+ /*
+ * While we would want to panic here, we cannot
+ * guarantee that the interface is indeed still on
+ * the list given we don't hold locks all the way.
+ */
+ return (ENOENT);
+#if 0
if (vmove)
panic("%s: ifp=%p not on the ifnet tailq %p",
__func__, ifp, &V_ifnet);
else
return; /* XXX this should panic as well? */
+#endif
}
/*
- * Remove/wait for pending events.
+ * At this point we know the interface still was on the ifnet list
+ * and we removed it so we are in a stable state.
*/
+#ifdef VIMAGE
+ curvnet->vnet_ifcnt--;
+#endif
+
+ /*
+ * In any case (destroy or vmove) detach us from the groups
+ * and remove/wait for pending events on the taskq.
+ * XXX-BZ in theory an interface could still enqueue a taskq change?
+ */
+ if_delgroups(ifp);
+
taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
/*
- * Remove routes and flush queues.
+ * Check if this is a cloned interface or not. Must do even if
+ * shutting down as a if_vmove_reclaim() would move the ifp and
+ * the if_clone_addgroup() will have a corrupted string overwise
+ * from a gibberish pointer.
*/
+ if (vmove && ifcp != NULL)
+ *ifcp = if_clone_findifc(ifp);
+
if_down(ifp);
+
+#ifdef VIMAGE
+ /*
+ * On VNET shutdown abort here as the stack teardown will do all
+ * the work top-down for us.
+ */
+ if (shutdown) {
+ /*
+ * In case of a vmove we are done here without error.
+ * If we would signal an error it would lead to the same
+ * abort as if we did not find the ifnet anymore.
+ * if_detach() calls us in void context and does not care
+ * about an early abort notification, so life is splendid :)
+ */
+ goto finish_vnet_shutdown;
+ }
+#endif
+
+ /*
+ * At this point we are not tearing down a VNET and are either
+ * going to destroy or vmove the interface and have to cleanup
+ * accordingly.
+ */
+
+ /*
+ * Remove routes and flush queues.
+ */
#ifdef ALTQ
if (ALTQ_IS_ENABLED(&ifp->if_snd))
altq_disable(&ifp->if_snd);
@@ -973,6 +1045,12 @@ if_detach_internal(struct ifnet *ifp, int vmove)
#endif
if_purgemaddrs(ifp);
+ /* Announce that the interface is gone. */
+ rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
+ EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
+ if (IS_DEFAULT_VNET(curvnet))
+ devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL);
+
if (!vmove) {
/*
* Prevent further calls into the device driver via ifnet.
@@ -986,37 +1064,21 @@ if_detach_internal(struct ifnet *ifp, int vmove)
ifp->if_addr = NULL;
/* We can now free link ifaddr. */
+ IF_ADDR_WLOCK(ifp);
if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
ifa = TAILQ_FIRST(&ifp->if_addrhead);
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+ IF_ADDR_WUNLOCK(ifp);
ifa_free(ifa);
- }
- }
-
- /*
- * Delete all remaining routes using this interface
- * Unfortuneatly the only way to do this is to slog through
- * the entire routing table looking for routes which point
- * to this interface...oh well...
- */
- for (i = 1; i <= AF_MAX; i++) {
- for (j = 0; j < rt_numfibs; j++) {
- rnh = rt_tables_get_rnh(j, i);
- if (rnh == NULL)
- continue;
- RADIX_NODE_HEAD_LOCK(rnh);
- (void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
- RADIX_NODE_HEAD_UNLOCK(rnh);
- }
+ } else
+ IF_ADDR_WUNLOCK(ifp);
}
- /* Announce that the interface is gone. */
- rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
- EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
- if (IS_DEFAULT_VNET(curvnet))
- devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL);
- if_delgroups(ifp);
+ rt_flushifroutes(ifp);
+#ifdef VIMAGE
+finish_vnet_shutdown:
+#endif
/*
* We cannot hold the lock over dom_ifdetach calls as they might
* sleep, for example trying to drain a callout, thus open up the
@@ -1027,10 +1089,14 @@ if_detach_internal(struct ifnet *ifp, int vmove)
ifp->if_afdata_initialized = 0;
IF_AFDATA_UNLOCK(ifp);
for (dp = domains; i > 0 && dp; dp = dp->dom_next) {
- if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
+ if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) {
(*dp->dom_ifdetach)(ifp,
ifp->if_afdata[dp->dom_family]);
+ ifp->if_afdata[dp->dom_family] = NULL;
+ }
}
+
+ return (0);
}
#ifdef VIMAGE
@@ -1041,16 +1107,28 @@ if_detach_internal(struct ifnet *ifp, int vmove)
* unused if_index in target vnet and calls if_grow() if necessary,
* and finally find an unused if_xname for the target vnet.
*/
-void
+static void
if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
{
- u_short idx;
+ struct if_clone *ifc;
+ u_int bif_dlt, bif_hdrlen;
+ int rc;
+
+ /*
+ * if_detach_internal() will call the eventhandler to notify
+ * interface departure. That will detach if_bpf. We need to
+ * safe the dlt and hdrlen so we can re-attach it later.
+ */
+ bpf_get_bp_params(ifp->if_bpf, &bif_dlt, &bif_hdrlen);
/*
* Detach from current vnet, but preserve LLADDR info, do not
* mark as dead etc. so that the ifnet can be reattached later.
+ * If we cannot find it, we lost the race to someone else.
*/
- if_detach_internal(ifp, 1);
+ rc = if_detach_internal(ifp, 1, &ifc);
+ if (rc != 0)
+ return;
/*
* Unlink the ifnet from ifindex_table[] in current vnet, and shrink
@@ -1076,15 +1154,14 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
CURVNET_SET_QUIET(new_vnet);
IFNET_WLOCK();
- if (ifindex_alloc_locked(&idx) != 0) {
- IFNET_WUNLOCK();
- panic("if_index overflow");
- }
- ifp->if_index = idx;
+ ifp->if_index = ifindex_alloc();
ifnet_setbyindex_locked(ifp->if_index, ifp);
IFNET_WUNLOCK();
- if_attach_internal(ifp, 1);
+ if_attach_internal(ifp, 1, ifc);
+
+ if (ifp->if_bpf == NULL)
+ bpfattach(ifp, bif_dlt, bif_hdrlen);
CURVNET_RESTORE();
}
@@ -1097,6 +1174,7 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
{
struct prison *pr;
struct ifnet *difp;
+ int shutdown;
/* Try to find the prison within our visibility. */
sx_slock(&allprison_lock);
@@ -1117,12 +1195,22 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
/* XXX Lock interfaces to avoid races. */
CURVNET_SET_QUIET(pr->pr_vnet);
difp = ifunit(ifname);
- CURVNET_RESTORE();
if (difp != NULL) {
+ CURVNET_RESTORE();
prison_free(pr);
return (EEXIST);
}
+ /* Make sure the VNET is stable. */
+ shutdown = (ifp->if_vnet->vnet_state > SI_SUB_VNET &&
+ ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
+ if (shutdown) {
+ CURVNET_RESTORE();
+ prison_free(pr);
+ return (EBUSY);
+ }
+ CURVNET_RESTORE();
+
/* Move the interface into the child jail/vnet. */
if_vmove(ifp, pr->pr_vnet);
@@ -1139,6 +1227,7 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid)
struct prison *pr;
struct vnet *vnet_dst;
struct ifnet *ifp;
+ int shutdown;
/* Try to find the prison within our visibility. */
sx_slock(&allprison_lock);
@@ -1166,6 +1255,15 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid)
return (EEXIST);
}
+ /* Make sure the VNET is stable. */
+ shutdown = (ifp->if_vnet->vnet_state > SI_SUB_VNET &&
+ ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
+ if (shutdown) {
+ CURVNET_RESTORE();
+ prison_free(pr);
+ return (EBUSY);
+ }
+
/* Get interface back from child jail/vnet. */
if_vmove(ifp, vnet_dst);
CURVNET_RESTORE();
@@ -1187,6 +1285,7 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
struct ifg_list *ifgl;
struct ifg_group *ifg = NULL;
struct ifg_member *ifgm;
+ int new = 0;
if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
groupname[strlen(groupname) - 1] <= '9')
@@ -1227,8 +1326,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
ifg->ifg_refcnt = 0;
TAILQ_INIT(&ifg->ifg_members);
- EVENTHANDLER_INVOKE(group_attach_event, ifg);
TAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next);
+ new = 1;
}
ifg->ifg_refcnt++;
@@ -1242,6 +1341,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
IFNET_WUNLOCK();
+ if (new)
+ EVENTHANDLER_INVOKE(group_attach_event, ifg);
EVENTHANDLER_INVOKE(group_change_event, groupname);
return (0);
@@ -1280,10 +1381,11 @@ if_delgroup(struct ifnet *ifp, const char *groupname)
if (--ifgl->ifgl_group->ifg_refcnt == 0) {
TAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_next);
+ IFNET_WUNLOCK();
EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group);
free(ifgl->ifgl_group, M_TEMP);
- }
- IFNET_WUNLOCK();
+ } else
+ IFNET_WUNLOCK();
free(ifgl, M_TEMP);
@@ -1324,11 +1426,12 @@ if_delgroups(struct ifnet *ifp)
if (--ifgl->ifgl_group->ifg_refcnt == 0) {
TAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_next);
+ IFNET_WUNLOCK();
EVENTHANDLER_INVOKE(group_detach_event,
ifgl->ifgl_group);
free(ifgl->ifgl_group, M_TEMP);
- }
- IFNET_WUNLOCK();
+ } else
+ IFNET_WUNLOCK();
free(ifgl, M_TEMP);
@@ -1434,46 +1537,63 @@ if_getgroupmembers(struct ifgroupreq *data)
}
/*
- * Delete Routes for a Network Interface
- *
- * Called for each routing entry via the rnh->rnh_walktree() call above
- * to delete all route entries referencing a detaching network interface.
- *
- * Arguments:
- * rn pointer to node in the routing table
- * arg argument passed to rnh->rnh_walktree() - detaching interface
- *
- * Returns:
- * 0 successful
- * errno failed - reason indicated
- *
+ * Return counter values from counter(9)s stored in ifnet.
*/
-static int
-if_rtdel(struct radix_node *rn, void *arg)
+uint64_t
+if_get_counter_default(struct ifnet *ifp, ift_counter cnt)
{
- struct rtentry *rt = (struct rtentry *)rn;
- struct ifnet *ifp = arg;
- int err;
- if (rt->rt_ifp == ifp) {
+ KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
- /*
- * Protect (sorta) against walktree recursion problems
- * with cloned routes
- */
- if ((rt->rt_flags & RTF_UP) == 0)
- return (0);
+ return (counter_u64_fetch(ifp->if_counters[cnt]));
+}
- err = rtrequest_fib(RTM_DELETE, rt_key(rt), rt->rt_gateway,
- rt_mask(rt),
- rt->rt_flags|RTF_RNH_LOCKED|RTF_PINNED,
- (struct rtentry **) NULL, rt->rt_fibnum);
- if (err) {
- log(LOG_WARNING, "if_rtdel: error %d\n", err);
- }
- }
+/*
+ * Increase an ifnet counter. Usually used for counters shared
+ * between the stack and a driver, but function supports them all.
+ */
+void
+if_inc_counter(struct ifnet *ifp, ift_counter cnt, int64_t inc)
+{
- return (0);
+ KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
+
+ counter_u64_add(ifp->if_counters[cnt], inc);
+}
+
+/*
+ * Copy data from ifnet to userland API structure if_data.
+ */
+void
+if_data_copy(struct ifnet *ifp, struct if_data *ifd)
+{
+
+ ifd->ifi_type = ifp->if_type;
+ ifd->ifi_physical = 0;
+ ifd->ifi_addrlen = ifp->if_addrlen;
+ ifd->ifi_hdrlen = ifp->if_hdrlen;
+ ifd->ifi_link_state = ifp->if_link_state;
+ ifd->ifi_vhid = 0;
+ ifd->ifi_datalen = sizeof(struct if_data);
+ ifd->ifi_mtu = ifp->if_mtu;
+ ifd->ifi_metric = ifp->if_metric;
+ ifd->ifi_baudrate = ifp->if_baudrate;
+ ifd->ifi_hwassist = ifp->if_hwassist;
+ ifd->ifi_epoch = ifp->if_epoch;
+ ifd->ifi_lastchange = ifp->if_lastchange;
+
+ ifd->ifi_ipackets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS);
+ ifd->ifi_ierrors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS);
+ ifd->ifi_opackets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS);
+ ifd->ifi_oerrors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS);
+ ifd->ifi_collisions = ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS);
+ ifd->ifi_ibytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES);
+ ifd->ifi_obytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES);
+ ifd->ifi_imcasts = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS);
+ ifd->ifi_omcasts = ifp->if_get_counter(ifp, IFCOUNTER_OMCASTS);
+ ifd->ifi_iqdrops = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS);
+ ifd->ifi_oqdrops = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS);
+ ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO);
}
/*
@@ -1497,28 +1617,56 @@ if_addr_runlock(struct ifnet *ifp)
}
void
-if_maddr_rlock(struct ifnet *ifp)
+if_maddr_rlock(if_t ifp)
{
- IF_ADDR_RLOCK(ifp);
+ IF_ADDR_RLOCK((struct ifnet *)ifp);
}
void
-if_maddr_runlock(struct ifnet *ifp)
+if_maddr_runlock(if_t ifp)
{
- IF_ADDR_RUNLOCK(ifp);
+ IF_ADDR_RUNLOCK((struct ifnet *)ifp);
}
/*
- * Reference count functions for ifaddrs.
+ * Initialization, destruction and refcounting functions for ifaddrs.
*/
-void
-ifa_init(struct ifaddr *ifa)
+struct ifaddr *
+ifa_alloc(size_t size, int flags)
{
+ struct ifaddr *ifa;
+
+ KASSERT(size >= sizeof(struct ifaddr),
+ ("%s: invalid size %zu", __func__, size));
+
+ ifa = malloc(size, M_IFADDR, M_ZERO | flags);
+ if (ifa == NULL)
+ return (NULL);
+
+ if ((ifa->ifa_opackets = counter_u64_alloc(flags)) == NULL)
+ goto fail;
+ if ((ifa->ifa_ipackets = counter_u64_alloc(flags)) == NULL)
+ goto fail;
+ if ((ifa->ifa_obytes = counter_u64_alloc(flags)) == NULL)
+ goto fail;
+ if ((ifa->ifa_ibytes = counter_u64_alloc(flags)) == NULL)
+ goto fail;
- mtx_init(&ifa->ifa_mtx, "ifaddr", NULL, MTX_DEF);
refcount_init(&ifa->ifa_refcnt, 1);
+
+ return (ifa);
+
+fail:
+ /* free(NULL) is okay */
+ counter_u64_free(ifa->ifa_opackets);
+ counter_u64_free(ifa->ifa_ipackets);
+ counter_u64_free(ifa->ifa_obytes);
+ counter_u64_free(ifa->ifa_ibytes);
+ free(ifa, M_IFADDR);
+
+ return (NULL);
}
void
@@ -1533,62 +1681,61 @@ ifa_free(struct ifaddr *ifa)
{
if (refcount_release(&ifa->ifa_refcnt)) {
- mtx_destroy(&ifa->ifa_mtx);
+ counter_u64_free(ifa->ifa_opackets);
+ counter_u64_free(ifa->ifa_ipackets);
+ counter_u64_free(ifa->ifa_obytes);
+ counter_u64_free(ifa->ifa_ibytes);
free(ifa, M_IFADDR);
}
}
-int
-ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
+static int
+ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa,
+ struct sockaddr *ia)
{
- int error = 0;
- struct rtentry *rt = NULL;
+ int error;
struct rt_addrinfo info;
- static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+ struct sockaddr_dl null_sdl;
+ struct ifnet *ifp;
+
+ ifp = ifa->ifa_ifp;
bzero(&info, sizeof(info));
- info.rti_ifp = V_loif;
+ if (cmd != RTM_DELETE)
+ info.rti_ifp = V_loif;
info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = ia;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
- error = rtrequest1_fib(RTM_ADD, &info, &rt, ifa->ifa_ifp->if_fib);
-
- if (error == 0 && rt != NULL) {
- RT_LOCK(rt);
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
- ifa->ifa_ifp->if_type;
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
- ifa->ifa_ifp->if_index;
- RT_REMREF(rt);
- RT_UNLOCK(rt);
- } else if (error != 0)
- log(LOG_INFO, "ifa_add_loopback_route: insertion failed\n");
+ link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type);
+
+ error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib);
+
+ if (error != 0)
+ log(LOG_DEBUG, "%s: %s failed for interface %s: %u\n",
+ __func__, otype, if_name(ifp), error);
return (error);
}
int
+ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
+{
+
+ return (ifa_maintain_loopback_route(RTM_ADD, "insertion", ifa, ia));
+}
+
+int
ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
{
- int error = 0;
- struct rt_addrinfo info;
- struct sockaddr_dl null_sdl;
- bzero(&null_sdl, sizeof(null_sdl));
- null_sdl.sdl_len = sizeof(null_sdl);
- null_sdl.sdl_family = AF_LINK;
- null_sdl.sdl_type = ifa->ifa_ifp->if_type;
- null_sdl.sdl_index = ifa->ifa_ifp->if_index;
- bzero(&info, sizeof(info));
- info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC;
- info.rti_info[RTAX_DST] = ia;
- info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
- error = rtrequest1_fib(RTM_DELETE, &info, NULL, ifa->ifa_ifp->if_fib);
+ return (ifa_maintain_loopback_route(RTM_DELETE, "deletion", ifa, ia));
+}
- if (error != 0)
- log(LOG_INFO, "ifa_del_loopback_route: deletion failed\n");
+int
+ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
+{
- return (error);
+ return (ifa_maintain_loopback_route(RTM_CHANGE, "switch", ifa, ia));
}
/*
@@ -1597,22 +1744,19 @@ ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
* to perform a different comparison.
*/
-#define sa_equal(a1, a2) \
- (bcmp((a1), (a2), ((a1))->sa_len) == 0)
-
#define sa_dl_equal(a1, a2) \
- ((((struct sockaddr_dl *)(a1))->sdl_len == \
- ((struct sockaddr_dl *)(a2))->sdl_len) && \
- (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \
- LLADDR((struct sockaddr_dl *)(a2)), \
- ((struct sockaddr_dl *)(a1))->sdl_alen) == 0))
+ ((((const struct sockaddr_dl *)(a1))->sdl_len == \
+ ((const struct sockaddr_dl *)(a2))->sdl_len) && \
+ (bcmp(CLLADDR((const struct sockaddr_dl *)(a1)), \
+ CLLADDR((const struct sockaddr_dl *)(a2)), \
+ ((const struct sockaddr_dl *)(a1))->sdl_alen) == 0))
/*
* Locate an interface based on a complete address.
*/
/*ARGSUSED*/
static struct ifaddr *
-ifa_ifwithaddr_internal(struct sockaddr *addr, int getref)
+ifa_ifwithaddr_internal(const struct sockaddr *addr, int getref)
{
struct ifnet *ifp;
struct ifaddr *ifa;
@@ -1649,14 +1793,14 @@ done:
}
struct ifaddr *
-ifa_ifwithaddr(struct sockaddr *addr)
+ifa_ifwithaddr(const struct sockaddr *addr)
{
return (ifa_ifwithaddr_internal(addr, 1));
}
int
-ifa_ifwithaddr_check(struct sockaddr *addr)
+ifa_ifwithaddr_check(const struct sockaddr *addr)
{
return (ifa_ifwithaddr_internal(addr, 0) != NULL);
@@ -1667,13 +1811,15 @@ ifa_ifwithaddr_check(struct sockaddr *addr)
*/
/* ARGSUSED */
struct ifaddr *
-ifa_ifwithbroadaddr(struct sockaddr *addr)
+ifa_ifwithbroadaddr(const struct sockaddr *addr, int fibnum)
{
struct ifnet *ifp;
struct ifaddr *ifa;
IFNET_RLOCK_NOSLEEP();
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
+ continue;
IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != addr->sa_family)
@@ -1700,7 +1846,7 @@ done:
*/
/*ARGSUSED*/
struct ifaddr *
-ifa_ifwithdstaddr_fib(struct sockaddr *addr, int fibnum)
+ifa_ifwithdstaddr(const struct sockaddr *addr, int fibnum)
{
struct ifnet *ifp;
struct ifaddr *ifa;
@@ -1730,32 +1876,25 @@ done:
return (ifa);
}
-struct ifaddr *
-ifa_ifwithdstaddr(struct sockaddr *addr)
-{
-
- return (ifa_ifwithdstaddr_fib(addr, RT_ALL_FIBS));
-}
-
/*
* Find an interface on a specific network. If many, choice
* is most specific found.
*/
struct ifaddr *
-ifa_ifwithnet_fib(struct sockaddr *addr, int ignore_ptp, int fibnum)
+ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum)
{
struct ifnet *ifp;
struct ifaddr *ifa;
struct ifaddr *ifa_maybe = NULL;
u_int af = addr->sa_family;
- char *addr_data = addr->sa_data, *cplim;
+ const char *addr_data = addr->sa_data, *cplim;
/*
* AF_LINK addresses can be looked up directly by their index number,
* so do that if we can.
*/
if (af == AF_LINK) {
- struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
+ const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)addr;
if (sdl->sdl_index && sdl->sdl_index <= V_if_index)
return (ifaddr_byindex(sdl->sdl_index));
}
@@ -1772,7 +1911,7 @@ ifa_ifwithnet_fib(struct sockaddr *addr, int ignore_ptp, int fibnum)
continue;
IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- char *cp, *cp2, *cp3;
+ const char *cp, *cp2, *cp3;
if (ifa->ifa_addr->sa_family != af)
next: continue;
@@ -1794,19 +1933,6 @@ next: continue;
}
} else {
/*
- * if we have a special address handler,
- * then use it instead of the generic one.
- */
- if (ifa->ifa_claim_addr) {
- if ((*ifa->ifa_claim_addr)(ifa, addr)) {
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
- goto done;
- }
- continue;
- }
-
- /*
* Scan all the bits in the ifa's address.
* If a bit dissagrees with what we are
* looking for, mask it with the netmask
@@ -1826,11 +1952,13 @@ next: continue;
/*
* If the netmask of what we just found
* is more specific than what we had before
- * (if we had one) then remember the new one
- * before continuing to search
- * for an even better one.
+ * (if we had one), or if the virtual status
+ * of new prefix is better than of the old one,
+ * then remember the new one before continuing
+ * to search for an even better one.
*/
if (ifa_maybe == NULL ||
+ ifa_preferred(ifa_maybe, ifa) ||
rn_refines((caddr_t)ifa->ifa_netmask,
(caddr_t)ifa_maybe->ifa_netmask)) {
if (ifa_maybe != NULL)
@@ -1851,22 +1979,15 @@ done:
return (ifa);
}
-struct ifaddr *
-ifa_ifwithnet(struct sockaddr *addr, int ignore_ptp)
-{
-
- return (ifa_ifwithnet_fib(addr, ignore_ptp, RT_ALL_FIBS));
-}
-
/*
* Find an interface address specific to an interface best matching
* a given address.
*/
struct ifaddr *
-ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
+ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
{
struct ifaddr *ifa;
- char *cp, *cp2, *cp3;
+ const char *cp, *cp2, *cp3;
char *cplim;
struct ifaddr *ifa_maybe = NULL;
u_int af = addr->sa_family;
@@ -1909,6 +2030,21 @@ done:
return (ifa);
}
+/*
+ * See whether new ifa is better than current one:
+ * 1) A non-virtual one is preferred over virtual.
+ * 2) A virtual in master state preferred over any other state.
+ *
+ * Used in several address selecting functions.
+ */
+int
+ifa_preferred(struct ifaddr *cur, struct ifaddr *next)
+{
+
+ return (cur->ifa_carp && (!next->ifa_carp ||
+ ((*carp_master_p)(next) && !(*carp_master_p)(cur))));
+}
+
#include <net/if_llatbl.h>
/*
@@ -1923,10 +2059,8 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
struct sockaddr *dst;
struct ifnet *ifp;
- RT_LOCK_ASSERT(rt);
-
- if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
- ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
+ if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == NULL) ||
+ ((ifp = ifa->ifa_ifp) == NULL) || ((dst = rt_key(rt)) == NULL))
return;
ifa = ifaof_ifpforaddr(dst, ifp);
if (ifa) {
@@ -1938,10 +2072,41 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
}
}
+struct sockaddr_dl *
+link_alloc_sdl(size_t size, int flags)
+{
+
+ return (malloc(size, M_TEMP, flags));
+}
+
+void
+link_free_sdl(struct sockaddr *sa)
+{
+ free(sa, M_TEMP);
+}
+
+/*
+ * Fills in given sdl with interface basic info.
+ * Returns pointer to filled sdl.
+ */
+struct sockaddr_dl *
+link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype)
+{
+ struct sockaddr_dl *sdl;
+
+ sdl = (struct sockaddr_dl *)paddr;
+ memset(sdl, 0, sizeof(struct sockaddr_dl));
+ sdl->sdl_len = sizeof(struct sockaddr_dl);
+ sdl->sdl_family = AF_LINK;
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = iftype;
+
+ return (sdl);
+}
+
/*
* Mark an interface down and notify protocols of
* the transition.
- * NOTE: must be called at splnet or eqivalent.
*/
static void
if_unroute(struct ifnet *ifp, int flag, int fam)
@@ -1965,7 +2130,6 @@ if_unroute(struct ifnet *ifp, int flag, int fam)
/*
* Mark an interface up and notify protocols of
* the transition.
- * NOTE: must be called at splnet or eqivalent.
*/
static void
if_route(struct ifnet *ifp, int flag, int fam)
@@ -2026,7 +2190,7 @@ do_link_state_change(void *arg, int pending)
(*vlan_link_state_p)(ifp);
if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) &&
- IFP2AC(ifp)->ac_netgraph != NULL)
+ ifp->if_l2com != NULL)
(*ng_ether_link_state_p)(ifp, link_state);
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
@@ -2051,7 +2215,6 @@ do_link_state_change(void *arg, int pending)
/*
* Mark an interface down and notify protocols of
* the transition.
- * NOTE: must be called at splnet or eqivalent.
*/
void
if_down(struct ifnet *ifp)
@@ -2063,7 +2226,6 @@ if_down(struct ifnet *ifp)
/*
* Mark an interface up and notify protocols of
* the transition.
- * NOTE: must be called at splnet or eqivalent.
*/
void
if_up(struct ifnet *ifp)
@@ -2088,8 +2250,8 @@ if_qflush(struct ifnet *ifp)
ALTQ_PURGE(ifq);
#endif
n = ifq->ifq_head;
- while ((m = n) != 0) {
- n = m->m_act;
+ while ((m = n) != NULL) {
+ n = m->m_nextpkt;
m_freem(m);
}
ifq->ifq_head = 0;
@@ -2140,7 +2302,6 @@ static int
ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
{
struct ifreq *ifr;
- struct ifstat *ifs;
int error = 0;
int new_flags, temp_flags;
size_t namelen, onamelen;
@@ -2182,7 +2343,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
break;
case SIOCGIFPHYS:
- ifr->ifr_phys = ifp->if_physical;
+ /* XXXGL: did this ever worked? */
+ ifr->ifr_phys = 0;
break;
case SIOCGIFDESCR:
@@ -2262,18 +2424,12 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
*/
new_flags = (ifr->ifr_flags & 0xffff) |
(ifr->ifr_flagshigh << 16);
- if (ifp->if_flags & IFF_SMART) {
- /* Smart drivers twiddle their own routes */
- } else if (ifp->if_flags & IFF_UP &&
+ if (ifp->if_flags & IFF_UP &&
(new_flags & IFF_UP) == 0) {
- int s = splimp();
if_down(ifp);
- splx(s);
} else if (new_flags & IFF_UP &&
(ifp->if_flags & IFF_UP) == 0) {
- int s = splimp();
if_up(ifp);
- splx(s);
}
/* See if permanently promiscuous mode bit is about to flip */
if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) {
@@ -2281,9 +2437,11 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
ifp->if_flags |= IFF_PROMISC;
else if (ifp->if_pcount == 0)
ifp->if_flags &= ~IFF_PROMISC;
- log(LOG_INFO, "%s: permanently promiscuous mode %s\n",
- ifp->if_xname,
- (new_flags & IFF_PPROMISC) ? "enabled" : "disabled");
+ if (log_promisc_mode_change)
+ log(LOG_INFO, "%s: permanently promiscuous mode %s\n",
+ ifp->if_xname,
+ ((new_flags & IFF_PPROMISC) ?
+ "enabled" : "disabled"));
}
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
(new_flags &~ IFF_CANTCHANGE);
@@ -2321,6 +2479,11 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
return (error);
if (new_name[0] == '\0')
return (EINVAL);
+ if (new_name[IFNAMSIZ-1] != '\0') {
+ new_name[IFNAMSIZ-1] = '\0';
+ if (strlen(new_name) == IFNAMSIZ-1)
+ return (EINVAL);
+ }
if (ifunit(new_name) != NULL)
return (EEXIST);
@@ -2339,9 +2502,9 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
log(LOG_INFO, "%s: changing name to '%s'\n",
ifp->if_xname, new_name);
+ IF_ADDR_WLOCK(ifp);
strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
ifa = ifp->if_addr;
- IFA_LOCK(ifa);
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
namelen = strlen(new_name);
onamelen = sdl->sdl_nlen;
@@ -2360,7 +2523,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
bzero(sdl->sdl_data, onamelen);
while (namelen != 0)
sdl->sdl_data[--namelen] = 0xff;
- IFA_UNLOCK(ifa);
+ IF_ADDR_WUNLOCK(ifp);
EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
/* Announce the return of the interface. */
@@ -2420,6 +2583,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
#ifdef INET6
nd6_setmtu(ifp);
#endif
+ rt_updatemtu(ifp);
}
break;
}
@@ -2470,7 +2634,6 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
#ifdef INET6
case SIOCSIFPHYADDR_IN6:
#endif
- case SIOCSLIFPHYADDR:
case SIOCSIFMEDIA:
case SIOCSIFGENERIC:
error = priv_check(td, PRIV_NET_HWIOCTL);
@@ -2484,13 +2647,10 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
break;
case SIOCGIFSTATUS:
- ifs = (struct ifstat *)data;
- ifs->ascii[0] = '\0';
-
case SIOCGIFPSRCADDR:
case SIOCGIFPDSTADDR:
- case SIOCGLIFPHYADDR:
case SIOCGIFMEDIA:
+ case SIOCGIFXMEDIA:
case SIOCGIFGENERIC:
if (ifp->if_ioctl == NULL)
return (EOPNOTSUPP);
@@ -2503,7 +2663,6 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
return (error);
error = if_setlladdr(ifp,
ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
- EVENTHANDLER_INVOKE(iflladdr_event, ifp);
break;
case SIOCAIFGROUP:
@@ -2542,6 +2701,9 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
return (error);
}
+/* COMPAT_SVR4 */
+#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf)
+
#ifdef COMPAT_FREEBSD32
struct ifconf32 {
int32_t ifc_len;
@@ -2563,11 +2725,25 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
struct ifreq *ifr;
int error;
int oif_flags;
+#ifdef VIMAGE
+ int shutdown;
+#endif
CURVNET_SET(so->so_vnet);
+#ifdef VIMAGE
+ /* Make sure the VNET is stable. */
+ shutdown = (so->so_vnet->vnet_state > SI_SUB_VNET &&
+ so->so_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
+ if (shutdown) {
+ CURVNET_RESTORE();
+ return (EBUSY);
+ }
+#endif
+
+
switch (cmd) {
case SIOCGIFCONF:
- case OSIOCGIFCONF:
+ case OSIOCGIFCONF: /* COMPAT_SVR4 */
error = ifconf(cmd, data);
CURVNET_RESTORE();
return (error);
@@ -2626,6 +2802,16 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
error = if_getgroupmembers((struct ifgroupreq *)data);
CURVNET_RESTORE();
return (error);
+#if defined(INET) || defined(INET6)
+ case SIOCSVH:
+ case SIOCGVH:
+ if (carp_ioctl_p == NULL)
+ error = EPROTONOSUPPORT;
+ else
+ error = (*carp_ioctl_p)(ifr, cmd, td);
+ CURVNET_RESTORE();
+ return (error);
+#endif
}
ifp = ifunit_ref(ifr->ifr_name);
@@ -2657,79 +2843,17 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
* layer, and do not perform any credentials checks or input
* validation.
*/
-#ifndef COMPAT_43
- error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
- data,
- ifp, td));
+ error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data,
+ ifp, td));
if (error == EOPNOTSUPP && ifp != NULL && ifp->if_ioctl != NULL &&
cmd != SIOCSIFADDR && cmd != SIOCSIFBRDADDR &&
cmd != SIOCSIFDSTADDR && cmd != SIOCSIFNETMASK)
error = (*ifp->if_ioctl)(ifp, cmd, data);
-#else
- {
- u_long ocmd = cmd;
-
- switch (cmd) {
-
- case SIOCSIFDSTADDR:
- case SIOCSIFADDR:
- case SIOCSIFBRDADDR:
- case SIOCSIFNETMASK:
-#if BYTE_ORDER != BIG_ENDIAN
- if (ifr->ifr_addr.sa_family == 0 &&
- ifr->ifr_addr.sa_len < 16) {
- ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
- ifr->ifr_addr.sa_len = 16;
- }
-#else
- if (ifr->ifr_addr.sa_len == 0)
- ifr->ifr_addr.sa_len = 16;
-#endif
- break;
-
- case OSIOCGIFADDR:
- cmd = SIOCGIFADDR;
- break;
-
- case OSIOCGIFDSTADDR:
- cmd = SIOCGIFDSTADDR;
- break;
-
- case OSIOCGIFBRDADDR:
- cmd = SIOCGIFBRDADDR;
- break;
-
- case OSIOCGIFNETMASK:
- cmd = SIOCGIFNETMASK;
- }
- error = ((*so->so_proto->pr_usrreqs->pru_control)(so,
- cmd,
- data,
- ifp, td));
- if (error == EOPNOTSUPP && ifp != NULL &&
- ifp->if_ioctl != NULL &&
- cmd != SIOCSIFADDR && cmd != SIOCSIFBRDADDR &&
- cmd != SIOCSIFDSTADDR && cmd != SIOCSIFNETMASK)
- error = (*ifp->if_ioctl)(ifp, cmd, data);
- switch (ocmd) {
-
- case OSIOCGIFADDR:
- case OSIOCGIFDSTADDR:
- case OSIOCGIFBRDADDR:
- case OSIOCGIFNETMASK:
- *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
-
- }
- }
-#endif /* COMPAT_43 */
if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
#ifdef INET6
- if (ifp->if_flags & IFF_UP) {
- int s = splimp();
+ if (ifp->if_flags & IFF_UP)
in6_if_up(ifp);
- splx(s);
- }
#endif
}
if_rele(ifp);
@@ -2825,7 +2949,8 @@ ifpromisc(struct ifnet *ifp, int pswitch)
error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC,
&ifp->if_pcount, pswitch);
/* If promiscuous mode status has changed, log a message */
- if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC))
+ if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC) &&
+ log_promisc_mode_change)
log(LOG_INFO, "%s: promiscuous mode %s\n",
ifp->if_xname,
(ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
@@ -2890,16 +3015,15 @@ again:
if (prison_if(curthread->td_ucred, sa) != 0)
continue;
addrs++;
-#ifdef COMPAT_43
+ /* COMPAT_SVR4 */
if (cmd == OSIOCGIFCONF) {
struct osockaddr *osa =
- (struct osockaddr *)&ifr.ifr_addr;
+ (struct osockaddr *)&ifr.ifr_addr;
ifr.ifr_addr = *sa;
osa->sa_family = sa->sa_family;
sbuf_bcat(sb, &ifr, sizeof(ifr));
max_len += sizeof(ifr);
} else
-#endif
if (sa->sa_len <= sizeof(*sa)) {
ifr.ifr_addr = *sa;
sbuf_bcat(sb, &ifr, sizeof(ifr));
@@ -2955,7 +3079,7 @@ if_allmulti(struct ifnet *ifp, int onswitch)
}
struct ifmultiaddr *
-if_findmulti(struct ifnet *ifp, struct sockaddr *sa)
+if_findmulti(struct ifnet *ifp, const struct sockaddr *sa)
{
struct ifmultiaddr *ifma;
@@ -3034,8 +3158,6 @@ if_freemulti(struct ifmultiaddr *ifma)
KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d",
ifma->ifma_refcount));
- KASSERT(ifma->ifma_protospec == NULL,
- ("if_freemulti: protospec not NULL"));
if (ifma->ifma_lladdr != NULL)
free(ifma->ifma_lladdr, M_IFMADDR);
@@ -3067,6 +3189,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
{
struct ifmultiaddr *ifma, *ll_ifma;
struct sockaddr *llsa;
+ struct sockaddr_dl sdl;
int error;
/*
@@ -3086,12 +3209,18 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
/*
* The address isn't already present; resolve the protocol address
* into a link layer address, and then look that up, bump its
- * refcount or allocate an ifma for that also. If 'llsa' was
- * returned, we will need to free it later.
+ * refcount or allocate an ifma for that also.
+ * Most link layer resolving functions returns address data which
+ * fits inside default sockaddr_dl structure. However callback
+ * can allocate another sockaddr structure, in that case we need to
+ * free it later.
*/
llsa = NULL;
ll_ifma = NULL;
if (ifp->if_resolvemulti != NULL) {
+ /* Provide called function with buffer size information */
+ sdl.sdl_len = sizeof(sdl);
+ llsa = (struct sockaddr *)&sdl;
error = ifp->if_resolvemulti(ifp, &llsa, sa);
if (error)
goto unlock_out;
@@ -3155,14 +3284,14 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
(void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
}
- if (llsa != NULL)
- free(llsa, M_IFMADDR);
+ if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
+ link_free_sdl(llsa);
return (0);
free_llsa_out:
- if (llsa != NULL)
- free(llsa, M_IFMADDR);
+ if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
+ link_free_sdl(llsa);
unlock_out:
IF_ADDR_WUNLOCK(ifp);
@@ -3363,8 +3492,10 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
*
* At this time we only support certain types of interfaces,
* and we don't allow the length of the address to change.
+ *
+ * Set noinline to be dtrace-friendly
*/
-int
+__noinline int
if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
{
struct sockaddr_dl *sdl;
@@ -3422,17 +3553,45 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
ifr.ifr_flagshigh = ifp->if_flags >> 16;
(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
}
-#ifdef INET
- /*
- * Also send gratuitous ARPs to notify other nodes about
- * the address change.
- */
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- if (ifa->ifa_addr->sa_family == AF_INET)
- arp_ifinit(ifp, ifa);
- }
-#endif
}
+ EVENTHANDLER_INVOKE(iflladdr_event, ifp);
+ return (0);
+}
+
+/*
+ * Compat function for handling basic encapsulation requests.
+ * Not converted stacks (FDDI, IB, ..) supports traditional
+ * output model: ARP (and other similar L2 protocols) are handled
+ * inside output routine, arpresolve/nd6_resolve() returns MAC
+ * address instead of full prepend.
+ *
+ * This function creates calculated header==MAC for IPv4/IPv6 and
+ * returns EAFNOSUPPORT (which is then handled in ARP code) for other
+ * address families.
+ */
+static int
+if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req)
+{
+
+ if (req->rtype != IFENCAP_LL)
+ return (EOPNOTSUPP);
+
+ if (req->bufsize < req->lladdr_len)
+ return (ENOMEM);
+
+ switch (req->family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ /* Copy lladdr to storage as is */
+ memmove(req->buf, req->lladdr, req->lladdr_len);
+ req->bufsize = req->lladdr_len;
+ req->lladdr_off = 0;
+
return (0);
}
@@ -3500,15 +3659,15 @@ if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
IF_LOCK(ifq);
if (_IF_QFULL(ifq)) {
- _IF_DROP(ifq);
IF_UNLOCK(ifq);
+ if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
m_freem(m);
return (0);
}
if (ifp != NULL) {
- ifp->if_obytes += m->m_pkthdr.len + adjust;
+ if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len + adjust);
if (m->m_flags & (M_BCAST|M_MCAST))
- ifp->if_omcasts++;
+ if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
active = ifp->if_drv_flags & IFF_DRV_OACTIVE;
}
_IF_ENQUEUE(ifq, m);
@@ -3543,3 +3702,465 @@ if_deregister_com_alloc(u_char type)
if_com_alloc[type] = NULL;
if_com_free[type] = NULL;
}
+
+/* API for driver access to network stack owned ifnet.*/
+uint64_t
+if_setbaudrate(struct ifnet *ifp, uint64_t baudrate)
+{
+ uint64_t oldbrate;
+
+ oldbrate = ifp->if_baudrate;
+ ifp->if_baudrate = baudrate;
+ return (oldbrate);
+}
+
+uint64_t
+if_getbaudrate(if_t ifp)
+{
+
+ return (((struct ifnet *)ifp)->if_baudrate);
+}
+
+int
+if_setcapabilities(if_t ifp, int capabilities)
+{
+ ((struct ifnet *)ifp)->if_capabilities = capabilities;
+ return (0);
+}
+
+int
+if_setcapabilitiesbit(if_t ifp, int setbit, int clearbit)
+{
+ ((struct ifnet *)ifp)->if_capabilities |= setbit;
+ ((struct ifnet *)ifp)->if_capabilities &= ~clearbit;
+
+ return (0);
+}
+
+int
+if_getcapabilities(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_capabilities;
+}
+
+int
+if_setcapenable(if_t ifp, int capabilities)
+{
+ ((struct ifnet *)ifp)->if_capenable = capabilities;
+ return (0);
+}
+
+int
+if_setcapenablebit(if_t ifp, int setcap, int clearcap)
+{
+ if(setcap)
+ ((struct ifnet *)ifp)->if_capenable |= setcap;
+ if(clearcap)
+ ((struct ifnet *)ifp)->if_capenable &= ~clearcap;
+
+ return (0);
+}
+
+const char *
+if_getdname(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_dname;
+}
+
+int
+if_togglecapenable(if_t ifp, int togglecap)
+{
+ ((struct ifnet *)ifp)->if_capenable ^= togglecap;
+ return (0);
+}
+
+int
+if_getcapenable(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_capenable;
+}
+
+/*
+ * This is largely undesirable because it ties ifnet to a device, but does
+ * provide flexiblity for an embedded product vendor. Should be used with
+ * the understanding that it violates the interface boundaries, and should be
+ * a last resort only.
+ */
+int
+if_setdev(if_t ifp, void *dev)
+{
+ return (0);
+}
+
+int
+if_setdrvflagbits(if_t ifp, int set_flags, int clear_flags)
+{
+ ((struct ifnet *)ifp)->if_drv_flags |= set_flags;
+ ((struct ifnet *)ifp)->if_drv_flags &= ~clear_flags;
+
+ return (0);
+}
+
+int
+if_getdrvflags(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_drv_flags;
+}
+
+int
+if_setdrvflags(if_t ifp, int flags)
+{
+ ((struct ifnet *)ifp)->if_drv_flags = flags;
+ return (0);
+}
+
+
+int
+if_setflags(if_t ifp, int flags)
+{
+ ((struct ifnet *)ifp)->if_flags = flags;
+ return (0);
+}
+
+int
+if_setflagbits(if_t ifp, int set, int clear)
+{
+ ((struct ifnet *)ifp)->if_flags |= set;
+ ((struct ifnet *)ifp)->if_flags &= ~clear;
+
+ return (0);
+}
+
+int
+if_getflags(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_flags;
+}
+
+int
+if_clearhwassist(if_t ifp)
+{
+ ((struct ifnet *)ifp)->if_hwassist = 0;
+ return (0);
+}
+
+int
+if_sethwassistbits(if_t ifp, int toset, int toclear)
+{
+ ((struct ifnet *)ifp)->if_hwassist |= toset;
+ ((struct ifnet *)ifp)->if_hwassist &= ~toclear;
+
+ return (0);
+}
+
+int
+if_sethwassist(if_t ifp, int hwassist_bit)
+{
+ ((struct ifnet *)ifp)->if_hwassist = hwassist_bit;
+ return (0);
+}
+
+int
+if_gethwassist(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_hwassist;
+}
+
+int
+if_setmtu(if_t ifp, int mtu)
+{
+ ((struct ifnet *)ifp)->if_mtu = mtu;
+ return (0);
+}
+
+int
+if_getmtu(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_mtu;
+}
+
+int
+if_getmtu_family(if_t ifp, int family)
+{
+ struct domain *dp;
+
+ for (dp = domains; dp; dp = dp->dom_next) {
+ if (dp->dom_family == family && dp->dom_ifmtu != NULL)
+ return (dp->dom_ifmtu((struct ifnet *)ifp));
+ }
+
+ return (((struct ifnet *)ifp)->if_mtu);
+}
+
+int
+if_setsoftc(if_t ifp, void *softc)
+{
+ ((struct ifnet *)ifp)->if_softc = softc;
+ return (0);
+}
+
+void *
+if_getsoftc(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_softc;
+}
+
+void
+if_setrcvif(struct mbuf *m, if_t ifp)
+{
+ m->m_pkthdr.rcvif = (struct ifnet *)ifp;
+}
+
+void
+if_setvtag(struct mbuf *m, uint16_t tag)
+{
+ m->m_pkthdr.ether_vtag = tag;
+}
+
+uint16_t
+if_getvtag(struct mbuf *m)
+{
+
+ return (m->m_pkthdr.ether_vtag);
+}
+
+int
+if_sendq_empty(if_t ifp)
+{
+ return IFQ_DRV_IS_EMPTY(&((struct ifnet *)ifp)->if_snd);
+}
+
+struct ifaddr *
+if_getifaddr(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_addr;
+}
+
+int
+if_getamcount(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_amcount;
+}
+
+
+int
+if_setsendqready(if_t ifp)
+{
+ IFQ_SET_READY(&((struct ifnet *)ifp)->if_snd);
+ return (0);
+}
+
+int
+if_setsendqlen(if_t ifp, int tx_desc_count)
+{
+ IFQ_SET_MAXLEN(&((struct ifnet *)ifp)->if_snd, tx_desc_count);
+ ((struct ifnet *)ifp)->if_snd.ifq_drv_maxlen = tx_desc_count;
+
+ return (0);
+}
+
+int
+if_vlantrunkinuse(if_t ifp)
+{
+ return ((struct ifnet *)ifp)->if_vlantrunk != NULL?1:0;
+}
+
+int
+if_input(if_t ifp, struct mbuf* sendmp)
+{
+ (*((struct ifnet *)ifp)->if_input)((struct ifnet *)ifp, sendmp);
+ return (0);
+
+}
+
+/* XXX */
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN 6
+#endif
+
+int
+if_setupmultiaddr(if_t ifp, void *mta, int *cnt, int max)
+{
+ struct ifmultiaddr *ifma;
+ uint8_t *lmta = (uint8_t *)mta;
+ int mcnt = 0;
+
+ TAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+
+ if (mcnt == max)
+ break;
+
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ &lmta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN);
+ mcnt++;
+ }
+ *cnt = mcnt;
+
+ return (0);
+}
+
+int
+if_multiaddr_array(if_t ifp, void *mta, int *cnt, int max)
+{
+ int error;
+
+ if_maddr_rlock(ifp);
+ error = if_setupmultiaddr(ifp, mta, cnt, max);
+ if_maddr_runlock(ifp);
+ return (error);
+}
+
+int
+if_multiaddr_count(if_t ifp, int max)
+{
+ struct ifmultiaddr *ifma;
+ int count;
+
+ count = 0;
+ if_maddr_rlock(ifp);
+ TAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ count++;
+ if (count == max)
+ break;
+ }
+ if_maddr_runlock(ifp);
+ return (count);
+}
+
+int
+if_multi_apply(struct ifnet *ifp, int (*filter)(void *, struct ifmultiaddr *, int), void *arg)
+{
+ struct ifmultiaddr *ifma;
+ int cnt = 0;
+
+ if_maddr_rlock(ifp);
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
+ cnt += filter(arg, ifma, cnt);
+ if_maddr_runlock(ifp);
+ return (cnt);
+}
+
+struct mbuf *
+if_dequeue(if_t ifp)
+{
+ struct mbuf *m;
+ IFQ_DRV_DEQUEUE(&((struct ifnet *)ifp)->if_snd, m);
+
+ return (m);
+}
+
+int
+if_sendq_prepend(if_t ifp, struct mbuf *m)
+{
+ IFQ_DRV_PREPEND(&((struct ifnet *)ifp)->if_snd, m);
+ return (0);
+}
+
+int
+if_setifheaderlen(if_t ifp, int len)
+{
+ ((struct ifnet *)ifp)->if_hdrlen = len;
+ return (0);
+}
+
+caddr_t
+if_getlladdr(if_t ifp)
+{
+ return (IF_LLADDR((struct ifnet *)ifp));
+}
+
+void *
+if_gethandle(u_char type)
+{
+ return (if_alloc(type));
+}
+
+void
+if_bpfmtap(if_t ifh, struct mbuf *m)
+{
+ struct ifnet *ifp = (struct ifnet *)ifh;
+
+ BPF_MTAP(ifp, m);
+}
+
+void
+if_etherbpfmtap(if_t ifh, struct mbuf *m)
+{
+ struct ifnet *ifp = (struct ifnet *)ifh;
+
+ ETHER_BPF_MTAP(ifp, m);
+}
+
+void
+if_vlancap(if_t ifh)
+{
+ struct ifnet *ifp = (struct ifnet *)ifh;
+ VLAN_CAPABILITIES(ifp);
+}
+
+void
+if_setinitfn(if_t ifp, void (*init_fn)(void *))
+{
+ ((struct ifnet *)ifp)->if_init = init_fn;
+}
+
+void
+if_setioctlfn(if_t ifp, int (*ioctl_fn)(if_t, u_long, caddr_t))
+{
+ ((struct ifnet *)ifp)->if_ioctl = (void *)ioctl_fn;
+}
+
+void
+if_setstartfn(if_t ifp, void (*start_fn)(if_t))
+{
+ ((struct ifnet *)ifp)->if_start = (void *)start_fn;
+}
+
+void
+if_settransmitfn(if_t ifp, if_transmit_fn_t start_fn)
+{
+ ((struct ifnet *)ifp)->if_transmit = start_fn;
+}
+
+void if_setqflushfn(if_t ifp, if_qflush_fn_t flush_fn)
+{
+ ((struct ifnet *)ifp)->if_qflush = flush_fn;
+
+}
+
+void
+if_setgetcounterfn(if_t ifp, if_get_counter_t fn)
+{
+
+ ifp->if_get_counter = fn;
+}
+
+/* Revisit these - These are inline functions originally. */
+int
+drbr_inuse_drv(if_t ifh, struct buf_ring *br)
+{
+ return drbr_inuse(ifh, br);
+}
+
+struct mbuf*
+drbr_dequeue_drv(if_t ifh, struct buf_ring *br)
+{
+ return drbr_dequeue(ifh, br);
+}
+
+int
+drbr_needs_enqueue_drv(if_t ifh, struct buf_ring *br)
+{
+ return drbr_needs_enqueue(ifh, br);
+}
+
+int
+drbr_enqueue_drv(if_t ifh, struct buf_ring *br, struct mbuf *m)
+{
+ return drbr_enqueue(ifh, br, m);
+
+}