b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * CDDL HEADER START
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * The contents of this file are subject to the terms of the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Common Development and Distribution License (the "License").
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * You may not use this file except in compliance with the License.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * See the License for the specific language governing permissions
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * and limitations under the License.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * When distributing Covered Code, include this CDDL HEADER in each
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * If applicable, add the following below this CDDL HEADER, with the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * fields enclosed by brackets "[]" replaced with your own identifying
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * information: Portions Copyright [yyyy] [name of copyright owner]
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * CDDL HEADER END
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Use is subject to license terms.
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill * Copyright (c) 2016, Joyent, Inc. All rights reserved.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * The ipnet device defined here provides access to packets at the IP layer. To
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * provide access to packets at this layer it registers a callback function in
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * the ip module and when there are open instances of the device ip will pass
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * packets into the device. Packets from ip are passed on the input, output and
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * loopback paths. Internally the module returns to ip as soon as possible by
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * deferring processing using a taskq.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Management of the devices in /dev/ipnet/ is handled by the devname
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * filesystem and use of the neti interfaces. This module registers for NIC
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * events using the neti framework so that when IP interfaces are bought up,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * taken down etc. the ipnet module is notified and its view of the interfaces
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * configured on the system adjusted. On attach, the module gets an initial
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * view of the system again using the neti framework but as it has already
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * registered for IP interface events, it is still up-to-date with any changes.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk 0, /* mi_minpsz */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk 0 /* mi_lowat */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * List to hold static view of ipnetif_t's on the system. This is needed to
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * avoid holding the lock protecting the avl tree of ipnetif's over the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * callback into the dev filesystem.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Convenience enumerated type for ipnet_accept(). It describes the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * properties of a given ipnet_addrp_t relative to a single ipnet_t
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * client stream. The values represent whether the address is ...
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirktypedef enum {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk IPNETADDR_MYADDR, /* an address on my ipnetif_t. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk IPNETADDR_MBCAST, /* a multicast or broadcast address. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* Argument used for the ipnet_nicevent_taskq callback. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic ddi_taskq_t *ipnet_taskq; /* taskq for packets */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic ddi_taskq_t *ipnet_nicevent_taskq; /* taskq for NIC events */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic const int IPNET_MINOR_LO = 1; /* minor number for /dev/lo0 */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic const int IPNET_MINOR_MIN = 2; /* start of dynamic minors */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic dl_info_ack_t ipnet_infoack = IPNET_INFO_ACK_INIT;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic ipnet_acceptfn_t ipnet_accept, ipnet_loaccept;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_open(queue_t *, dev_t *, int, int, cred_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_wputnondata(queue_t *, mblk_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_attach(dev_info_t *, ddi_attach_cmd_t);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_detach(dev_info_t *, ddi_detach_cmd_t);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_inforeq(queue_t *q, mblk_t *mp);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_bindreq(queue_t *q, mblk_t *mp);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_unbindreq(queue_t *q, mblk_t *mp);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_dlpromisconreq(queue_t *q, mblk_t *mp);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_dlpromiscoffreq(queue_t *q, mblk_t *mp);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_join_allmulti(ipnetif_t *, ipnet_stack_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_leave_allmulti(ipnetif_t *, ipnet_stack_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_nicevent_cb(hook_event_token_t, hook_data_t, void *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_nicevent_task(void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic ipnetif_t *ipnetif_create(const char *, uint64_t, ipnet_stack_t *,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void ipnetif_remove(ipnetif_t *, ipnet_stack_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic ipnetif_addr_t *ipnet_match_lif(ipnetif_t *, lif_if_t, boolean_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic ipnetif_t *ipnetif_getby_index(uint64_t, ipnet_stack_t *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic ipnetif_t *ipnetif_getby_dev(dev_t, ipnet_stack_t *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic boolean_t ipnetif_in_zone(ipnetif_t *, zoneid_t, ipnet_stack_t *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void ipnetif_zonecheck(ipnetif_t *, ipnet_stack_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic int ipnet_populate_if(net_handle_t, ipnet_stack_t *, boolean_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int ipnetif_compare_name(const void *, const void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int ipnetif_compare_name_zone(const void *, const void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int ipnetif_compare_index(const void *, const void *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_add_ifaddr(uint64_t, ipnetif_t *, net_handle_t);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_delete_ifaddr(ipnetif_addr_t *, ipnetif_t *, boolean_t);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_register_netihook(ipnet_stack_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void *ipnet_stack_init(netstackid_t, netstack_t *);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void ipnet_stack_fini(netstackid_t, void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void ipnet_dispatch(void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int ipobs_bounce_func(hook_event_token_t, hook_data_t, void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int ipnet_bpf_bounce(hook_event_token_t, hook_data_t, void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic ipnetif_t *ipnetif_clone_create(ipnetif_t *, zoneid_t);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip KirkDDI_DEFINE_STREAM_OPS(ipnet_ops, nulldev, nulldev, ipnet_attach,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_detach, nodev, ipnet_devinfo, D_MP | D_MTPERMOD, &ipnet_info,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk "STREAMS ipnet driver",
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This structure contains the template data (names and type) that is
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * copied, in bulk, into the new kstats structure created by net_kstat_create.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * No actual statistical information is stored in this instance of the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ipnet_kstats_t structure.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Walk the list of physical interfaces on the machine, for each
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * interface create a new ipnetif_t and add any addresses to it. We
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * need to do the walk twice, once for IPv4 and once for IPv6.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * The interfaces are destroyed as part of ipnet_stack_fini() for each
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * stack. Note that we cannot do this initialization in
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * ipnet_stack_init(), since ipnet_stack_init() cannot fail.
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy if ((ret = ipnet_populate_if(ips->ips_ndv4, ips, B_FALSE)) == 0)
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy ret = ipnet_populate_if(ips->ips_ndv6, ips, B_TRUE);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Standard module entry points.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ipnet_major = ddi_name_to_major("ipnet")) == (major_t)-1)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_minor_space = id_space_create("ipnet_minor_space",
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * We call ddi_taskq_create() with nthread == 1 to ensure in-order
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * delivery of packets to clients. Note that we need to create the
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * taskqs before calling netstack_register() since ipnet_stack_init()
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * registers callbacks that use 'em.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_taskq = ddi_taskq_create(NULL, "ipnet", 1, TASKQ_DEFAULTPRI, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_nicevent_taskq = ddi_taskq_create(NULL, "ipnet_nic_event_queue",
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (ipnet_taskq == NULL || ipnet_nicevent_taskq == NULL) {
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem netstack_register(NS_IPNET, ipnet_stack_init, NULL, ipnet_stack_fini);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk HOOK_INIT(ips->ips_nicevents, ipnet_nicevent_cb, "ipnet_nicevents",
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * It is possible for an exclusive stack to be in the process of
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * shutting down here, and the netid and protocol lookups could fail
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * in that case.
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy zoneid = netstackid_to_zoneid(ips->ips_netstack->netstack_stackid);
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy if ((netid = net_zoneidtonetid(zoneid)) == -1)
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy if ((ips->ips_ndv4 = net_protocol_lookup(netid, NHF_INET)) != NULL) {
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy if ((ret = net_hook_register(ips->ips_ndv4, NH_NIC_EVENTS,
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy VERIFY(net_protocol_release(ips->ips_ndv4) == 0);
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy cmn_err(CE_WARN, "unable to register IPv4 netinfo hooks"
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy if ((ips->ips_ndv6 = net_protocol_lookup(netid, NHF_INET6)) != NULL) {
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy if ((ret = net_hook_register(ips->ips_ndv6, NH_NIC_EVENTS,
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy VERIFY(net_protocol_release(ips->ips_ndv6) == 0);
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy cmn_err(CE_WARN, "unable to register IPv6 netinfo hooks"
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Create a local set of kstats for each zone.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ips->ips_kstatp = net_kstat_create(netid, "ipnet", 0, "ipnet_stats",
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (ipnet_kstats_t) / sizeof (kstat_named_t), 0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void *)(uintptr_t)ips->ips_netstack->netstack_stackid;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cmn_err(CE_WARN, "net_kstat_create(%s,%s,%s) failed",
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * This function is called on attach to build an initial view of the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * interfaces on the system. It will be called once for IPv4 and once
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * for IPv6, although there is only one ipnet interface for both IPv4
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * and IPv6 there are separate address lists.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_populate_if(net_handle_t nd, ipnet_stack_t *ips, boolean_t isv6)
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * If ipnet_register_netihook() was unable to initialize this
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * stack's net_handle_t, then we cannot populate any interface
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * information. This usually happens when we attempted to
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * grab a net_handle_t as a stack was shutting down. We don't
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * want to fail the entire _init() operation because of a
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * stack shutdown (other stacks will continue to work just
133be3055da09253fc544763dcb744957f1f6319Sebastien Roy * fine), so we silently return success here.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Make sure we're not processing NIC events during the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * population of our interfaces and address lists.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (net_getifname(nd, phyif, name, LIFNAMSIZ) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ipnetif = ipnetif_getby_index(phyif, ips)) == NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ipnetif = ipnetif_create(name, phyif, ips, ifflags);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk isv6 ? IPNETIF_IPV6PLUMBED : IPNETIF_IPV4PLUMBED;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk for (lif = net_lifgetnext(nd, phyif, 0); lif != 0;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Skip addresses that aren't up. We'll add
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * them when we receive an NE_LIF_UP event.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (net_getlifflags(nd, phyif, lif, &ifflags) != 0 ||
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* Don't add it if we already have it. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (ipnet_match_lif(ipnetif, lif, isv6) != NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (ddi_create_minor_node(dip, "lo0", S_IFCHR, IPNET_MINOR_LO,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* ARGSUSED */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk *result = (void *)0;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* ARGSUSED */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_open(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * If the system is labeled, only the global zone is allowed to open
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * IP observability nodes.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (is_system_labeled() && zoneid != GLOBAL_ZONEID)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* We don't support open as a module */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* This driver is self-cloning, we don't support re-open. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ipnet = kmem_zalloc(sizeof (*ipnet), KM_NOSLEEP)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY((ns = netstack_find_by_cred(crp)) != NULL);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet->ipnet_minor = (minor_t)id_alloc(ipnet_minor_space);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * We need to hold ips_event_lock here as any NE_LIF_DOWN events need
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * to be processed after ipnet_if is set and the ipnet_t has been
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * inserted in the ips_str_list.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed !ipnetif_in_zone(ipnet->ipnet_if, zoneid, ips)) {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk cv_wait(&ips->ips_walkers_cv, &ips->ips_walkers_lock);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk *dev = makedevice(getmajor(*dev), ipnet->ipnet_minor);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Only register our callback if we're the first open client; we call
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * unregister in close() for the last open client.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (list_head(&ips->ips_str_list) == list_tail(&ips->ips_str_list))
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ips->ips_hook = ipobs_register_hook(ns, ipnet_input);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_stack_t *ips = ipnet->ipnet_ns->netstack_ipnet;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk cv_wait(&ips->ips_walkers_cv, &ips->ips_walkers_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ipobs_unregister_hook(ips->ips_netstack, ips->ips_hook);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* Fallthrough, we don't support I_STR with DLIOCIPNETINFO. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk size_t size = sizeof (dl_info_ack_t) + sizeof (ushort_t);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*NOTREACHED*/
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dlbindack(q, mp, dlp->bind_req.dl_sap, 0, 0, 0, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_UNBIND_REQ, DL_BADPRIM, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (level == DL_PROMISC_PHYS || level == DL_PROMISC_MULTI) {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_PROMISCON_REQ, DL_SYSERR, err);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (level == DL_PROMISC_PHYS || level == DL_PROMISC_MULTI) {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_join_allmulti(ipnetif_t *ipnetif, ipnet_stack_t *ips)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ip_stack_t *ipst = ips->ips_netstack->netstack_ip;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk (IPNETIF_IPV4ALLMULTI | IPNETIF_IPV6ALLMULTI)) == 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_leave_allmulti(ipnetif_t *ipnetif, ipnet_stack_t *ips)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ip_stack_t *ipst = ips->ips_netstack->netstack_ip;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Allocate a new mblk_t and put a dl_ipnetinfo_t in it.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The structure it copies the header information from,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * hook_pkt_observe_t, is constructed using network byte
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * order in ipobs_hook(), so there is no conversion here.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_addheader(hook_pkt_observe_t *hdr, mblk_t *mp)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((dlhdr = allocb(sizeof (dl_ipnetinfo_t), BPRI_HI)) == NULL) {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_get_addrtype(ipnet_t *ipnet, ipnet_addrp_t *addr)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* First check if the address is multicast or limited broadcast. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Walk the address list to see if the address belongs to our
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * interface or is one of our subnet broadcast addresses.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk &ipnetif->if_ip4addr_list : &ipnetif->if_ip6addr_list;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ifaddr != NULL && addrtype == IPNETADDR_UNKNOWN;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * If we're not in the global zone, then only look at
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * addresses in our zone.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Verify if the packet contained in hdr should be passed up to the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * ipnet client stream.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_accept(ipnet_t *ipnet, hook_pkt_observe_t *hdr, ipnet_addrp_t *src,
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * If the packet's ifindex matches ours, or the packet's group ifindex
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * matches ours, it's on the interface we're observing. (Thus,
e11c3f44f531fdff80941ce57c065d2ae861cefcmeem * observing on the group ifindex matches all ifindexes in the group.)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ipnet_addrtype_t, srctype, ipnet_addrp_t *, src,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ipnet_addrtype_t, dsttype, ipnet_addrp_t *, dst,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Do not allow an ipnet stream to see packets that are not from or to
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * its zone. The exception is when zones are using the shared stack
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * model. In this case, streams in the global zone have visibility
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * into other shared-stack zones, and broadcast and multicast traffic
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * is visible by all zones in the stack.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (ipnet->ipnet_zoneid != ntohl(hdr->hpo_zsrc) &&
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * If DL_PROMISC_SAP isn't enabled, then the bound SAP must match the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * packet's IP version.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (!(ipnet->ipnet_flags & IPNET_PROMISC_SAP) &&
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* If the destination address is ours, then accept the packet. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * If DL_PROMISC_PHYS is enabled, then we can see all packets that are
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * sent or received on the interface we're observing, or packets that
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * have our source address (this allows us to see packets we send).
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * We accept multicast and broadcast packets transmitted or received
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * on the interface we're observing.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Verify if the packet contained in hdr should be passed up to the ipnet
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * client stream that's in IPNET_LOMODE.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_loaccept(ipnet_t *ipnet, hook_pkt_observe_t *hdr, ipnet_addrp_t *src,
fc5884fc5cbeced353b19c8153bd02be0d801d97Darren Reed if (hdr->hpo_htype != htons(IPOBS_HOOK_LOCAL)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ipnet_if is only NULL for IPNET_MINOR_LO devices.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * An ipnet stream must not see packets that are not from/to its zone.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (ipnet->ipnet_zoneid != ntohl(hdr->hpo_zsrc) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hook_pkt_observe_t *hdr = (hook_pkt_observe_t *)mp->b_rptr;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ips = ((netstack_t *)hdr->hpo_ctx)->netstack_ipnet;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed src.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_src;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dst.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_dst;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed src.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_src;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dst.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_dst;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!(*ipnet->ipnet_acceptfn)(ipnet, hdr, &src, &dst)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((netmp = dupmsg(hdr->hpo_pkt->b_cont)) == NULL &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (netmp = copymsg(hdr->hpo_pkt->b_cont)) == NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((netmp = ipnet_addheader(hdr, netmp)) == NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hook_pkt_observe_t *hdr = (hook_pkt_observe_t *)mp->b_rptr;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ips = ((netstack_t *)hdr->hpo_ctx)->netstack_ipnet;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (ddi_taskq_dispatch(ipnet_taskq, ipnet_dispatch, mp, DDI_NOSLEEP) !=
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ipnetif = kmem_zalloc(sizeof (*ipnetif), KM_NOSLEEP)) == NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_init(&ipnetif->if_addr_lock, NULL, MUTEX_DEFAULT, 0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed list_create(&ipnetif->if_ip4addr_list, sizeof (ipnetif_addr_t),
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed list_create(&ipnetif->if_ip6addr_list, sizeof (ipnetif_addr_t),
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_init(&ipnetif->if_reflock, NULL, MUTEX_DEFAULT, 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Create a new ipnetif_t and new minor node for it. If creation is
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * successful the new ipnetif_t is inserted into an avl_tree
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * containing ipnetif's for this stack instance.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_create(const char *name, uint64_t index, ipnet_stack_t *ips,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Because ipnetif_create() can be called from a NIC event
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * callback, it should not block.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ifminor = (minor_t)id_alloc_nosleep(ipnet_minor_space);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk (void) strlcpy(ipnetif->if_name, name, LIFNAMSIZ);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ipnetif->if_zoneid = netstack_get_zoneid(ips->ips_netstack);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnetif->if_dev = makedevice(ipnet_major, ifminor);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY(avl_find(&ips->ips_avl_by_index, &index, &where) == NULL);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk avl_insert(&ips->ips_avl_by_index, ipnetif, where);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY(avl_find(&ips->ips_avl_by_name, (void *)name, &where) == NULL);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk avl_insert(&ips->ips_avl_by_name, ipnetif, where);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_remove(ipnetif_t *ipnetif, ipnet_stack_t *ips)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* Send a SIGHUP to all open streams associated with this ipnetif. */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk for (ipnet = list_head(&ips->ips_str_list); ipnet != NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Release the reference we implicitly held in ipnetif_create().
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk /* Remove IPv4/v6 address lists from the ipnetif */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_purge_addrlist(&ipnetif->if_ip4addr_list);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_purge_addrlist(&ipnetif->if_ip6addr_list);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed id_free(ipnet_minor_space, getminor(ipnetif->if_dev));
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Create an ipnetif_addr_t with the given logical interface id (lif)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * and add it to the supplied ipnetif. The lif is the netinfo
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * representation of logical interface id, and we use this id to match
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * incoming netinfo events against our lists of addresses.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_add_ifaddr(uint64_t lif, ipnetif_t *ipnetif, net_handle_t nd)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (net_getlifaddr(nd, phyif, lif, 1, &type, &addr) != 0 ||
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ifaddr = kmem_alloc(sizeof (*ifaddr), KM_NOSLEEP)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Try and get the broadcast address. Note that it's okay for
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * an interface to not have a broadcast address, so we don't
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * fail the entire operation if net_getlifaddr() fails here.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (net_getlifaddr(nd, phyif, lif, 1, &type, &bcast) == 0)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ifaddr->ifa_ip6addr = ((struct sockaddr_in6 *)&addr)->sin6_addr;
7b57f05abb8796d3c91c8d4d4c75dcafb5af6b69Darren Reed * The zoneid stored in ipnetif_t needs to correspond to the actual
7b57f05abb8796d3c91c8d4d4c75dcafb5af6b69Darren Reed * zone the address is being used in. This facilitates finding the
7b57f05abb8796d3c91c8d4d4c75dcafb5af6b69Darren Reed * correct netstack_t pointer, amongst other things, later.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk &ipnetif->if_ip4addr_list : &ipnetif->if_ip6addr_list, ifaddr);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_delete_ifaddr(ipnetif_addr_t *ifaddr, ipnetif_t *ipnetif, boolean_t isv6)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk &ipnetif->if_ip6addr_list : &ipnetif->if_ip4addr_list, ifaddr);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_plumb_ev(ipnet_nicevent_t *ipne, ipnet_stack_t *ips, boolean_t isv6)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) net_getlifflags(ipne->ipne_protocol, ifindex, 0, &ifflags);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ipnetif = ipnetif_create(ifname, ifindex, ips, ifflags);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk isv6 ? IPNETIF_IPV6PLUMBED : IPNETIF_IPV4PLUMBED;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk isv6 ? IPNETIF_IPV6ALLMULTI : IPNETIF_IPV4ALLMULTI;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_unplumb_ev(uint64_t ifindex, ipnet_stack_t *ips, boolean_t isv6)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk &ipnetif->if_ip6addr_list : &ipnetif->if_ip4addr_list);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Note that we have one ipnetif for both IPv4 and IPv6, but we receive
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * separate NE_UNPLUMB events for IPv4 and IPv6. We remove the ipnetif
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * if both IPv4 and IPv6 interfaces have been unplumbed.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnetif->if_flags &= isv6 ? ~IPNETIF_IPV6PLUMBED : ~IPNETIF_IPV4PLUMBED;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (!(ipnetif->if_flags & (IPNETIF_IPV4PLUMBED | IPNETIF_IPV6PLUMBED)))
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_lifup_ev(uint64_t ifindex, uint64_t lifindex, net_handle_t nd,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ifaddr = ipnet_match_lif(ipnetif, lifindex, isv6)) != NULL) {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * We must have missed a NE_LIF_DOWN event. Delete this
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * ifaddr and re-create it.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_lifdown_ev(uint64_t ifindex, uint64_t lifindex, ipnet_stack_t *ips,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ifaddr = ipnet_match_lif(ipnetif, lifindex, isv6)) != NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Make sure that open streams on this ipnetif are still allowed to
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * have it open.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * This callback from the NIC event framework dispatches a taskq as the event
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * handlers may block.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* ARGSUSED */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_nicevent_cb(hook_event_token_t token, hook_data_t info, void *arg)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk hook_nic_event_t *hn = (hook_nic_event_t *)info;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ipne = kmem_alloc(sizeof (ipnet_nicevent_t), KM_NOSLEEP)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipne->ipne_stackid = ips->ips_netstack->netstack_stackid;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk (void) ddi_taskq_dispatch(ipnet_nicevent_taskq, ipnet_nicevent_task,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ns = netstack_find_by_stackid(ipne->ipne_stackid)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_unplumb_ev(ipne->ipne_ifindex, ips, isv6);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_lifup_ev(ipne->ipne_ifindex, ipne->ipne_lifindex,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_lifdown_ev(ipne->ipne_ifindex, ipne->ipne_lifindex, ips,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (is_system_labeled() && zoneid != GLOBAL_ZONEID)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ns = netstack_find_by_zoneid(zoneid)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ipnetif = avl_find(&ips->ips_avl_by_name, name, NULL)) != NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_getby_index(uint64_t id, ipnet_stack_t *ips)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ipnetif = avl_find(&ips->ips_avl_by_index, &id, NULL)) != NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk for (ipnetif = avl_first(tree); ipnetif != NULL;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_match_lif(ipnetif_t *ipnetif, lif_if_t lid, boolean_t isv6)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk list = isv6 ? &ipnetif->if_ip6addr_list : &ipnetif->if_ip4addr_list;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* ARGSUSED */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkstatic void *
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_stack_init(netstackid_t stackid, netstack_t *ns)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk mutex_init(&ips->ips_avl_lock, NULL, MUTEX_DEFAULT, 0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed avl_create(&ips->ips_avl_by_index, ipnetif_compare_index,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk sizeof (ipnetif_t), offsetof(ipnetif_t, if_avl_by_index));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed avl_create(&ips->ips_avl_by_name, ipnetif_compare_name,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk sizeof (ipnetif_t), offsetof(ipnetif_t, if_avl_by_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed avl_create(&ips->ips_avl_by_shared, ipnetif_compare_name_zone,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (ipnetif_t), offsetof(ipnetif_t, if_avl_by_shared));
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk mutex_init(&ips->ips_walkers_lock, NULL, MUTEX_DEFAULT, NULL);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk cv_init(&ips->ips_walkers_cv, NULL, CV_DRIVER, NULL);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk list_create(&ips->ips_str_list, sizeof (ipnet_t),
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* ARGSUSED */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_stack_fini(netstackid_t stackid, void *arg)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed net_kstat_delete(net_zoneidtonetid(zoneid), ips->ips_kstatp);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY(net_hook_unregister(ips->ips_ndv4, NH_NIC_EVENTS,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY(net_protocol_release(ips->ips_ndv4) == 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY(net_hook_unregister(ips->ips_ndv6, NH_NIC_EVENTS,
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk VERIFY(net_protocol_release(ips->ips_ndv6) == 0);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk for (ipnetif = avl_first(&ips->ips_avl_by_index); ipnetif != NULL;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk nipnetif = AVL_NEXT(&ips->ips_avl_by_index, ipnetif);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* Do any of the addresses in addrlist belong the supplied zoneid? */
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_addrs_in_zone(list_t *addrlist, zoneid_t zoneid)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk/* Should the supplied ipnetif be visible from the supplied zoneid? */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_in_zone(ipnetif_t *ipnetif, zoneid_t zoneid, ipnet_stack_t *ips)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * The global zone has visibility into all interfaces in the global
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * stack, and exclusive stack zones have visibility into all
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * interfaces in their stack.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ips->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Shared-stack zones only have visibility for interfaces that have
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * addresses in their zone.
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ret = ipnet_addrs_in_zone(&ipnetif->if_ip4addr_list, zoneid) ||
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnet_addrs_in_zone(&ipnetif->if_ip6addr_list, zoneid);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * Verify that any ipnet_t that has a reference to the supplied ipnetif should
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * still be allowed to have it open. A given ipnet_t may no longer be allowed
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * to have an ipnetif open if there are no longer any addresses that belong to
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * the ipnetif in the ipnet_t's non-global shared-stack zoneid. If that's the
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * case, send the ipnet_t an M_HANGUP.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_zonecheck(ipnetif_t *ipnetif, ipnet_stack_t *ips)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!ipnetif_in_zone(ipnetif, ipnet->ipnet_zoneid, ips))
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirkipnet_walk_if(ipnet_walkfunc_t *cb, void *arg, zoneid_t zoneid)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk * On labeled systems, non-global zones shouldn't see anything
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if (is_system_labeled() && zoneid != GLOBAL_ZONEID)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk if ((ns = netstack_find_by_zoneid(zoneid)) == NULL)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk for (ipnetif = avl_first(&ips->ips_avl_by_index); ipnetif != NULL;
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk ipnetif = avl_walk(&ips->ips_avl_by_index, ipnetif, AVL_AFTER)) {
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk cbnode = kmem_zalloc(sizeof (ipnetif_cbdata_t), KM_SLEEP);
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk (void) strlcpy(cbnode->ic_ifname, ipnetif->if_name, LIFNAMSIZ);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_compare_index(const void *index_ptr, const void *ipnetifp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int64_t index2 = (int64_t)((ipnetif_t *)ipnetifp)->if_index;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_compare_name(const void *name_ptr, const void *ipnetifp)
b127ac411761a3d8d642d9342d9cac2785e1faaaPhilip Kirk res = strcmp(((ipnetif_t *)ipnetifp)->if_name, name_ptr);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_compare_name_zone(const void *key_ptr, const void *ipnetifp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipobs_bounce_func(hook_event_token_t token, hook_data_t info, void *arg)
dbed73cbda2229fd1aa6dc5743993cae7f0a7ee9Sangeeta Misra * Code in ip_input() expects that it is the only one accessing the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed HOOK_INIT(hook, ipobs_bounce_func, "", (void *)func);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * To register multiple hooks with he same callback function,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * a unique name is needed.
391710f23076bd83c9cf29287fda8576773aec1eDarren Reed (void) snprintf(name, sizeof (name), "ipobserve_%p", (void *)hook);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) net_hook_register(ipst->ips_ip4_observe_pr, NH_OBSERVE, hook);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) net_hook_register(ipst->ips_ip6_observe_pr, NH_OBSERVE, hook);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipobs_unregister_hook(netstack_t *ns, hook_t *hook)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) net_hook_unregister(ipst->ips_ip4_observe_pr, NH_OBSERVE, hook);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) net_hook_unregister(ipst->ips_ip6_observe_pr, NH_OBSERVE, hook);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ******************************************************************** */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* BPF Functions below */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ******************************************************************** */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Convenience function to make mapping a zoneid to an ipnet_stack_t easy.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed VERIFY((ns = netstack_find_by_zoneid(zoneid)) != NULL);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * Functions, such as the above ipnet_find_by_zoneid(), will return a
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * pointer to ipnet_stack_t by calling a netstack lookup function.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * The netstack_find_*() functions return a pointer after doing a "hold"
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * on the data structure and thereby require a "release" when the caller
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * is finished with it. We need to mirror that API here and thus a caller
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * of ipnet_find_by_zoneid() is required to call ipnet_rele().
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The list of interfaces available via ipnet is private for each zone,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * so the AVL tree of each zone must be searched for a given name, even
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * if all names are unique.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_open_byname(const char *name, ipnetif_t **ptr, zoneid_t zoneid)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed VERIFY((ips = ipnet_find_by_zoneid(zoneid)) != NULL);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * Shared instance zone?
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (netstackid_to_zoneid(zoneid_to_netstackid(zoneid)) != zoneid) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed ipnetif = avl_find(&ips->ips_avl_by_shared, (void *)key, NULL);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed ipnetif = avl_find(&ips->ips_avl_by_name, (void *)name, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * To find the linkid for a given name, it is necessary to know which zone
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the interface name belongs to and to search the avl tree for that zone
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * as there is no master list of all interfaces and which zone they belong
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to. It is assumed that the caller of this function is somehow already
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * working with the ipnet interfaces and hence the ips_event_lock is held.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * When BPF calls into this function, it is doing so because of an event
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * in ipnet, and thus ipnet holds the ips_event_lock. Thus the datalink id
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * value returned has meaning without the need for grabbing a hold on the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * owning structure.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_get_linkid_byname(const char *name, uint_t *idp, zoneid_t zoneid)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed VERIFY((ips = ipnet_find_by_zoneid(zoneid)) != NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ifp = avl_find(&ips->ips_avl_by_name, (void *)name, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Shared instance zone?
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (netstackid_to_zoneid(zoneid_to_netstackid(zoneid)) != zoneid) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ifp = avl_find(&ips->ips_avl_by_shared, (void *)key, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Strictly speaking, there is no such thing as a "client" in ipnet, like
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * there is in mac. BPF only needs to have this because it is required as
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * part of interfacing correctly with mac. The reuse of the original
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ipnetif_t as a client poses no danger, so long as it is done with its
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * own ref-count'd hold that is given up on close.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_client_open(ipnetif_t *ptr, ipnetif_t **result)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This is called from BPF when it needs to start receiving packets
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * from ipnet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The use of the ipnet_t structure here is somewhat lightweight when
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * compared to how it is used elsewhere but it already has all of the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * right fields in it, so reuse here doesn't seem out of order. Its
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * primary purpose here is to provide the means to store pointers for
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * use when ipnet_promisc_remove() needs to be called.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This should never be called for the IPNET_MINOR_LO device as it is
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * never created via ipnetif_create.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_promisc_add(void *handle, uint_t how, void *data, uintptr_t *mhandle,
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill if (how != DL_PROMISC_PHYS && how != DL_PROMISC_MULTI)
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill ns = netstack_find_by_zoneid(ifp->if_zoneid);
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill if ((error = ipnet_join_allmulti(ifp, ns->netstack_ipnet)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * To register multiple hooks with the same callback function,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * a unique name is needed.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed HOOK_INIT(ipnet->ipnet_hook, ipnet_bpf_bounce, "", ipnet);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) snprintf(name, sizeof (name), "ipnet_promisc_%p",
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = net_hook_register(ipst->ips_ip4_observe_pr, NH_OBSERVE,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = net_hook_register(ipst->ips_ip6_observe_pr, NH_OBSERVE,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) net_hook_unregister(ipst->ips_ip4_observe_pr,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cmn_err(CE_WARN, "net_hook_register failed: %d", error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed VERIFY(net_hook_unregister(ipst->ips_ip4_observe_pr, NH_OBSERVE,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed VERIFY(net_hook_unregister(ipst->ips_ip6_observe_pr, NH_OBSERVE,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * arg here comes from the ipnet_t allocated in ipnet_promisc_add.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * An important field from that structure is "ipnet_data" that
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * contains the "data" pointer passed into ipnet_promisc_add: it needs
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to be passed back to bpf when we call into ipnet_itap.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ipnet_itap is set by ipnet_set_bpfattach, which in turn is called
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnet_bpf_bounce(hook_event_token_t token, hook_data_t info, void *arg)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ips = ((netstack_t *)hdr->hpo_ctx)->netstack_ipnet;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed src.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_src;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dst.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_dst;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed src.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_src;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dst.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_dst;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!(*ipnet->ipnet_acceptfn)(ipnet, hdr, &src, &dst)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * clone'd ipnetif_t's are created when a shared IP instance zone comes
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to life and configures an IP address. The model that BPF uses is that
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * each interface must have a unique pointer and each interface must be
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * representative of what it can capture. They are limited to one DLT
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * per interface and one zone per interface. Thus every interface that
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * can be seen in a zone must be announced via an attach to bpf. For
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * shared instance zones, this means the ipnet driver needs to detect
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * when an address is added to an interface in a zone for the first
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * time (and also when the last address is removed.)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedipnetif_clone_create(ipnetif_t *ifp, zoneid_t zoneid)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uintptr_t key[2] = { zoneid, (uintptr_t)ifp->if_name };
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed newif = avl_find(&ips->ips_avl_by_shared, (void *)key, &where);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) strlcpy(newif->if_name, ifp->if_name, LIFNAMSIZ);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed newif->if_flags = ifp->if_flags & IPNETIF_LOOPBACK;