15373Sraghuram /*
25373Sraghuram * CDDL HEADER START
35373Sraghuram *
45373Sraghuram * The contents of this file are subject to the terms of the
55373Sraghuram * Common Development and Distribution License (the "License").
65373Sraghuram * You may not use this file except in compliance with the License.
75373Sraghuram *
85373Sraghuram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95373Sraghuram * or http://www.opensolaris.org/os/licensing.
105373Sraghuram * See the License for the specific language governing permissions
115373Sraghuram * and limitations under the License.
125373Sraghuram *
135373Sraghuram * When distributing Covered Code, include this CDDL HEADER in each
145373Sraghuram * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155373Sraghuram * If applicable, add the following below this CDDL HEADER, with the
165373Sraghuram * fields enclosed by brackets "[]" replaced with your own identifying
175373Sraghuram * information: Portions Copyright [yyyy] [name of copyright owner]
185373Sraghuram *
195373Sraghuram * CDDL HEADER END
205373Sraghuram */
215373Sraghuram
225373Sraghuram /*
23*12300SSriharsha.Basavapatna@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245373Sraghuram */
255373Sraghuram
265373Sraghuram #include <sys/types.h>
275373Sraghuram #include <sys/errno.h>
285373Sraghuram #include <sys/debug.h>
295373Sraghuram #include <sys/time.h>
305373Sraghuram #include <sys/sysmacros.h>
315373Sraghuram #include <sys/systm.h>
325373Sraghuram #include <sys/user.h>
335373Sraghuram #include <sys/stropts.h>
345373Sraghuram #include <sys/stream.h>
355373Sraghuram #include <sys/strlog.h>
365373Sraghuram #include <sys/strsubr.h>
375373Sraghuram #include <sys/cmn_err.h>
385373Sraghuram #include <sys/cpu.h>
395373Sraghuram #include <sys/kmem.h>
405373Sraghuram #include <sys/conf.h>
415373Sraghuram #include <sys/ddi.h>
425373Sraghuram #include <sys/sunddi.h>
435373Sraghuram #include <sys/ksynch.h>
445373Sraghuram #include <sys/stat.h>
455373Sraghuram #include <sys/kstat.h>
465373Sraghuram #include <sys/vtrace.h>
475373Sraghuram #include <sys/strsun.h>
485373Sraghuram #include <sys/dlpi.h>
495373Sraghuram #include <sys/ethernet.h>
505373Sraghuram #include <net/if.h>
515373Sraghuram #include <sys/varargs.h>
525373Sraghuram #include <sys/machsystm.h>
535373Sraghuram #include <sys/modctl.h>
545373Sraghuram #include <sys/modhash.h>
555373Sraghuram #include <sys/mac.h>
565373Sraghuram #include <sys/mac_ether.h>
575373Sraghuram #include <sys/taskq.h>
585373Sraghuram #include <sys/note.h>
595373Sraghuram #include <sys/mach_descrip.h>
605373Sraghuram #include <sys/mdeg.h>
615373Sraghuram #include <sys/ldc.h>
625373Sraghuram #include <sys/vsw_fdb.h>
635373Sraghuram #include <sys/vsw.h>
645373Sraghuram #include <sys/vio_mailbox.h>
655373Sraghuram #include <sys/vnet_mailbox.h>
665373Sraghuram #include <sys/vnet_common.h>
675373Sraghuram #include <sys/vio_util.h>
685373Sraghuram #include <sys/sdt.h>
695373Sraghuram #include <sys/atomic.h>
706419Ssb155480 #include <sys/vlan.h>
715373Sraghuram
725373Sraghuram /* Switching setup routines */
738370SSriharsha.Basavapatna@Sun.COM void vsw_setup_switching_thread(void *arg);
748370SSriharsha.Basavapatna@Sun.COM int vsw_setup_switching_start(vsw_t *vswp);
758370SSriharsha.Basavapatna@Sun.COM void vsw_setup_switching_stop(vsw_t *vswp);
765373Sraghuram int vsw_setup_switching(vsw_t *);
779819SSriharsha.Basavapatna@Sun.COM void vsw_setup_switching_post_process(vsw_t *vswp);
786537Swentaoy void vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller,
796537Swentaoy vsw_port_t *port, mac_resource_handle_t mrh);
805373Sraghuram static int vsw_setup_layer2(vsw_t *);
815373Sraghuram static int vsw_setup_layer3(vsw_t *);
825373Sraghuram
835373Sraghuram /* Switching/data transmit routines */
848275SEric Cheng static void vsw_switch_l2_frame_mac_client(vsw_t *vswp, mblk_t *mp, int caller,
858275SEric Cheng vsw_port_t *port, mac_resource_handle_t);
865373Sraghuram static void vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller,
876419Ssb155480 vsw_port_t *port, mac_resource_handle_t);
885373Sraghuram static void vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller,
896419Ssb155480 vsw_port_t *port, mac_resource_handle_t);
905935Ssb155480 static int vsw_forward_all(vsw_t *vswp, mblk_t *mp,
915935Ssb155480 int caller, vsw_port_t *port);
925935Ssb155480 static int vsw_forward_grp(vsw_t *vswp, mblk_t *mp,
935373Sraghuram int caller, vsw_port_t *port);
945373Sraghuram
956419Ssb155480 /* VLAN routines */
966419Ssb155480 void vsw_create_vlans(void *arg, int type);
976419Ssb155480 void vsw_destroy_vlans(void *arg, int type);
986419Ssb155480 void vsw_vlan_add_ids(void *arg, int type);
996419Ssb155480 void vsw_vlan_remove_ids(void *arg, int type);
1006419Ssb155480 static void vsw_vlan_create_hash(void *arg, int type);
1016419Ssb155480 static void vsw_vlan_destroy_hash(void *arg, int type);
1026419Ssb155480 boolean_t vsw_frame_lookup_vid(void *arg, int caller, struct ether_header *ehp,
1036419Ssb155480 uint16_t *vidp);
1046419Ssb155480 mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
1056419Ssb155480 uint32_t vsw_vlan_frames_untag(void *arg, int type, mblk_t **np, mblk_t **npt);
1066419Ssb155480 boolean_t vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
1076419Ssb155480
1085373Sraghuram /* Forwarding database (FDB) routines */
1096419Ssb155480 void vsw_fdbe_add(vsw_t *vswp, void *port);
1106419Ssb155480 void vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr);
1116419Ssb155480 static vsw_fdbe_t *vsw_fdbe_find(vsw_t *vswp, struct ether_addr *);
1126419Ssb155480 static void vsw_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val);
1136419Ssb155480
1145373Sraghuram int vsw_add_rem_mcst(vnet_mcast_msg_t *, vsw_port_t *);
1155373Sraghuram int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *);
1165373Sraghuram int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *);
1175373Sraghuram void vsw_del_mcst_vsw(vsw_t *);
1185373Sraghuram
1195373Sraghuram /* Support functions */
1205373Sraghuram static mblk_t *vsw_dupmsgchain(mblk_t *mp);
1218275SEric Cheng static mblk_t *vsw_get_same_dest_list(struct ether_header *ehp, mblk_t **mpp);
1225373Sraghuram
1235373Sraghuram
1245373Sraghuram /*
1255373Sraghuram * Functions imported from other files.
1265373Sraghuram */
1278275SEric Cheng extern mblk_t *vsw_tx_msg(vsw_t *, mblk_t *, int, vsw_port_t *);
1285373Sraghuram extern mcst_addr_t *vsw_del_addr(uint8_t, void *, uint64_t);
1295373Sraghuram extern int vsw_mac_open(vsw_t *vswp);
1305373Sraghuram extern void vsw_mac_close(vsw_t *vswp);
1315935Ssb155480 extern void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh,
1325935Ssb155480 mblk_t *mp, vsw_macrx_flags_t flags);
1335373Sraghuram extern void vsw_set_addrs(vsw_t *vswp);
1348275SEric Cheng extern int vsw_portsend(vsw_port_t *port, mblk_t *mp);
1356495Sspeer extern void vsw_hio_init(vsw_t *vswp);
1366495Sspeer extern void vsw_hio_start_ports(vsw_t *vswp);
1378275SEric Cheng extern int vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port,
1388275SEric Cheng mcst_addr_t *mcst_p, int type);
1398275SEric Cheng extern void vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port,
1408275SEric Cheng mcst_addr_t *mcst_p, int type);
1419819SSriharsha.Basavapatna@Sun.COM extern void vsw_mac_link_update(vsw_t *vswp, link_state_t link_state);
1429819SSriharsha.Basavapatna@Sun.COM extern void vsw_physlink_update_ports(vsw_t *vswp);
1435373Sraghuram
1445373Sraghuram /*
1455373Sraghuram * Tunables used in this file.
1465373Sraghuram */
1476419Ssb155480 extern int vsw_setup_switching_delay;
1486419Ssb155480 extern uint32_t vsw_vlan_nchains;
1496419Ssb155480 extern uint32_t vsw_fdbe_refcnt_delay;
1505373Sraghuram
1516419Ssb155480 #define VSW_FDBE_REFHOLD(p) \
1526419Ssb155480 { \
1536419Ssb155480 atomic_inc_32(&(p)->refcnt); \
1546419Ssb155480 ASSERT((p)->refcnt != 0); \
1556419Ssb155480 }
1566419Ssb155480
1576419Ssb155480 #define VSW_FDBE_REFRELE(p) \
1586419Ssb155480 { \
1596419Ssb155480 ASSERT((p)->refcnt != 0); \
1606419Ssb155480 atomic_dec_32(&(p)->refcnt); \
1616419Ssb155480 }
1625373Sraghuram
1635373Sraghuram /*
1648370SSriharsha.Basavapatna@Sun.COM * Thread to setup switching mode. This thread is created during vsw_attach()
1658370SSriharsha.Basavapatna@Sun.COM * initially. It invokes vsw_setup_switching() and keeps retrying while the
1668370SSriharsha.Basavapatna@Sun.COM * returned value is EAGAIN. The thread exits when the switching mode setup is
1678370SSriharsha.Basavapatna@Sun.COM * done successfully or when the error returned is not EAGAIN. This thread may
1688370SSriharsha.Basavapatna@Sun.COM * also get created from vsw_update_md_prop() if the switching mode needs to be
1698370SSriharsha.Basavapatna@Sun.COM * updated.
1705373Sraghuram */
1715373Sraghuram void
vsw_setup_switching_thread(void * arg)1728370SSriharsha.Basavapatna@Sun.COM vsw_setup_switching_thread(void *arg)
1735373Sraghuram {
1748370SSriharsha.Basavapatna@Sun.COM callb_cpr_t cprinfo;
1758370SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = (vsw_t *)arg;
1768370SSriharsha.Basavapatna@Sun.COM clock_t wait_time;
1778370SSriharsha.Basavapatna@Sun.COM clock_t xwait;
1788370SSriharsha.Basavapatna@Sun.COM clock_t wait_rv;
1795373Sraghuram int rv;
1805373Sraghuram
1818370SSriharsha.Basavapatna@Sun.COM /* wait time used on successive retries */
1828370SSriharsha.Basavapatna@Sun.COM xwait = drv_usectohz(vsw_setup_switching_delay * MICROSEC);
1838370SSriharsha.Basavapatna@Sun.COM
1848370SSriharsha.Basavapatna@Sun.COM CALLB_CPR_INIT(&cprinfo, &vswp->sw_thr_lock, callb_generic_cpr,
1858370SSriharsha.Basavapatna@Sun.COM "vsw_setup_sw_thread");
1868370SSriharsha.Basavapatna@Sun.COM
1878370SSriharsha.Basavapatna@Sun.COM mutex_enter(&vswp->sw_thr_lock);
1888370SSriharsha.Basavapatna@Sun.COM
1898370SSriharsha.Basavapatna@Sun.COM while ((vswp->sw_thr_flags & VSW_SWTHR_STOP) == 0) {
1908370SSriharsha.Basavapatna@Sun.COM
1918370SSriharsha.Basavapatna@Sun.COM CALLB_CPR_SAFE_BEGIN(&cprinfo);
1928370SSriharsha.Basavapatna@Sun.COM
1938370SSriharsha.Basavapatna@Sun.COM /* Wait for sometime before (re)trying setup_switching() */
1948370SSriharsha.Basavapatna@Sun.COM wait_time = ddi_get_lbolt() + xwait;
1958370SSriharsha.Basavapatna@Sun.COM while ((vswp->sw_thr_flags & VSW_SWTHR_STOP) == 0) {
1968370SSriharsha.Basavapatna@Sun.COM wait_rv = cv_timedwait(&vswp->sw_thr_cv,
1978370SSriharsha.Basavapatna@Sun.COM &vswp->sw_thr_lock, wait_time);
1988370SSriharsha.Basavapatna@Sun.COM if (wait_rv == -1) { /* timed out */
1998370SSriharsha.Basavapatna@Sun.COM break;
2008370SSriharsha.Basavapatna@Sun.COM }
2018370SSriharsha.Basavapatna@Sun.COM }
2025373Sraghuram
2038370SSriharsha.Basavapatna@Sun.COM CALLB_CPR_SAFE_END(&cprinfo, &vswp->sw_thr_lock)
2048370SSriharsha.Basavapatna@Sun.COM
2058370SSriharsha.Basavapatna@Sun.COM if ((vswp->sw_thr_flags & VSW_SWTHR_STOP) != 0) {
2068370SSriharsha.Basavapatna@Sun.COM /*
2078370SSriharsha.Basavapatna@Sun.COM * If there is a stop request, process that first and
2088370SSriharsha.Basavapatna@Sun.COM * exit the loop. Continue to hold the mutex which gets
2098370SSriharsha.Basavapatna@Sun.COM * released in CALLB_CPR_EXIT().
2108370SSriharsha.Basavapatna@Sun.COM */
2118370SSriharsha.Basavapatna@Sun.COM break;
2128370SSriharsha.Basavapatna@Sun.COM }
2135373Sraghuram
2148370SSriharsha.Basavapatna@Sun.COM mutex_exit(&vswp->sw_thr_lock);
2158370SSriharsha.Basavapatna@Sun.COM rv = vsw_setup_switching(vswp);
2168370SSriharsha.Basavapatna@Sun.COM if (rv == 0) {
2179819SSriharsha.Basavapatna@Sun.COM vsw_setup_switching_post_process(vswp);
2188370SSriharsha.Basavapatna@Sun.COM }
2198370SSriharsha.Basavapatna@Sun.COM mutex_enter(&vswp->sw_thr_lock);
2208370SSriharsha.Basavapatna@Sun.COM if (rv != EAGAIN) {
2218370SSriharsha.Basavapatna@Sun.COM break;
2228370SSriharsha.Basavapatna@Sun.COM }
2238370SSriharsha.Basavapatna@Sun.COM
2245373Sraghuram }
2255373Sraghuram
2268370SSriharsha.Basavapatna@Sun.COM vswp->sw_thr_flags &= ~VSW_SWTHR_STOP;
2278370SSriharsha.Basavapatna@Sun.COM vswp->sw_thread = NULL;
2288370SSriharsha.Basavapatna@Sun.COM CALLB_CPR_EXIT(&cprinfo);
2298370SSriharsha.Basavapatna@Sun.COM thread_exit();
2305373Sraghuram }
2315373Sraghuram
2325373Sraghuram /*
2338370SSriharsha.Basavapatna@Sun.COM * Create a thread to setup the switching mode.
2348370SSriharsha.Basavapatna@Sun.COM * Returns 0 on success; 1 on failure.
2358370SSriharsha.Basavapatna@Sun.COM */
2368370SSriharsha.Basavapatna@Sun.COM int
vsw_setup_switching_start(vsw_t * vswp)2378370SSriharsha.Basavapatna@Sun.COM vsw_setup_switching_start(vsw_t *vswp)
2388370SSriharsha.Basavapatna@Sun.COM {
2398370SSriharsha.Basavapatna@Sun.COM mutex_enter(&vswp->sw_thr_lock);
2408370SSriharsha.Basavapatna@Sun.COM
2418370SSriharsha.Basavapatna@Sun.COM vswp->sw_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
2428370SSriharsha.Basavapatna@Sun.COM vsw_setup_switching_thread, vswp, 0, &p0, TS_RUN, minclsyspri);
2438370SSriharsha.Basavapatna@Sun.COM
2448370SSriharsha.Basavapatna@Sun.COM if (vswp->sw_thread == NULL) {
2458370SSriharsha.Basavapatna@Sun.COM mutex_exit(&vswp->sw_thr_lock);
2468370SSriharsha.Basavapatna@Sun.COM return (1);
2478370SSriharsha.Basavapatna@Sun.COM }
2488370SSriharsha.Basavapatna@Sun.COM
2498370SSriharsha.Basavapatna@Sun.COM mutex_exit(&vswp->sw_thr_lock);
2508370SSriharsha.Basavapatna@Sun.COM return (0);
2518370SSriharsha.Basavapatna@Sun.COM }
2528370SSriharsha.Basavapatna@Sun.COM
2538370SSriharsha.Basavapatna@Sun.COM /*
2548370SSriharsha.Basavapatna@Sun.COM * Stop the thread to setup switching mode.
2555373Sraghuram */
2565373Sraghuram void
vsw_setup_switching_stop(vsw_t * vswp)2578370SSriharsha.Basavapatna@Sun.COM vsw_setup_switching_stop(vsw_t *vswp)
2585373Sraghuram {
2598370SSriharsha.Basavapatna@Sun.COM kt_did_t tid = 0;
2605373Sraghuram
2618370SSriharsha.Basavapatna@Sun.COM /*
2628370SSriharsha.Basavapatna@Sun.COM * Signal the setup_switching thread to stop and wait until it stops.
2638370SSriharsha.Basavapatna@Sun.COM */
2648370SSriharsha.Basavapatna@Sun.COM mutex_enter(&vswp->sw_thr_lock);
2655373Sraghuram
2668370SSriharsha.Basavapatna@Sun.COM if (vswp->sw_thread != NULL) {
2678370SSriharsha.Basavapatna@Sun.COM tid = vswp->sw_thread->t_did;
2688370SSriharsha.Basavapatna@Sun.COM vswp->sw_thr_flags |= VSW_SWTHR_STOP;
2698370SSriharsha.Basavapatna@Sun.COM cv_signal(&vswp->sw_thr_cv);
2708370SSriharsha.Basavapatna@Sun.COM }
2715373Sraghuram
2728370SSriharsha.Basavapatna@Sun.COM mutex_exit(&vswp->sw_thr_lock);
2738370SSriharsha.Basavapatna@Sun.COM
2748370SSriharsha.Basavapatna@Sun.COM if (tid != 0)
2758370SSriharsha.Basavapatna@Sun.COM thread_join(tid);
2765373Sraghuram
2775373Sraghuram (void) atomic_swap_32(&vswp->switching_setup_done, B_FALSE);
2785373Sraghuram
2795373Sraghuram vswp->mac_open_retries = 0;
2805373Sraghuram }
2815373Sraghuram
2825373Sraghuram /*
2835373Sraghuram * Setup the required switching mode.
2845373Sraghuram * Returns:
2855373Sraghuram * 0 on success.
2865373Sraghuram * EAGAIN if retry is needed.
2875373Sraghuram * 1 on all other failures.
2885373Sraghuram */
2895373Sraghuram int
vsw_setup_switching(vsw_t * vswp)2905373Sraghuram vsw_setup_switching(vsw_t *vswp)
2915373Sraghuram {
2928275SEric Cheng int rv = 1;
2935373Sraghuram
2945373Sraghuram D1(vswp, "%s: enter", __func__);
2955373Sraghuram
2965373Sraghuram /*
2975373Sraghuram * Select best switching mode.
2988275SEric Cheng * This is done as this routine can be called from the timeout
2998275SEric Cheng * handler to retry setting up a specific mode. Currently only
3008275SEric Cheng * the function which sets up layer2/promisc mode returns EAGAIN
3018275SEric Cheng * if the underlying network device is not available yet, causing
3028275SEric Cheng * retries.
3035373Sraghuram */
3048275SEric Cheng if (vswp->smode & VSW_LAYER2) {
3058275SEric Cheng rv = vsw_setup_layer2(vswp);
3068275SEric Cheng } else if (vswp->smode & VSW_LAYER3) {
3078275SEric Cheng rv = vsw_setup_layer3(vswp);
3088275SEric Cheng } else {
3098275SEric Cheng DERR(vswp, "unknown switch mode");
3105373Sraghuram rv = 1;
3115373Sraghuram }
3125373Sraghuram
3135373Sraghuram if (rv && (rv != EAGAIN)) {
3145373Sraghuram cmn_err(CE_WARN, "!vsw%d: Unable to setup specified "
3155373Sraghuram "switching mode", vswp->instance);
3165373Sraghuram } else if (rv == 0) {
3175373Sraghuram (void) atomic_swap_32(&vswp->switching_setup_done, B_TRUE);
3185373Sraghuram }
3195373Sraghuram
3205373Sraghuram D2(vswp, "%s: Operating in mode %d", __func__,
3218275SEric Cheng vswp->smode);
3225373Sraghuram
3235373Sraghuram D1(vswp, "%s: exit", __func__);
3245373Sraghuram
3255373Sraghuram return (rv);
3265373Sraghuram }
3275373Sraghuram
3285373Sraghuram /*
3295373Sraghuram * Setup for layer 2 switching.
3305373Sraghuram *
3315373Sraghuram * Returns:
3325373Sraghuram * 0 on success.
3335373Sraghuram * EAGAIN if retry is needed.
3345373Sraghuram * EIO on all other failures.
3355373Sraghuram */
3365373Sraghuram static int
vsw_setup_layer2(vsw_t * vswp)3375373Sraghuram vsw_setup_layer2(vsw_t *vswp)
3385373Sraghuram {
3395373Sraghuram int rv;
3405373Sraghuram
3415373Sraghuram D1(vswp, "%s: enter", __func__);
3425373Sraghuram
3438275SEric Cheng /*
3448275SEric Cheng * Until the network device is successfully opened,
3458275SEric Cheng * set the switching to use vsw_switch_l2_frame.
3468275SEric Cheng */
3475373Sraghuram vswp->vsw_switch_frame = vsw_switch_l2_frame;
3488275SEric Cheng vswp->mac_cl_switching = B_FALSE;
3495373Sraghuram
3505373Sraghuram rv = strlen(vswp->physname);
3515373Sraghuram if (rv == 0) {
3525373Sraghuram /*
3535373Sraghuram * Physical device name is NULL, which is
3545373Sraghuram * required for layer 2.
3555373Sraghuram */
3568275SEric Cheng cmn_err(CE_WARN, "!vsw%d: no network device name specified",
3575373Sraghuram vswp->instance);
3585373Sraghuram return (EIO);
3595373Sraghuram }
3605373Sraghuram
3618275SEric Cheng mutex_enter(&vswp->mac_lock);
3625373Sraghuram
3635373Sraghuram rv = vsw_mac_open(vswp);
3645373Sraghuram if (rv != 0) {
3655373Sraghuram if (rv != EAGAIN) {
3668275SEric Cheng cmn_err(CE_WARN, "!vsw%d: Unable to open network "
3675373Sraghuram "device: %s\n", vswp->instance, vswp->physname);
3685373Sraghuram }
3698275SEric Cheng mutex_exit(&vswp->mac_lock);
3705373Sraghuram return (rv);
3715373Sraghuram }
3725373Sraghuram
3735373Sraghuram /*
3748275SEric Cheng * Now we can use the mac client switching, so set the switching
3758275SEric Cheng * function to use vsw_switch_l2_frame_mac_client(), which simply
3768275SEric Cheng * sends the packets to MAC layer for switching.
3775373Sraghuram */
3788275SEric Cheng vswp->vsw_switch_frame = vsw_switch_l2_frame_mac_client;
3798275SEric Cheng vswp->mac_cl_switching = B_TRUE;
3805373Sraghuram
3815373Sraghuram D1(vswp, "%s: exit", __func__);
3825373Sraghuram
3836495Sspeer /* Initialize HybridIO related stuff */
3846495Sspeer vsw_hio_init(vswp);
3858275SEric Cheng
3868275SEric Cheng mutex_exit(&vswp->mac_lock);
3875373Sraghuram return (0);
3885373Sraghuram
3895373Sraghuram exit_error:
3905373Sraghuram vsw_mac_close(vswp);
3918275SEric Cheng mutex_exit(&vswp->mac_lock);
3925373Sraghuram return (EIO);
3935373Sraghuram }
3945373Sraghuram
3955373Sraghuram static int
vsw_setup_layer3(vsw_t * vswp)3965373Sraghuram vsw_setup_layer3(vsw_t *vswp)
3975373Sraghuram {
3985373Sraghuram D1(vswp, "%s: enter", __func__);
3995373Sraghuram
4005373Sraghuram D2(vswp, "%s: operating in layer 3 mode", __func__);
4015373Sraghuram vswp->vsw_switch_frame = vsw_switch_l3_frame;
4025373Sraghuram
4035373Sraghuram D1(vswp, "%s: exit", __func__);
4045373Sraghuram
4055373Sraghuram return (0);
4065373Sraghuram }
4075373Sraghuram
4086537Swentaoy /* ARGSUSED */
4096537Swentaoy void
vsw_switch_frame_nop(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * port,mac_resource_handle_t mrh)4106537Swentaoy vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port,
4116537Swentaoy mac_resource_handle_t mrh)
4126537Swentaoy {
4136537Swentaoy freemsgchain(mp);
4146537Swentaoy }
4156537Swentaoy
4165373Sraghuram /*
4178275SEric Cheng * Use mac client for layer 2 switching .
4188275SEric Cheng */
4198275SEric Cheng static void
vsw_switch_l2_frame_mac_client(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * port,mac_resource_handle_t mrh)4208275SEric Cheng vsw_switch_l2_frame_mac_client(vsw_t *vswp, mblk_t *mp, int caller,
4218275SEric Cheng vsw_port_t *port, mac_resource_handle_t mrh)
4228275SEric Cheng {
4238275SEric Cheng _NOTE(ARGUNUSED(mrh))
4248275SEric Cheng
4258275SEric Cheng mblk_t *ret_m;
4268275SEric Cheng
4278275SEric Cheng /*
4288275SEric Cheng * This switching function is expected to be called by
4298275SEric Cheng * the ports or the interface only. The packets from
4308275SEric Cheng * physical interface already switched.
4318275SEric Cheng */
4328275SEric Cheng ASSERT((caller == VSW_VNETPORT) || (caller == VSW_LOCALDEV));
4338275SEric Cheng
4348275SEric Cheng if ((ret_m = vsw_tx_msg(vswp, mp, caller, port)) != NULL) {
4358275SEric Cheng DERR(vswp, "%s: drop mblks to "
4368275SEric Cheng "phys dev", __func__);
4378275SEric Cheng freemsgchain(ret_m);
4388275SEric Cheng }
4398275SEric Cheng }
4408275SEric Cheng
4418275SEric Cheng /*
4425373Sraghuram * Switch the given ethernet frame when operating in layer 2 mode.
4435373Sraghuram *
4445373Sraghuram * vswp: pointer to the vsw instance
4455373Sraghuram * mp: pointer to chain of ethernet frame(s) to be switched
4465373Sraghuram * caller: identifies the source of this frame as:
4475373Sraghuram * 1. VSW_VNETPORT - a vsw port (connected to a vnet).
4485373Sraghuram * 2. VSW_PHYSDEV - the physical ethernet device
4495373Sraghuram * 3. VSW_LOCALDEV - vsw configured as a virtual interface
4505373Sraghuram * arg: argument provided by the caller.
4515373Sraghuram * 1. for VNETPORT - pointer to the corresponding vsw_port_t.
4525373Sraghuram * 2. for PHYSDEV - NULL
4535373Sraghuram * 3. for LOCALDEV - pointer to to this vsw_t(self)
4545373Sraghuram */
4555373Sraghuram void
vsw_switch_l2_frame(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * arg,mac_resource_handle_t mrh)4565373Sraghuram vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller,
4575373Sraghuram vsw_port_t *arg, mac_resource_handle_t mrh)
4585373Sraghuram {
4595373Sraghuram struct ether_header *ehp;
4605373Sraghuram mblk_t *bp, *ret_m;
4616419Ssb155480 vsw_fdbe_t *fp;
4625373Sraghuram
4635373Sraghuram D1(vswp, "%s: enter (caller %d)", __func__, caller);
4645373Sraghuram
4655373Sraghuram /*
4665373Sraghuram * PERF: rather than breaking up the chain here, scan it
4675373Sraghuram * to find all mblks heading to same destination and then
4685373Sraghuram * pass that sub-chain to the lower transmit functions.
4695373Sraghuram */
4705373Sraghuram
4715373Sraghuram /* process the chain of packets */
4725373Sraghuram bp = mp;
4735373Sraghuram while (bp) {
4745373Sraghuram ehp = (struct ether_header *)bp->b_rptr;
4758275SEric Cheng mp = vsw_get_same_dest_list(ehp, &bp);
4768275SEric Cheng ASSERT(mp != NULL);
4775373Sraghuram
4785373Sraghuram D2(vswp, "%s: mblk data buffer %lld : actual data size %lld",
4795373Sraghuram __func__, MBLKSIZE(mp), MBLKL(mp));
4805373Sraghuram
4815373Sraghuram if (ether_cmp(&ehp->ether_dhost, &vswp->if_addr) == 0) {
4825373Sraghuram /*
4835373Sraghuram * If destination is VSW_LOCALDEV (vsw as an eth
4845373Sraghuram * interface) and if the device is up & running,
4855373Sraghuram * send the packet up the stack on this host.
4865373Sraghuram * If the virtual interface is down, drop the packet.
4875373Sraghuram */
4885373Sraghuram if (caller != VSW_LOCALDEV) {
4895935Ssb155480 vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_FREEMSG);
4905373Sraghuram } else {
4915373Sraghuram freemsgchain(mp);
4925373Sraghuram }
4935373Sraghuram continue;
4945373Sraghuram }
4955373Sraghuram
4966419Ssb155480 /*
4976419Ssb155480 * Find fdb entry for the destination
4986419Ssb155480 * and hold a reference to it.
4996419Ssb155480 */
5006419Ssb155480 fp = vsw_fdbe_find(vswp, &ehp->ether_dhost);
5016419Ssb155480 if (fp != NULL) {
5025373Sraghuram
5035373Sraghuram /*
5045373Sraghuram * If plumbed and in promisc mode then copy msg
5055373Sraghuram * and send up the stack.
5065373Sraghuram */
5075935Ssb155480 vsw_mac_rx(vswp, mrh, mp,
5085935Ssb155480 VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG);
5095373Sraghuram
5105373Sraghuram /*
5115373Sraghuram * If the destination is in FDB, the packet
5125373Sraghuram * should be forwarded to the correponding
5135373Sraghuram * vsw_port (connected to a vnet device -
5145373Sraghuram * VSW_VNETPORT)
5155373Sraghuram */
5168275SEric Cheng (void) vsw_portsend(fp->portp, mp);
5175373Sraghuram
5186419Ssb155480 /* Release the reference on the fdb entry */
5196419Ssb155480 VSW_FDBE_REFRELE(fp);
5205373Sraghuram } else {
5215373Sraghuram /*
5225373Sraghuram * Destination not in FDB.
5235373Sraghuram *
5245373Sraghuram * If the destination is broadcast or
5255373Sraghuram * multicast forward the packet to all
5265373Sraghuram * (VNETPORTs, PHYSDEV, LOCALDEV),
5275373Sraghuram * except the caller.
5285373Sraghuram */
5295373Sraghuram if (IS_BROADCAST(ehp)) {
5305935Ssb155480 D2(vswp, "%s: BROADCAST pkt", __func__);
5315935Ssb155480 (void) vsw_forward_all(vswp, mp, caller, arg);
5325373Sraghuram } else if (IS_MULTICAST(ehp)) {
5335935Ssb155480 D2(vswp, "%s: MULTICAST pkt", __func__);
5345935Ssb155480 (void) vsw_forward_grp(vswp, mp, caller, arg);
5355373Sraghuram } else {
5365373Sraghuram /*
5375373Sraghuram * If the destination is unicast, and came
5385373Sraghuram * from either a logical network device or
5395373Sraghuram * the switch itself when it is plumbed, then
5405373Sraghuram * send it out on the physical device and also
5415373Sraghuram * up the stack if the logical interface is
5425373Sraghuram * in promiscious mode.
5435373Sraghuram *
5445373Sraghuram * NOTE: The assumption here is that if we
5455373Sraghuram * cannot find the destination in our fdb, its
5465373Sraghuram * a unicast address, and came from either a
5475373Sraghuram * vnet or down the stack (when plumbed) it
5485373Sraghuram * must be destinded for an ethernet device
5495373Sraghuram * outside our ldoms.
5505373Sraghuram */
5515373Sraghuram if (caller == VSW_VNETPORT) {
5525373Sraghuram /* promisc check copy etc */
5535935Ssb155480 vsw_mac_rx(vswp, mrh, mp,
5545373Sraghuram VSW_MACRX_PROMISC |
5555373Sraghuram VSW_MACRX_COPYMSG);
5565373Sraghuram
5578275SEric Cheng if ((ret_m = vsw_tx_msg(vswp, mp,
5588275SEric Cheng caller, arg)) != NULL) {
5595373Sraghuram DERR(vswp, "%s: drop mblks to "
5605373Sraghuram "phys dev", __func__);
5615373Sraghuram freemsgchain(ret_m);
5625373Sraghuram }
5635373Sraghuram
5645373Sraghuram } else if (caller == VSW_PHYSDEV) {
5655373Sraghuram /*
5665373Sraghuram * Pkt seen because card in promisc
5675373Sraghuram * mode. Send up stack if plumbed in
5685373Sraghuram * promisc mode, else drop it.
5695373Sraghuram */
5705935Ssb155480 vsw_mac_rx(vswp, mrh, mp,
5715373Sraghuram VSW_MACRX_PROMISC |
5725373Sraghuram VSW_MACRX_FREEMSG);
5735373Sraghuram
5745373Sraghuram } else if (caller == VSW_LOCALDEV) {
5755373Sraghuram /*
5765373Sraghuram * Pkt came down the stack, send out
5775373Sraghuram * over physical device.
5785373Sraghuram */
5798275SEric Cheng if ((ret_m = vsw_tx_msg(vswp, mp,
5808275SEric Cheng caller, NULL)) != NULL) {
5815373Sraghuram DERR(vswp, "%s: drop mblks to "
5825373Sraghuram "phys dev", __func__);
5835373Sraghuram freemsgchain(ret_m);
5845373Sraghuram }
5855373Sraghuram }
5865373Sraghuram }
5875373Sraghuram }
5885373Sraghuram }
5895373Sraghuram D1(vswp, "%s: exit\n", __func__);
5905373Sraghuram }
5915373Sraghuram
5925373Sraghuram /*
5935373Sraghuram * Switch ethernet frame when in layer 3 mode (i.e. using IP
5945373Sraghuram * layer to do the routing).
5955373Sraghuram *
5965373Sraghuram * There is a large amount of overlap between this function and
5975373Sraghuram * vsw_switch_l2_frame. At some stage we need to revisit and refactor
5985373Sraghuram * both these functions.
5995373Sraghuram */
6005373Sraghuram void
vsw_switch_l3_frame(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * arg,mac_resource_handle_t mrh)6015373Sraghuram vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller,
6025373Sraghuram vsw_port_t *arg, mac_resource_handle_t mrh)
6035373Sraghuram {
6045373Sraghuram struct ether_header *ehp;
6055373Sraghuram mblk_t *bp = NULL;
6066419Ssb155480 vsw_fdbe_t *fp;
6075373Sraghuram
6085373Sraghuram D1(vswp, "%s: enter (caller %d)", __func__, caller);
6095373Sraghuram
6105373Sraghuram /*
6115373Sraghuram * In layer 3 mode should only ever be switching packets
6125373Sraghuram * between IP layer and vnet devices. So make sure thats
6135373Sraghuram * who is invoking us.
6145373Sraghuram */
6155373Sraghuram if ((caller != VSW_LOCALDEV) && (caller != VSW_VNETPORT)) {
6165373Sraghuram DERR(vswp, "%s: unexpected caller (%d)", __func__, caller);
6175373Sraghuram freemsgchain(mp);
6185373Sraghuram return;
6195373Sraghuram }
6205373Sraghuram
6215373Sraghuram /* process the chain of packets */
6225373Sraghuram bp = mp;
6235373Sraghuram while (bp) {
6245373Sraghuram ehp = (struct ether_header *)bp->b_rptr;
6258275SEric Cheng mp = vsw_get_same_dest_list(ehp, &bp);
6268275SEric Cheng ASSERT(mp != NULL);
6275373Sraghuram
6285373Sraghuram D2(vswp, "%s: mblk data buffer %lld : actual data size %lld",
6295373Sraghuram __func__, MBLKSIZE(mp), MBLKL(mp));
6305373Sraghuram
6316419Ssb155480 /*
6326419Ssb155480 * Find fdb entry for the destination
6336419Ssb155480 * and hold a reference to it.
6346419Ssb155480 */
6356419Ssb155480 fp = vsw_fdbe_find(vswp, &ehp->ether_dhost);
6366419Ssb155480 if (fp != NULL) {
6375373Sraghuram
6385373Sraghuram D2(vswp, "%s: sending to target port", __func__);
6398275SEric Cheng (void) vsw_portsend(fp->portp, mp);
6405373Sraghuram
6416419Ssb155480 /* Release the reference on the fdb entry */
6426419Ssb155480 VSW_FDBE_REFRELE(fp);
6435373Sraghuram } else {
6445373Sraghuram /*
6455373Sraghuram * Destination not in FDB
6465373Sraghuram *
6475373Sraghuram * If the destination is broadcast or
6485373Sraghuram * multicast forward the packet to all
6495373Sraghuram * (VNETPORTs, PHYSDEV, LOCALDEV),
6505373Sraghuram * except the caller.
6515373Sraghuram */
6525373Sraghuram if (IS_BROADCAST(ehp)) {
6535373Sraghuram D2(vswp, "%s: BROADCAST pkt", __func__);
6545935Ssb155480 (void) vsw_forward_all(vswp, mp, caller, arg);
6555373Sraghuram } else if (IS_MULTICAST(ehp)) {
6565373Sraghuram D2(vswp, "%s: MULTICAST pkt", __func__);
6575935Ssb155480 (void) vsw_forward_grp(vswp, mp, caller, arg);
6585373Sraghuram } else {
6595373Sraghuram /*
6605373Sraghuram * Unicast pkt from vnet that we don't have
6615373Sraghuram * an FDB entry for, so must be destinded for
6625373Sraghuram * the outside world. Attempt to send up to the
6635373Sraghuram * IP layer to allow it to deal with it.
6645373Sraghuram */
6655373Sraghuram if (caller == VSW_VNETPORT) {
6665935Ssb155480 vsw_mac_rx(vswp, mrh,
6675935Ssb155480 mp, VSW_MACRX_FREEMSG);
6685373Sraghuram }
6695373Sraghuram }
6705373Sraghuram }
6715373Sraghuram }
6725373Sraghuram
6735373Sraghuram D1(vswp, "%s: exit", __func__);
6745373Sraghuram }
6755373Sraghuram
6765373Sraghuram /*
6779819SSriharsha.Basavapatna@Sun.COM * Additional initializations that are needed for the specific switching mode.
6787816SWentao.Yang@Sun.COM */
6797816SWentao.Yang@Sun.COM void
vsw_setup_switching_post_process(vsw_t * vswp)6809819SSriharsha.Basavapatna@Sun.COM vsw_setup_switching_post_process(vsw_t *vswp)
6817816SWentao.Yang@Sun.COM {
6829819SSriharsha.Basavapatna@Sun.COM link_state_t link_state = LINK_STATE_UP;
6839819SSriharsha.Basavapatna@Sun.COM
6848275SEric Cheng if (vswp->smode & VSW_LAYER2) {
6857816SWentao.Yang@Sun.COM /*
6867816SWentao.Yang@Sun.COM * Program unicst, mcst addrs of vsw
6877816SWentao.Yang@Sun.COM * interface and ports in the physdev.
6887816SWentao.Yang@Sun.COM */
6897816SWentao.Yang@Sun.COM vsw_set_addrs(vswp);
6907816SWentao.Yang@Sun.COM
6917816SWentao.Yang@Sun.COM /* Start HIO for ports that have already connected */
6927816SWentao.Yang@Sun.COM vsw_hio_start_ports(vswp);
6939336SSriharsha.Basavapatna@Sun.COM
6949819SSriharsha.Basavapatna@Sun.COM if (vswp->pls_update == B_TRUE) {
6959819SSriharsha.Basavapatna@Sun.COM link_state = vswp->phys_link_state;
6969819SSriharsha.Basavapatna@Sun.COM }
6979819SSriharsha.Basavapatna@Sun.COM
6989336SSriharsha.Basavapatna@Sun.COM /* Update physical link info to any ports already connected */
6999819SSriharsha.Basavapatna@Sun.COM vsw_physlink_update_ports(vswp);
7007816SWentao.Yang@Sun.COM }
7019819SSriharsha.Basavapatna@Sun.COM
7029819SSriharsha.Basavapatna@Sun.COM vsw_mac_link_update(vswp, link_state);
7037816SWentao.Yang@Sun.COM }
7047816SWentao.Yang@Sun.COM
7057816SWentao.Yang@Sun.COM /*
7065373Sraghuram * Forward the ethernet frame to all ports (VNETPORTs, PHYSDEV, LOCALDEV),
7075373Sraghuram * except the caller (port on which frame arrived).
7085373Sraghuram */
7095373Sraghuram static int
vsw_forward_all(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * arg)7105935Ssb155480 vsw_forward_all(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg)
7115373Sraghuram {
7125373Sraghuram vsw_port_list_t *plist = &vswp->plist;
7135373Sraghuram vsw_port_t *portp;
7145373Sraghuram mblk_t *nmp = NULL;
7155373Sraghuram mblk_t *ret_m = NULL;
7165373Sraghuram int skip_port = 0;
7175373Sraghuram
7185373Sraghuram D1(vswp, "vsw_forward_all: enter\n");
7195373Sraghuram
7205373Sraghuram /*
7215373Sraghuram * Broadcast message from inside ldoms so send to outside
7225373Sraghuram * world if in either of layer 2 modes.
7235373Sraghuram */
7248275SEric Cheng if ((vswp->smode & VSW_LAYER2) &&
7255373Sraghuram ((caller == VSW_LOCALDEV) || (caller == VSW_VNETPORT))) {
7265373Sraghuram
7275373Sraghuram nmp = vsw_dupmsgchain(mp);
7285373Sraghuram if (nmp) {
7298275SEric Cheng if ((ret_m = vsw_tx_msg(vswp, nmp, caller, arg))
7308275SEric Cheng != NULL) {
7315373Sraghuram DERR(vswp, "%s: dropping pkt(s) "
7325373Sraghuram "consisting of %ld bytes of data for"
7335373Sraghuram " physical device", __func__, MBLKL(ret_m));
7345373Sraghuram freemsgchain(ret_m);
7355373Sraghuram }
7365373Sraghuram }
7375373Sraghuram }
7385373Sraghuram
7395373Sraghuram if (caller == VSW_VNETPORT)
7405373Sraghuram skip_port = 1;
7415373Sraghuram
7425373Sraghuram /*
7435373Sraghuram * Broadcast message from other vnet (layer 2 or 3) or outside
7445373Sraghuram * world (layer 2 only), send up stack if plumbed.
7455373Sraghuram */
7465373Sraghuram if ((caller == VSW_PHYSDEV) || (caller == VSW_VNETPORT)) {
7475935Ssb155480 vsw_mac_rx(vswp, NULL, mp, VSW_MACRX_COPYMSG);
7485373Sraghuram }
7495373Sraghuram
7505373Sraghuram /* send it to all VNETPORTs */
7515373Sraghuram READ_ENTER(&plist->lockrw);
7525373Sraghuram for (portp = plist->head; portp != NULL; portp = portp->p_next) {
7535373Sraghuram D2(vswp, "vsw_forward_all: port %d", portp->p_instance);
7545373Sraghuram /*
7555373Sraghuram * Caution ! - don't reorder these two checks as arg
7565373Sraghuram * will be NULL if the caller is PHYSDEV. skip_port is
7575373Sraghuram * only set if caller is VNETPORT.
7585373Sraghuram */
7595373Sraghuram if ((skip_port) && (portp == arg)) {
7605373Sraghuram continue;
7615373Sraghuram } else {
7625373Sraghuram nmp = vsw_dupmsgchain(mp);
7635373Sraghuram if (nmp) {
7645373Sraghuram /*
7655373Sraghuram * The plist->lockrw is protecting the
7665373Sraghuram * portp from getting destroyed here.
7675373Sraghuram * So, no ref_cnt is incremented here.
7685373Sraghuram */
7698275SEric Cheng (void) vsw_portsend(portp, nmp);
7705373Sraghuram } else {
7715373Sraghuram DERR(vswp, "vsw_forward_all: nmp NULL");
7725373Sraghuram }
7735373Sraghuram }
7745373Sraghuram }
7755373Sraghuram RW_EXIT(&plist->lockrw);
7765373Sraghuram
7775373Sraghuram freemsgchain(mp);
7785373Sraghuram
7795373Sraghuram D1(vswp, "vsw_forward_all: exit\n");
7805373Sraghuram return (0);
7815373Sraghuram }
7825373Sraghuram
7835373Sraghuram /*
7845373Sraghuram * Forward pkts to any devices or interfaces which have registered
7855373Sraghuram * an interest in them (i.e. multicast groups).
7865373Sraghuram */
7875373Sraghuram static int
vsw_forward_grp(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * arg)7885935Ssb155480 vsw_forward_grp(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg)
7895373Sraghuram {
7905373Sraghuram struct ether_header *ehp = (struct ether_header *)mp->b_rptr;
7915373Sraghuram mfdb_ent_t *entp = NULL;
7925373Sraghuram mfdb_ent_t *tpp = NULL;
7935373Sraghuram vsw_port_t *port;
7945373Sraghuram uint64_t key = 0;
7955373Sraghuram mblk_t *nmp = NULL;
7965373Sraghuram mblk_t *ret_m = NULL;
7975373Sraghuram boolean_t check_if = B_TRUE;
7985373Sraghuram
7995373Sraghuram /*
8005373Sraghuram * Convert address to hash table key
8015373Sraghuram */
8026419Ssb155480 KEY_HASH(key, &ehp->ether_dhost);
8035373Sraghuram
8045373Sraghuram D1(vswp, "%s: key 0x%llx", __func__, key);
8055373Sraghuram
8065373Sraghuram /*
8075373Sraghuram * If pkt came from either a vnet or down the stack (if we are
8085373Sraghuram * plumbed) and we are in layer 2 mode, then we send the pkt out
8095373Sraghuram * over the physical adapter, and then check to see if any other
8105373Sraghuram * vnets are interested in it.
8115373Sraghuram */
8128275SEric Cheng if ((vswp->smode & VSW_LAYER2) &&
8135373Sraghuram ((caller == VSW_VNETPORT) || (caller == VSW_LOCALDEV))) {
8145373Sraghuram nmp = vsw_dupmsgchain(mp);
8155373Sraghuram if (nmp) {
8168275SEric Cheng if ((ret_m = vsw_tx_msg(vswp, nmp, caller, arg))
8178275SEric Cheng != NULL) {
8185373Sraghuram DERR(vswp, "%s: dropping pkt(s) consisting of "
8195373Sraghuram "%ld bytes of data for physical device",
8205373Sraghuram __func__, MBLKL(ret_m));
8215373Sraghuram freemsgchain(ret_m);
8225373Sraghuram }
8235373Sraghuram }
8245373Sraghuram }
8255373Sraghuram
8265373Sraghuram READ_ENTER(&vswp->mfdbrw);
8275373Sraghuram if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)key,
8285373Sraghuram (mod_hash_val_t *)&entp) != 0) {
8295373Sraghuram D3(vswp, "%s: no table entry found for addr 0x%llx",
8305373Sraghuram __func__, key);
8315373Sraghuram } else {
8325373Sraghuram /*
8335373Sraghuram * Send to list of devices associated with this address...
8345373Sraghuram */
8355373Sraghuram for (tpp = entp; tpp != NULL; tpp = tpp->nextp) {
8365373Sraghuram
8375373Sraghuram /* dont send to ourselves */
8385373Sraghuram if ((caller == VSW_VNETPORT) &&
8395373Sraghuram (tpp->d_addr == (void *)arg)) {
8405373Sraghuram port = (vsw_port_t *)tpp->d_addr;
8415373Sraghuram D3(vswp, "%s: not sending to ourselves"
8425373Sraghuram " : port %d", __func__, port->p_instance);
8435373Sraghuram continue;
8445373Sraghuram
8455373Sraghuram } else if ((caller == VSW_LOCALDEV) &&
8465373Sraghuram (tpp->d_type == VSW_LOCALDEV)) {
8475935Ssb155480 D2(vswp, "%s: not sending back up stack",
8485373Sraghuram __func__);
8495373Sraghuram continue;
8505373Sraghuram }
8515373Sraghuram
8525373Sraghuram if (tpp->d_type == VSW_VNETPORT) {
8535373Sraghuram port = (vsw_port_t *)tpp->d_addr;
8545373Sraghuram D3(vswp, "%s: sending to port %ld for addr "
8555373Sraghuram "0x%llx", __func__, port->p_instance, key);
8565373Sraghuram
8575373Sraghuram nmp = vsw_dupmsgchain(mp);
8585373Sraghuram if (nmp) {
8595373Sraghuram /*
8605373Sraghuram * The vswp->mfdbrw is protecting the
8615373Sraghuram * portp from getting destroyed here.
8625373Sraghuram * So, no ref_cnt is incremented here.
8635373Sraghuram */
8648275SEric Cheng (void) vsw_portsend(port, nmp);
8655373Sraghuram }
8665373Sraghuram } else {
8675935Ssb155480 vsw_mac_rx(vswp, NULL,
8685935Ssb155480 mp, VSW_MACRX_COPYMSG);
8695935Ssb155480 D2(vswp, "%s: sending up stack"
8705373Sraghuram " for addr 0x%llx", __func__, key);
8715373Sraghuram check_if = B_FALSE;
8725373Sraghuram }
8735373Sraghuram }
8745373Sraghuram }
8755373Sraghuram
8765373Sraghuram RW_EXIT(&vswp->mfdbrw);
8775373Sraghuram
8785373Sraghuram /*
8795373Sraghuram * If the pkt came from either a vnet or from physical device,
8805373Sraghuram * and if we havent already sent the pkt up the stack then we
8815373Sraghuram * check now if we can/should (i.e. the interface is plumbed
8825373Sraghuram * and in promisc mode).
8835373Sraghuram */
8845373Sraghuram if ((check_if) &&
8855373Sraghuram ((caller == VSW_VNETPORT) || (caller == VSW_PHYSDEV))) {
8865935Ssb155480 vsw_mac_rx(vswp, NULL, mp,
8875373Sraghuram VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG);
8885373Sraghuram }
8895373Sraghuram
8905373Sraghuram freemsgchain(mp);
8915373Sraghuram
8925373Sraghuram D1(vswp, "%s: exit", __func__);
8935373Sraghuram
8945373Sraghuram return (0);
8955373Sraghuram }
8965373Sraghuram
8975373Sraghuram /*
8986419Ssb155480 * This function creates the vlan id hash table for the given vsw device or
8996419Ssb155480 * port. It then adds each vlan that the device or port has been assigned,
9006419Ssb155480 * into this hash table.
9016419Ssb155480 * Arguments:
9026419Ssb155480 * arg: vsw device or port.
9036419Ssb155480 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port).
9046419Ssb155480 */
9056419Ssb155480 void
vsw_create_vlans(void * arg,int type)9066419Ssb155480 vsw_create_vlans(void *arg, int type)
9076419Ssb155480 {
9086419Ssb155480 /* create vlan hash table */
9096419Ssb155480 vsw_vlan_create_hash(arg, type);
9106419Ssb155480
9116419Ssb155480 /* add vlan ids of the vsw device into its hash table */
9126419Ssb155480 vsw_vlan_add_ids(arg, type);
9136419Ssb155480 }
9146419Ssb155480
9156419Ssb155480 /*
9166419Ssb155480 * This function removes the vlan ids of the vsw device or port from its hash
9176419Ssb155480 * table. It then destroys the vlan hash table.
9186419Ssb155480 * Arguments:
9196419Ssb155480 * arg: vsw device or port.
9206419Ssb155480 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port).
9216419Ssb155480 */
9226419Ssb155480 void
vsw_destroy_vlans(void * arg,int type)9236419Ssb155480 vsw_destroy_vlans(void *arg, int type)
9246419Ssb155480 {
9256419Ssb155480 /* remove vlan ids from the hash table */
9266419Ssb155480 vsw_vlan_remove_ids(arg, type);
9276419Ssb155480
9286419Ssb155480 /* destroy vlan-hash-table */
9296419Ssb155480 vsw_vlan_destroy_hash(arg, type);
9306419Ssb155480 }
9316419Ssb155480
9326419Ssb155480 /*
9336419Ssb155480 * Create a vlan-id hash table for the given vsw device or port.
9346419Ssb155480 */
9356419Ssb155480 static void
vsw_vlan_create_hash(void * arg,int type)9366419Ssb155480 vsw_vlan_create_hash(void *arg, int type)
9376419Ssb155480 {
9386419Ssb155480 char hashname[MAXNAMELEN];
9396419Ssb155480
9406419Ssb155480 if (type == VSW_LOCALDEV) {
9416419Ssb155480 vsw_t *vswp = (vsw_t *)arg;
9426419Ssb155480
9436419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vsw%d-vlan-hash",
9446419Ssb155480 vswp->instance);
9456419Ssb155480
9466419Ssb155480 vswp->vlan_nchains = vsw_vlan_nchains;
9476419Ssb155480 vswp->vlan_hashp = mod_hash_create_idhash(hashname,
9486419Ssb155480 vswp->vlan_nchains, mod_hash_null_valdtor);
9496419Ssb155480
9506419Ssb155480 } else if (type == VSW_VNETPORT) {
9516419Ssb155480 vsw_port_t *portp = (vsw_port_t *)arg;
9526419Ssb155480
9536419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash",
9546419Ssb155480 portp->p_instance);
9556419Ssb155480
9566419Ssb155480 portp->vlan_nchains = vsw_vlan_nchains;
9576419Ssb155480 portp->vlan_hashp = mod_hash_create_idhash(hashname,
9586419Ssb155480 portp->vlan_nchains, mod_hash_null_valdtor);
9596419Ssb155480
9606419Ssb155480 } else {
9616419Ssb155480 return;
9626419Ssb155480 }
9636419Ssb155480 }
9646419Ssb155480
9656419Ssb155480 /*
9666419Ssb155480 * Destroy the vlan-id hash table for the given vsw device or port.
9676419Ssb155480 */
9686419Ssb155480 static void
vsw_vlan_destroy_hash(void * arg,int type)9696419Ssb155480 vsw_vlan_destroy_hash(void *arg, int type)
9706419Ssb155480 {
9716419Ssb155480 if (type == VSW_LOCALDEV) {
9726419Ssb155480 vsw_t *vswp = (vsw_t *)arg;
9736419Ssb155480
9746419Ssb155480 mod_hash_destroy_hash(vswp->vlan_hashp);
9756419Ssb155480 vswp->vlan_nchains = 0;
9766419Ssb155480 } else if (type == VSW_VNETPORT) {
9776419Ssb155480 vsw_port_t *portp = (vsw_port_t *)arg;
9786419Ssb155480
9796419Ssb155480 mod_hash_destroy_hash(portp->vlan_hashp);
9806419Ssb155480 portp->vlan_nchains = 0;
9816419Ssb155480 } else {
9826419Ssb155480 return;
9836419Ssb155480 }
9846419Ssb155480 }
9856419Ssb155480
9866419Ssb155480 /*
9876419Ssb155480 * Add vlan ids of the given vsw device or port into its hash table.
9885373Sraghuram */
9896419Ssb155480 void
vsw_vlan_add_ids(void * arg,int type)9906419Ssb155480 vsw_vlan_add_ids(void *arg, int type)
9916419Ssb155480 {
9926419Ssb155480 int rv;
9936419Ssb155480 int i;
9946419Ssb155480
9956419Ssb155480 if (type == VSW_LOCALDEV) {
9966419Ssb155480 vsw_t *vswp = (vsw_t *)arg;
9976419Ssb155480
9986419Ssb155480 rv = mod_hash_insert(vswp->vlan_hashp,
9996419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(vswp->pvid),
10006419Ssb155480 (mod_hash_val_t)B_TRUE);
10018275SEric Cheng if (rv != 0) {
10028275SEric Cheng cmn_err(CE_WARN, "vsw%d: Duplicate vlan-id(%d) for "
10038275SEric Cheng "the interface", vswp->instance, vswp->pvid);
10048275SEric Cheng }
10056419Ssb155480
10066419Ssb155480 for (i = 0; i < vswp->nvids; i++) {
10076419Ssb155480 rv = mod_hash_insert(vswp->vlan_hashp,
10088275SEric Cheng (mod_hash_key_t)VLAN_ID_KEY(vswp->vids[i].vl_vid),
10096419Ssb155480 (mod_hash_val_t)B_TRUE);
10108275SEric Cheng if (rv != 0) {
10118275SEric Cheng cmn_err(CE_WARN, "vsw%d: Duplicate vlan-id(%d)"
10128275SEric Cheng " for the interface", vswp->instance,
10138275SEric Cheng vswp->pvid);
10148275SEric Cheng }
10156419Ssb155480 }
10166419Ssb155480
10176419Ssb155480 } else if (type == VSW_VNETPORT) {
10186419Ssb155480 vsw_port_t *portp = (vsw_port_t *)arg;
10198275SEric Cheng vsw_t *vswp = portp->p_vswp;
10206419Ssb155480
10216419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp,
10226419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
10236419Ssb155480 (mod_hash_val_t)B_TRUE);
10248275SEric Cheng if (rv != 0) {
10258275SEric Cheng cmn_err(CE_WARN, "vsw%d: Duplicate vlan-id(%d) for "
10268275SEric Cheng "the port(%d)", vswp->instance, vswp->pvid,
10278275SEric Cheng portp->p_instance);
10288275SEric Cheng }
10296419Ssb155480
10306419Ssb155480 for (i = 0; i < portp->nvids; i++) {
10316419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp,
10328275SEric Cheng (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i].vl_vid),
10336419Ssb155480 (mod_hash_val_t)B_TRUE);
10348275SEric Cheng if (rv != 0) {
10358275SEric Cheng cmn_err(CE_WARN, "vsw%d: Duplicate vlan-id(%d)"
10368275SEric Cheng " for the port(%d)", vswp->instance,
10378275SEric Cheng vswp->pvid, portp->p_instance);
10388275SEric Cheng }
10396419Ssb155480 }
10406419Ssb155480
10416419Ssb155480 }
10426419Ssb155480 }
10436419Ssb155480
10446419Ssb155480 /*
10456419Ssb155480 * Remove vlan ids of the given vsw device or port from its hash table.
10466419Ssb155480 */
10476419Ssb155480 void
vsw_vlan_remove_ids(void * arg,int type)10486419Ssb155480 vsw_vlan_remove_ids(void *arg, int type)
10496419Ssb155480 {
10506419Ssb155480 mod_hash_val_t vp;
10516419Ssb155480 int rv;
10526419Ssb155480 int i;
10536419Ssb155480
10546419Ssb155480 if (type == VSW_LOCALDEV) {
10556419Ssb155480 vsw_t *vswp = (vsw_t *)arg;
10566419Ssb155480
10576419Ssb155480 rv = vsw_vlan_lookup(vswp->vlan_hashp, vswp->pvid);
10586419Ssb155480 if (rv == B_TRUE) {
10596419Ssb155480 rv = mod_hash_remove(vswp->vlan_hashp,
10606419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(vswp->pvid),
10616419Ssb155480 (mod_hash_val_t *)&vp);
10626419Ssb155480 ASSERT(rv == 0);
10636419Ssb155480 }
10646419Ssb155480
10656419Ssb155480 for (i = 0; i < vswp->nvids; i++) {
10668275SEric Cheng rv = vsw_vlan_lookup(vswp->vlan_hashp,
10678275SEric Cheng vswp->vids[i].vl_vid);
10686419Ssb155480 if (rv == B_TRUE) {
10696419Ssb155480 rv = mod_hash_remove(vswp->vlan_hashp,
10708275SEric Cheng (mod_hash_key_t)VLAN_ID_KEY(
10718275SEric Cheng vswp->vids[i].vl_vid),
10726419Ssb155480 (mod_hash_val_t *)&vp);
10736419Ssb155480 ASSERT(rv == 0);
10746419Ssb155480 }
10756419Ssb155480 }
10766419Ssb155480
10776419Ssb155480 } else if (type == VSW_VNETPORT) {
10786419Ssb155480 vsw_port_t *portp = (vsw_port_t *)arg;
10796419Ssb155480
10806419Ssb155480 portp = (vsw_port_t *)arg;
10816419Ssb155480 rv = vsw_vlan_lookup(portp->vlan_hashp, portp->pvid);
10826419Ssb155480 if (rv == B_TRUE) {
10836419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp,
10846419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
10856419Ssb155480 (mod_hash_val_t *)&vp);
10866419Ssb155480 ASSERT(rv == 0);
10876419Ssb155480 }
10886419Ssb155480
10896419Ssb155480 for (i = 0; i < portp->nvids; i++) {
10908275SEric Cheng rv = vsw_vlan_lookup(portp->vlan_hashp,
10918275SEric Cheng portp->vids[i].vl_vid);
10926419Ssb155480 if (rv == B_TRUE) {
10936419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp,
10948275SEric Cheng (mod_hash_key_t)VLAN_ID_KEY(
10958275SEric Cheng portp->vids[i].vl_vid),
10966419Ssb155480 (mod_hash_val_t *)&vp);
10976419Ssb155480 ASSERT(rv == 0);
10986419Ssb155480 }
10996419Ssb155480 }
11006419Ssb155480
11016419Ssb155480 } else {
11026419Ssb155480 return;
11036419Ssb155480 }
11046419Ssb155480 }
11056419Ssb155480
11066419Ssb155480 /*
11076419Ssb155480 * Find the given vlan id in the hash table.
11086419Ssb155480 * Return: B_TRUE if the id is found; B_FALSE if not found.
11096419Ssb155480 */
11106419Ssb155480 boolean_t
vsw_vlan_lookup(mod_hash_t * vlan_hashp,uint16_t vid)11116419Ssb155480 vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid)
11126419Ssb155480 {
11136419Ssb155480 int rv;
11146419Ssb155480 mod_hash_val_t vp;
11156419Ssb155480
11166419Ssb155480 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);
11176419Ssb155480
11186419Ssb155480 if (rv != 0)
11196419Ssb155480 return (B_FALSE);
11206419Ssb155480
11216419Ssb155480 return (B_TRUE);
11226419Ssb155480 }
11236419Ssb155480
11246419Ssb155480 /*
11256419Ssb155480 * Add an entry into FDB for the given vsw.
11266419Ssb155480 */
11276419Ssb155480 void
vsw_fdbe_add(vsw_t * vswp,void * port)11286419Ssb155480 vsw_fdbe_add(vsw_t *vswp, void *port)
11295373Sraghuram {
11305373Sraghuram uint64_t addr = 0;
11316419Ssb155480 vsw_port_t *portp;
11326419Ssb155480 vsw_fdbe_t *fp;
11336419Ssb155480 int rv;
11345373Sraghuram
11356419Ssb155480 portp = (vsw_port_t *)port;
11366419Ssb155480 KEY_HASH(addr, &portp->p_macaddr);
11375373Sraghuram
11386419Ssb155480 fp = kmem_zalloc(sizeof (vsw_fdbe_t), KM_SLEEP);
11396419Ssb155480 fp->portp = port;
11405373Sraghuram
11415373Sraghuram /*
11425373Sraghuram * Note: duplicate keys will be rejected by mod_hash.
11435373Sraghuram */
11446419Ssb155480 rv = mod_hash_insert(vswp->fdb_hashp, (mod_hash_key_t)addr,
11456419Ssb155480 (mod_hash_val_t)fp);
11468275SEric Cheng if (rv != 0) {
11478275SEric Cheng cmn_err(CE_WARN, "vsw%d: Duplicate mac-address(%s) for "
11488275SEric Cheng "the port(%d)", vswp->instance,
11498275SEric Cheng ether_sprintf(&portp->p_macaddr), portp->p_instance);
1150*12300SSriharsha.Basavapatna@Sun.COM kmem_free(fp, sizeof (*fp));
11518275SEric Cheng }
11525373Sraghuram }
11535373Sraghuram
11545373Sraghuram /*
11555373Sraghuram * Remove an entry from FDB.
11565373Sraghuram */
11576419Ssb155480 void
vsw_fdbe_del(vsw_t * vswp,struct ether_addr * eaddr)11586419Ssb155480 vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr)
11595373Sraghuram {
11605373Sraghuram uint64_t addr = 0;
11616419Ssb155480 vsw_fdbe_t *fp;
11626419Ssb155480 int rv;
11635373Sraghuram
11646419Ssb155480 KEY_HASH(addr, eaddr);
11656419Ssb155480
11666419Ssb155480 /*
11676419Ssb155480 * Remove the entry from fdb hash table.
11686419Ssb155480 * This prevents further references to this fdb entry.
11696419Ssb155480 */
11706419Ssb155480 rv = mod_hash_remove(vswp->fdb_hashp, (mod_hash_key_t)addr,
11716419Ssb155480 (mod_hash_val_t *)&fp);
11726419Ssb155480 if (rv != 0) {
11736419Ssb155480 /* invalid key? */
11746419Ssb155480 return;
11756419Ssb155480 }
11766419Ssb155480
11776419Ssb155480 /*
11786419Ssb155480 * If there are threads already ref holding before the entry was
11796419Ssb155480 * removed from hash table, then wait for ref count to drop to zero.
11806419Ssb155480 */
11816419Ssb155480 while (fp->refcnt != 0) {
11826419Ssb155480 delay(drv_usectohz(vsw_fdbe_refcnt_delay));
11836419Ssb155480 }
11846419Ssb155480
11856419Ssb155480 kmem_free(fp, sizeof (*fp));
11866419Ssb155480 }
11875373Sraghuram
11886419Ssb155480 /*
11896419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold
11906419Ssb155480 * a reference to it and return the entry, else returns NULL.
11916419Ssb155480 */
11926419Ssb155480 static vsw_fdbe_t *
vsw_fdbe_find(vsw_t * vswp,struct ether_addr * addrp)11936419Ssb155480 vsw_fdbe_find(vsw_t *vswp, struct ether_addr *addrp)
11946419Ssb155480 {
11956419Ssb155480 uint64_t key = 0;
11966419Ssb155480 vsw_fdbe_t *fp;
11976419Ssb155480 int rv;
11986419Ssb155480
11996419Ssb155480 KEY_HASH(key, addrp);
12006419Ssb155480
12016419Ssb155480 rv = mod_hash_find_cb(vswp->fdb_hashp, (mod_hash_key_t)key,
12026419Ssb155480 (mod_hash_val_t *)&fp, vsw_fdbe_find_cb);
12036419Ssb155480
12046419Ssb155480 if (rv != 0)
12056419Ssb155480 return (NULL);
12066419Ssb155480
12076419Ssb155480 return (fp);
12086419Ssb155480 }
12096419Ssb155480
12106419Ssb155480 /*
12116419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb
12126419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by
12136419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb
12146419Ssb155480 * entry before returning the found entry.
12156419Ssb155480 */
12166419Ssb155480 static void
vsw_fdbe_find_cb(mod_hash_key_t key,mod_hash_val_t val)12176419Ssb155480 vsw_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val)
12186419Ssb155480 {
12196419Ssb155480 _NOTE(ARGUNUSED(key))
12206419Ssb155480 VSW_FDBE_REFHOLD((vsw_fdbe_t *)val);
12216419Ssb155480 }
12225373Sraghuram
12236419Ssb155480 /*
12246419Ssb155480 * A given frame must be always tagged with the appropriate vlan id (unless it
12256419Ssb155480 * is in the default-vlan) before the mac address switching function is called.
12266419Ssb155480 * Otherwise, after switching function determines the destination, we cannot
12276419Ssb155480 * figure out if the destination belongs to the the same vlan that the frame
12286419Ssb155480 * originated from and if it needs tag/untag. Frames which are inbound from
12296419Ssb155480 * the external(physical) network over a vlan trunk link are always tagged.
12306419Ssb155480 * However frames which are received from a vnet-port over ldc or frames which
12316419Ssb155480 * are coming down the stack on the service domain over vsw interface may be
12326419Ssb155480 * untagged. These frames must be tagged with the appropriate pvid of the
12336419Ssb155480 * sender (vnet-port or vsw device), before invoking the switching function.
12346419Ssb155480 *
12356419Ssb155480 * Arguments:
12366419Ssb155480 * arg: caller of the function.
12376419Ssb155480 * type: type of arg(caller): VSW_LOCALDEV(vsw) or VSW_VNETPORT(port)
12386419Ssb155480 * mp: frame(s) to be tagged.
12396419Ssb155480 */
12406419Ssb155480 mblk_t *
vsw_vlan_frame_pretag(void * arg,int type,mblk_t * mp)12416419Ssb155480 vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp)
12426419Ssb155480 {
12436419Ssb155480 vsw_t *vswp;
12446419Ssb155480 vsw_port_t *portp;
12456419Ssb155480 struct ether_header *ehp;
12466419Ssb155480 mblk_t *bp;
12476419Ssb155480 mblk_t *bpt;
12486419Ssb155480 mblk_t *bph;
12496419Ssb155480 mblk_t *bpn;
12506419Ssb155480 uint16_t pvid;
12515373Sraghuram
12526419Ssb155480 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
12535373Sraghuram
12546419Ssb155480 if (type == VSW_LOCALDEV) {
12556419Ssb155480 vswp = (vsw_t *)arg;
12566419Ssb155480 pvid = vswp->pvid;
12576419Ssb155480 portp = NULL;
12586419Ssb155480 } else {
12596419Ssb155480 /* VSW_VNETPORT */
12606419Ssb155480 portp = (vsw_port_t *)arg;
12616419Ssb155480 pvid = portp->pvid;
12626419Ssb155480 vswp = portp->p_vswp;
12636419Ssb155480 }
12646419Ssb155480
12656419Ssb155480 bpn = bph = bpt = NULL;
12666419Ssb155480
12676419Ssb155480 for (bp = mp; bp != NULL; bp = bpn) {
12686419Ssb155480
12696419Ssb155480 bpn = bp->b_next;
12706419Ssb155480 bp->b_next = bp->b_prev = NULL;
12716419Ssb155480
12726419Ssb155480 /* Determine if it is an untagged frame */
12736419Ssb155480 ehp = (struct ether_header *)bp->b_rptr;
12745373Sraghuram
12756419Ssb155480 if (ehp->ether_type != ETHERTYPE_VLAN) { /* untagged */
12766419Ssb155480
12776419Ssb155480 /* no need to tag if the frame is in default vlan */
12786419Ssb155480 if (pvid != vswp->default_vlan_id) {
12796419Ssb155480 bp = vnet_vlan_insert_tag(bp, pvid);
12806419Ssb155480 if (bp == NULL) {
12816419Ssb155480 continue;
12826419Ssb155480 }
12836419Ssb155480 }
12846419Ssb155480 }
12856419Ssb155480
12866419Ssb155480 /* build a chain of processed packets */
12876419Ssb155480 if (bph == NULL) {
12886419Ssb155480 bph = bpt = bp;
12896419Ssb155480 } else {
12906419Ssb155480 bpt->b_next = bp;
12916419Ssb155480 bpt = bp;
12926419Ssb155480 }
12936419Ssb155480
12946419Ssb155480 }
12956419Ssb155480
12966419Ssb155480 return (bph);
12975373Sraghuram }
12985373Sraghuram
12995373Sraghuram /*
13006419Ssb155480 * Frames destined to a vnet-port or to the local vsw interface, must be
13016419Ssb155480 * untagged if necessary before sending. This function first checks that the
13026419Ssb155480 * frame can be sent to the destination in the vlan identified by the frame
13036419Ssb155480 * tag. Note that when this function is invoked the frame must have been
13046419Ssb155480 * already tagged (unless it is in the default-vlan). Because, this function is
13056419Ssb155480 * called when the switching function determines the destination and invokes
13066419Ssb155480 * its send function (vnet-port or vsw interface) and all frames would have
13076419Ssb155480 * been tagged by this time (see comments in vsw_vlan_frame_pretag()).
13086419Ssb155480 *
13096419Ssb155480 * Arguments:
13106419Ssb155480 * arg: destination device.
13116419Ssb155480 * type: type of arg(destination): VSW_LOCALDEV(vsw) or VSW_VNETPORT(port)
13126419Ssb155480 * np: head of pkt chain to be validated and untagged.
13136419Ssb155480 * npt: tail of pkt chain to be validated and untagged.
13146419Ssb155480 *
13156419Ssb155480 * Returns:
13166419Ssb155480 * np: head of updated chain of packets
13176419Ssb155480 * npt: tail of updated chain of packets
13188275SEric Cheng * rv: count of the packets in the returned list
13195373Sraghuram */
13206419Ssb155480 uint32_t
vsw_vlan_frame_untag(void * arg,int type,mblk_t ** np,mblk_t ** npt)13216419Ssb155480 vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, mblk_t **npt)
13225373Sraghuram {
13236419Ssb155480 mblk_t *bp;
13246419Ssb155480 mblk_t *bpt;
13256419Ssb155480 mblk_t *bph;
13266419Ssb155480 mblk_t *bpn;
13276419Ssb155480 vsw_port_t *portp;
13286419Ssb155480 vsw_t *vswp;
13296419Ssb155480 uint32_t count;
13306419Ssb155480 struct ether_header *ehp;
13316419Ssb155480 boolean_t is_tagged;
13326419Ssb155480 boolean_t rv;
13336419Ssb155480 uint16_t vlan_id;
13346419Ssb155480 uint16_t pvid;
13356419Ssb155480 mod_hash_t *vlan_hashp;
13365373Sraghuram
13376419Ssb155480 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
13385373Sraghuram
13398275SEric Cheng
13406419Ssb155480 if (type == VSW_LOCALDEV) {
13416419Ssb155480 vswp = (vsw_t *)arg;
13426419Ssb155480 pvid = vswp->pvid;
13436419Ssb155480 vlan_hashp = vswp->vlan_hashp;
13446419Ssb155480 portp = NULL;
13456419Ssb155480 } else {
13466419Ssb155480 /* type == VSW_VNETPORT */
13476419Ssb155480 portp = (vsw_port_t *)arg;
13486419Ssb155480 vswp = portp->p_vswp;
13496419Ssb155480 vlan_hashp = portp->vlan_hashp;
13506419Ssb155480 pvid = portp->pvid;
13515373Sraghuram }
13525373Sraghuram
13538275SEric Cheng /*
13548275SEric Cheng * If the MAC layer switching in place, then
13558275SEric Cheng * untagging required only if the pvid is not
13568275SEric Cheng * the same as default_vlan_id. This is because,
13578275SEric Cheng * the MAC layer will send packets for the
13588275SEric Cheng * registered vlans only.
13598275SEric Cheng */
13608275SEric Cheng if ((vswp->mac_cl_switching == B_TRUE) &&
13618275SEric Cheng (pvid == vswp->default_vlan_id)) {
13628275SEric Cheng /* simply count and set the tail */
13638275SEric Cheng count = 1;
13648275SEric Cheng bp = *np;
13658275SEric Cheng ASSERT(bp != NULL);
13668275SEric Cheng while (bp->b_next != NULL) {
13678275SEric Cheng bp = bp->b_next;
13688275SEric Cheng count++;
13698275SEric Cheng }
13708275SEric Cheng *npt = bp;
13718275SEric Cheng return (count);
13728275SEric Cheng }
13738275SEric Cheng
13746419Ssb155480 bpn = bph = bpt = NULL;
13756419Ssb155480 count = 0;
13766419Ssb155480
13776419Ssb155480 for (bp = *np; bp != NULL; bp = bpn) {
13786419Ssb155480
13796419Ssb155480 bpn = bp->b_next;
13806419Ssb155480 bp->b_next = bp->b_prev = NULL;
13816419Ssb155480
13826419Ssb155480 /*
13836419Ssb155480 * Determine the vlan id that the frame belongs to.
13846419Ssb155480 */
13856419Ssb155480 ehp = (struct ether_header *)bp->b_rptr;
13866419Ssb155480 is_tagged = vsw_frame_lookup_vid(arg, type, ehp, &vlan_id);
13876419Ssb155480
13886419Ssb155480 /*
13898275SEric Cheng * If MAC layer switching in place, then we
13908275SEric Cheng * need to untag only if the tagged packet has
13918275SEric Cheng * vlan-id same as the pvid.
13926419Ssb155480 */
13938275SEric Cheng if (vswp->mac_cl_switching == B_TRUE) {
13948275SEric Cheng
13958275SEric Cheng /* only tagged packets expected here */
13968275SEric Cheng ASSERT(is_tagged == B_TRUE);
13976419Ssb155480 if (vlan_id == pvid) {
13986419Ssb155480 bp = vnet_vlan_remove_tag(bp);
13996419Ssb155480 if (bp == NULL) {
14006419Ssb155480 /* packet dropped */
14018275SEric Cheng continue;
14028275SEric Cheng }
14038275SEric Cheng }
14048275SEric Cheng } else { /* No MAC layer switching */
14058275SEric Cheng
14068275SEric Cheng /*
14078275SEric Cheng * Check the frame header if tag/untag is needed.
14088275SEric Cheng */
14098275SEric Cheng if (is_tagged == B_FALSE) {
14108275SEric Cheng /*
14118275SEric Cheng * Untagged frame. We shouldn't have an
14128275SEric Cheng * untagged packet at this point, unless
14138275SEric Cheng * the destination's vlan id is
14148275SEric Cheng * default-vlan-id; if it is not the
14158275SEric Cheng * default-vlan-id, we drop the packet.
14168275SEric Cheng */
14178275SEric Cheng if (vlan_id != vswp->default_vlan_id) {
14188275SEric Cheng /* drop the packet */
14198275SEric Cheng freemsg(bp);
14206419Ssb155480 continue;
14216419Ssb155480 }
14228275SEric Cheng } else { /* Tagged */
14238275SEric Cheng /*
14248275SEric Cheng * Tagged frame, untag if it's the
14258275SEric Cheng * destination's pvid.
14268275SEric Cheng */
14278275SEric Cheng if (vlan_id == pvid) {
14288275SEric Cheng
14298275SEric Cheng bp = vnet_vlan_remove_tag(bp);
14308275SEric Cheng if (bp == NULL) {
14318275SEric Cheng /* packet dropped */
14328275SEric Cheng continue;
14338275SEric Cheng }
14348275SEric Cheng } else {
14358275SEric Cheng
14368275SEric Cheng /*
14378275SEric Cheng * Check if the destination is in the
14388275SEric Cheng * same vlan.
14398275SEric Cheng */
14408275SEric Cheng rv = vsw_vlan_lookup(vlan_hashp,
14418275SEric Cheng vlan_id);
14428275SEric Cheng if (rv == B_FALSE) {
14438275SEric Cheng /* drop the packet */
14448275SEric Cheng freemsg(bp);
14458275SEric Cheng continue;
14468275SEric Cheng }
14478275SEric Cheng }
14488275SEric Cheng
14496419Ssb155480 }
14506419Ssb155480 }
14515373Sraghuram
14526419Ssb155480 /* build a chain of processed packets */
14536419Ssb155480 if (bph == NULL) {
14546419Ssb155480 bph = bpt = bp;
14556419Ssb155480 } else {
14566419Ssb155480 bpt->b_next = bp;
14576419Ssb155480 bpt = bp;
14586419Ssb155480 }
14598275SEric Cheng count++;
14606419Ssb155480 }
14616419Ssb155480
14626419Ssb155480 *np = bph;
14636419Ssb155480 *npt = bpt;
14646419Ssb155480 return (count);
14656419Ssb155480 }
14666419Ssb155480
14676419Ssb155480 /*
14686419Ssb155480 * Lookup the vlan id of the given frame. If it is a vlan-tagged frame,
14696419Ssb155480 * then the vlan-id is available in the tag; otherwise, its vlan id is
14706419Ssb155480 * implicitly obtained based on the caller (destination of the frame:
14716419Ssb155480 * VSW_VNETPORT or VSW_LOCALDEV).
14726419Ssb155480 * The vlan id determined is returned in vidp.
14736419Ssb155480 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged.
14746419Ssb155480 */
14756419Ssb155480 boolean_t
vsw_frame_lookup_vid(void * arg,int caller,struct ether_header * ehp,uint16_t * vidp)14766419Ssb155480 vsw_frame_lookup_vid(void *arg, int caller, struct ether_header *ehp,
14776419Ssb155480 uint16_t *vidp)
14786419Ssb155480 {
14796419Ssb155480 struct ether_vlan_header *evhp;
14806419Ssb155480 vsw_t *vswp;
14816419Ssb155480 vsw_port_t *portp;
14826419Ssb155480
14836419Ssb155480 /* If it's a tagged frame, get the vid from vlan header */
14846419Ssb155480 if (ehp->ether_type == ETHERTYPE_VLAN) {
14856419Ssb155480
14866419Ssb155480 evhp = (struct ether_vlan_header *)ehp;
14876419Ssb155480 *vidp = VLAN_ID(ntohs(evhp->ether_tci));
14886419Ssb155480 return (B_TRUE);
14896419Ssb155480 }
14906419Ssb155480
14916419Ssb155480 /* Untagged frame; determine vlan id based on caller */
14926419Ssb155480 switch (caller) {
14936419Ssb155480
14946419Ssb155480 case VSW_VNETPORT:
14956419Ssb155480 /*
14966419Ssb155480 * packet destined to a vnet; vlan-id is pvid of vnet-port.
14976419Ssb155480 */
14986419Ssb155480 portp = (vsw_port_t *)arg;
14996419Ssb155480 *vidp = portp->pvid;
15006419Ssb155480 break;
15016419Ssb155480
15026419Ssb155480 case VSW_LOCALDEV:
15036419Ssb155480
15046419Ssb155480 /*
15056419Ssb155480 * packet destined to vsw interface;
15066419Ssb155480 * vlan-id is port-vlan-id of vsw device.
15076419Ssb155480 */
15086419Ssb155480 vswp = (vsw_t *)arg;
15096419Ssb155480 *vidp = vswp->pvid;
15106419Ssb155480 break;
15116419Ssb155480 }
15126419Ssb155480
15136419Ssb155480 return (B_FALSE);
15145373Sraghuram }
15155373Sraghuram
15165373Sraghuram /*
15175373Sraghuram * Add or remove multicast address(es).
15185373Sraghuram *
15195373Sraghuram * Returns 0 on success, 1 on failure.
15205373Sraghuram */
15215373Sraghuram int
vsw_add_rem_mcst(vnet_mcast_msg_t * mcst_pkt,vsw_port_t * port)15225373Sraghuram vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port)
15235373Sraghuram {
15245373Sraghuram mcst_addr_t *mcst_p = NULL;
15255373Sraghuram vsw_t *vswp = port->p_vswp;
15265373Sraghuram uint64_t addr = 0x0;
15275373Sraghuram int i;
15285373Sraghuram
15295373Sraghuram D1(vswp, "%s: enter", __func__);
15305373Sraghuram
15315373Sraghuram D2(vswp, "%s: %d addresses", __func__, mcst_pkt->count);
15325373Sraghuram
15335373Sraghuram for (i = 0; i < mcst_pkt->count; i++) {
15345373Sraghuram /*
15355373Sraghuram * Convert address into form that can be used
15365373Sraghuram * as hash table key.
15375373Sraghuram */
15386419Ssb155480 KEY_HASH(addr, &(mcst_pkt->mca[i]));
15395373Sraghuram
15405373Sraghuram /*
15415373Sraghuram * Add or delete the specified address/port combination.
15425373Sraghuram */
15435373Sraghuram if (mcst_pkt->set == 0x1) {
15445373Sraghuram D3(vswp, "%s: adding multicast address 0x%llx for "
15455373Sraghuram "port %ld", __func__, addr, port->p_instance);
15465373Sraghuram if (vsw_add_mcst(vswp, VSW_VNETPORT, addr, port) == 0) {
15475373Sraghuram /*
15485373Sraghuram * Update the list of multicast
15495373Sraghuram * addresses contained within the
15505373Sraghuram * port structure to include this new
15515373Sraghuram * one.
15525373Sraghuram */
15535373Sraghuram mcst_p = kmem_zalloc(sizeof (mcst_addr_t),
15545373Sraghuram KM_NOSLEEP);
15555373Sraghuram if (mcst_p == NULL) {
15565373Sraghuram DERR(vswp, "%s: unable to alloc mem",
15575373Sraghuram __func__);
15585373Sraghuram (void) vsw_del_mcst(vswp,
15595373Sraghuram VSW_VNETPORT, addr, port);
15605373Sraghuram return (1);
15615373Sraghuram }
15625373Sraghuram
15635373Sraghuram mcst_p->nextp = NULL;
15645373Sraghuram mcst_p->addr = addr;
15655373Sraghuram ether_copy(&mcst_pkt->mca[i], &mcst_p->mca);
15665373Sraghuram
15675373Sraghuram /*
15685373Sraghuram * Program the address into HW. If the addr
15695373Sraghuram * has already been programmed then the MAC
15705373Sraghuram * just increments a ref counter (which is
15715373Sraghuram * used when the address is being deleted)
15725373Sraghuram */
15738275SEric Cheng if (vsw_mac_multicast_add(vswp, port, mcst_p,
15748275SEric Cheng VSW_VNETPORT)) {
15758275SEric Cheng (void) vsw_del_mcst(vswp,
15768275SEric Cheng VSW_VNETPORT, addr, port);
15778275SEric Cheng kmem_free(mcst_p, sizeof (*mcst_p));
15788275SEric Cheng return (1);
15795373Sraghuram }
15805373Sraghuram
15815373Sraghuram mutex_enter(&port->mca_lock);
15825373Sraghuram mcst_p->nextp = port->mcap;
15835373Sraghuram port->mcap = mcst_p;
15845373Sraghuram mutex_exit(&port->mca_lock);
15855373Sraghuram
15865373Sraghuram } else {
15875373Sraghuram DERR(vswp, "%s: error adding multicast "
15885373Sraghuram "address 0x%llx for port %ld",
15895373Sraghuram __func__, addr, port->p_instance);
15905373Sraghuram return (1);
15915373Sraghuram }
15925373Sraghuram } else {
15935373Sraghuram /*
15945373Sraghuram * Delete an entry from the multicast hash
15955373Sraghuram * table and update the address list
15965373Sraghuram * appropriately.
15975373Sraghuram */
15985373Sraghuram if (vsw_del_mcst(vswp, VSW_VNETPORT, addr, port) == 0) {
15995373Sraghuram D3(vswp, "%s: deleting multicast address "
16005373Sraghuram "0x%llx for port %ld", __func__, addr,
16015373Sraghuram port->p_instance);
16025373Sraghuram
16035373Sraghuram mcst_p = vsw_del_addr(VSW_VNETPORT, port, addr);
16045373Sraghuram ASSERT(mcst_p != NULL);
16055373Sraghuram
16065373Sraghuram /*
16075373Sraghuram * Remove the address from HW. The address
16085373Sraghuram * will actually only be removed once the ref
16095373Sraghuram * count within the MAC layer has dropped to
16105373Sraghuram * zero. I.e. we can safely call this fn even
16115373Sraghuram * if other ports are interested in this
16125373Sraghuram * address.
16135373Sraghuram */
16148275SEric Cheng vsw_mac_multicast_remove(vswp, port, mcst_p,
16158275SEric Cheng VSW_VNETPORT);
16165373Sraghuram kmem_free(mcst_p, sizeof (*mcst_p));
16175373Sraghuram
16185373Sraghuram } else {
16195373Sraghuram DERR(vswp, "%s: error deleting multicast "
16205373Sraghuram "addr 0x%llx for port %ld",
16215373Sraghuram __func__, addr, port->p_instance);
16225373Sraghuram return (1);
16235373Sraghuram }
16245373Sraghuram }
16255373Sraghuram }
16265373Sraghuram D1(vswp, "%s: exit", __func__);
16275373Sraghuram return (0);
16285373Sraghuram }
16295373Sraghuram
16305373Sraghuram /*
16315373Sraghuram * Add a new multicast entry.
16325373Sraghuram *
16335373Sraghuram * Search hash table based on address. If match found then
16345373Sraghuram * update associated val (which is chain of ports), otherwise
16355373Sraghuram * create new key/val (addr/port) pair and insert into table.
16365373Sraghuram */
16375373Sraghuram int
vsw_add_mcst(vsw_t * vswp,uint8_t devtype,uint64_t addr,void * arg)16385373Sraghuram vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg)
16395373Sraghuram {
16405373Sraghuram int dup = 0;
16415373Sraghuram int rv = 0;
16425373Sraghuram mfdb_ent_t *ment = NULL;
16435373Sraghuram mfdb_ent_t *tmp_ent = NULL;
16445373Sraghuram mfdb_ent_t *new_ent = NULL;
16455373Sraghuram void *tgt = NULL;
16465373Sraghuram
16475373Sraghuram if (devtype == VSW_VNETPORT) {
16485373Sraghuram /*
16495373Sraghuram * Being invoked from a vnet.
16505373Sraghuram */
16515373Sraghuram ASSERT(arg != NULL);
16525373Sraghuram tgt = arg;
16535373Sraghuram D2(NULL, "%s: port %d : address 0x%llx", __func__,
16545373Sraghuram ((vsw_port_t *)arg)->p_instance, addr);
16555373Sraghuram } else {
16565373Sraghuram /*
16575373Sraghuram * We are being invoked via the m_multicst mac entry
16585373Sraghuram * point.
16595373Sraghuram */
16605373Sraghuram D2(NULL, "%s: address 0x%llx", __func__, addr);
16615373Sraghuram tgt = (void *)vswp;
16625373Sraghuram }
16635373Sraghuram
16645373Sraghuram WRITE_ENTER(&vswp->mfdbrw);
16655373Sraghuram if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr,
16665373Sraghuram (mod_hash_val_t *)&ment) != 0) {
16675373Sraghuram
16685373Sraghuram /* address not currently in table */
16695373Sraghuram ment = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP);
16705373Sraghuram ment->d_addr = (void *)tgt;
16715373Sraghuram ment->d_type = devtype;
16725373Sraghuram ment->nextp = NULL;
16735373Sraghuram
16745373Sraghuram if (mod_hash_insert(vswp->mfdb, (mod_hash_key_t)addr,
16755373Sraghuram (mod_hash_val_t)ment) != 0) {
16765373Sraghuram DERR(vswp, "%s: hash table insertion failed", __func__);
16775373Sraghuram kmem_free(ment, sizeof (mfdb_ent_t));
16785373Sraghuram rv = 1;
16795373Sraghuram } else {
16805373Sraghuram D2(vswp, "%s: added initial entry for 0x%llx to "
16815373Sraghuram "table", __func__, addr);
16825373Sraghuram }
16835373Sraghuram } else {
16845373Sraghuram /*
16855373Sraghuram * Address in table. Check to see if specified port
16865373Sraghuram * is already associated with the address. If not add
16875373Sraghuram * it now.
16885373Sraghuram */
16895373Sraghuram tmp_ent = ment;
16905373Sraghuram while (tmp_ent != NULL) {
16915373Sraghuram if (tmp_ent->d_addr == (void *)tgt) {
16925373Sraghuram if (devtype == VSW_VNETPORT) {
16935373Sraghuram DERR(vswp, "%s: duplicate port entry "
16945373Sraghuram "found for portid %ld and key "
16955373Sraghuram "0x%llx", __func__,
16965373Sraghuram ((vsw_port_t *)arg)->p_instance,
16975373Sraghuram addr);
16985373Sraghuram } else {
16995373Sraghuram DERR(vswp, "%s: duplicate entry found"
17005373Sraghuram "for key 0x%llx", __func__, addr);
17015373Sraghuram }
17025373Sraghuram rv = 1;
17035373Sraghuram dup = 1;
17045373Sraghuram break;
17055373Sraghuram }
17065373Sraghuram tmp_ent = tmp_ent->nextp;
17075373Sraghuram }
17085373Sraghuram
17095373Sraghuram /*
17105373Sraghuram * Port not on list so add it to end now.
17115373Sraghuram */
17125373Sraghuram if (0 == dup) {
17135373Sraghuram D2(vswp, "%s: added entry for 0x%llx to table",
17145373Sraghuram __func__, addr);
17155373Sraghuram new_ent = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP);
17165373Sraghuram new_ent->d_addr = (void *)tgt;
17175373Sraghuram new_ent->d_type = devtype;
17185373Sraghuram new_ent->nextp = NULL;
17195373Sraghuram
17205373Sraghuram tmp_ent = ment;
17215373Sraghuram while (tmp_ent->nextp != NULL)
17225373Sraghuram tmp_ent = tmp_ent->nextp;
17235373Sraghuram
17245373Sraghuram tmp_ent->nextp = new_ent;
17255373Sraghuram }
17265373Sraghuram }
17275373Sraghuram
17285373Sraghuram RW_EXIT(&vswp->mfdbrw);
17295373Sraghuram return (rv);
17305373Sraghuram }
17315373Sraghuram
17325373Sraghuram /*
17335373Sraghuram * Remove a multicast entry from the hashtable.
17345373Sraghuram *
17355373Sraghuram * Search hash table based on address. If match found, scan
17365373Sraghuram * list of ports associated with address. If specified port
17375373Sraghuram * found remove it from list.
17385373Sraghuram */
17395373Sraghuram int
vsw_del_mcst(vsw_t * vswp,uint8_t devtype,uint64_t addr,void * arg)17405373Sraghuram vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg)
17415373Sraghuram {
17425373Sraghuram mfdb_ent_t *ment = NULL;
17435373Sraghuram mfdb_ent_t *curr_p, *prev_p;
17445373Sraghuram void *tgt = NULL;
17455373Sraghuram
17465373Sraghuram D1(vswp, "%s: enter", __func__);
17475373Sraghuram
17485373Sraghuram if (devtype == VSW_VNETPORT) {
17495373Sraghuram tgt = (vsw_port_t *)arg;
17505373Sraghuram D2(vswp, "%s: removing port %d from mFDB for address"
17515373Sraghuram " 0x%llx", __func__, ((vsw_port_t *)tgt)->p_instance, addr);
17525373Sraghuram } else {
17535373Sraghuram D2(vswp, "%s: removing entry", __func__);
17545373Sraghuram tgt = (void *)vswp;
17555373Sraghuram }
17565373Sraghuram
17575373Sraghuram WRITE_ENTER(&vswp->mfdbrw);
17585373Sraghuram if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr,
17595373Sraghuram (mod_hash_val_t *)&ment) != 0) {
17605373Sraghuram D2(vswp, "%s: address 0x%llx not in table", __func__, addr);
17615373Sraghuram RW_EXIT(&vswp->mfdbrw);
17625373Sraghuram return (1);
17635373Sraghuram }
17645373Sraghuram
17655373Sraghuram prev_p = curr_p = ment;
17665373Sraghuram
17675373Sraghuram while (curr_p != NULL) {
17685373Sraghuram if (curr_p->d_addr == (void *)tgt) {
17695373Sraghuram if (devtype == VSW_VNETPORT) {
17705373Sraghuram D2(vswp, "%s: port %d found", __func__,
17715373Sraghuram ((vsw_port_t *)tgt)->p_instance);
17725373Sraghuram } else {
17735373Sraghuram D2(vswp, "%s: instance found", __func__);
17745373Sraghuram }
17755373Sraghuram
17765373Sraghuram if (prev_p == curr_p) {
17775373Sraghuram /*
17785373Sraghuram * head of list, if no other element is in
17795373Sraghuram * list then destroy this entry, otherwise
17805373Sraghuram * just replace it with updated value.
17815373Sraghuram */
17825373Sraghuram ment = curr_p->nextp;
17835373Sraghuram if (ment == NULL) {
17845373Sraghuram (void) mod_hash_destroy(vswp->mfdb,
17855373Sraghuram (mod_hash_val_t)addr);
17865373Sraghuram } else {
17875373Sraghuram (void) mod_hash_replace(vswp->mfdb,
17885373Sraghuram (mod_hash_key_t)addr,
17895373Sraghuram (mod_hash_val_t)ment);
17905373Sraghuram }
17915373Sraghuram } else {
17925373Sraghuram /*
17935373Sraghuram * Not head of list, no need to do
17945373Sraghuram * replacement, just adjust list pointers.
17955373Sraghuram */
17965373Sraghuram prev_p->nextp = curr_p->nextp;
17975373Sraghuram }
17985373Sraghuram break;
17995373Sraghuram }
18005373Sraghuram
18015373Sraghuram prev_p = curr_p;
18025373Sraghuram curr_p = curr_p->nextp;
18035373Sraghuram }
18045373Sraghuram
18055373Sraghuram RW_EXIT(&vswp->mfdbrw);
18065373Sraghuram
18075373Sraghuram D1(vswp, "%s: exit", __func__);
18085373Sraghuram
18095373Sraghuram if (curr_p == NULL)
18105373Sraghuram return (1);
18115373Sraghuram kmem_free(curr_p, sizeof (mfdb_ent_t));
18125373Sraghuram return (0);
18135373Sraghuram }
18145373Sraghuram
18155373Sraghuram /*
18165373Sraghuram * Port is being deleted, but has registered an interest in one
18175373Sraghuram * or more multicast groups. Using the list of addresses maintained
18185373Sraghuram * within the port structure find the appropriate entry in the hash
18195373Sraghuram * table and remove this port from the list of interested ports.
18205373Sraghuram */
18215373Sraghuram void
vsw_del_mcst_port(vsw_port_t * port)18225373Sraghuram vsw_del_mcst_port(vsw_port_t *port)
18235373Sraghuram {
18245373Sraghuram mcst_addr_t *mcap = NULL;
18255373Sraghuram vsw_t *vswp = port->p_vswp;
18265373Sraghuram
18275373Sraghuram D1(vswp, "%s: enter", __func__);
18285373Sraghuram
18295373Sraghuram mutex_enter(&port->mca_lock);
18305373Sraghuram
18315373Sraghuram while ((mcap = port->mcap) != NULL) {
18325373Sraghuram
18335373Sraghuram port->mcap = mcap->nextp;
18345373Sraghuram
18355373Sraghuram mutex_exit(&port->mca_lock);
18365373Sraghuram
18375373Sraghuram (void) vsw_del_mcst(vswp, VSW_VNETPORT,
18385373Sraghuram mcap->addr, port);
18395373Sraghuram
18405373Sraghuram /*
18415373Sraghuram * Remove the address from HW. The address
18425373Sraghuram * will actually only be removed once the ref
18435373Sraghuram * count within the MAC layer has dropped to
18445373Sraghuram * zero. I.e. we can safely call this fn even
18455373Sraghuram * if other ports are interested in this
18465373Sraghuram * address.
18475373Sraghuram */
18488275SEric Cheng vsw_mac_multicast_remove(vswp, port, mcap, VSW_VNETPORT);
18495373Sraghuram kmem_free(mcap, sizeof (*mcap));
18505373Sraghuram
18515373Sraghuram mutex_enter(&port->mca_lock);
18525373Sraghuram
18535373Sraghuram }
18545373Sraghuram
18555373Sraghuram mutex_exit(&port->mca_lock);
18565373Sraghuram
18575373Sraghuram D1(vswp, "%s: exit", __func__);
18585373Sraghuram }
18595373Sraghuram
18605373Sraghuram /*
18615373Sraghuram * This vsw instance is detaching, but has registered an interest in one
18625373Sraghuram * or more multicast groups. Using the list of addresses maintained
18635373Sraghuram * within the vsw structure find the appropriate entry in the hash
18645373Sraghuram * table and remove this instance from the list of interested ports.
18655373Sraghuram */
18665373Sraghuram void
vsw_del_mcst_vsw(vsw_t * vswp)18675373Sraghuram vsw_del_mcst_vsw(vsw_t *vswp)
18685373Sraghuram {
18695373Sraghuram mcst_addr_t *next_p = NULL;
18705373Sraghuram
18715373Sraghuram D1(vswp, "%s: enter", __func__);
18725373Sraghuram
18735373Sraghuram mutex_enter(&vswp->mca_lock);
18745373Sraghuram
18755373Sraghuram while (vswp->mcap != NULL) {
18765373Sraghuram DERR(vswp, "%s: deleting addr 0x%llx",
18775373Sraghuram __func__, vswp->mcap->addr);
18785373Sraghuram (void) vsw_del_mcst(vswp, VSW_LOCALDEV, vswp->mcap->addr, NULL);
18795373Sraghuram
18805373Sraghuram next_p = vswp->mcap->nextp;
18815373Sraghuram kmem_free(vswp->mcap, sizeof (mcst_addr_t));
18825373Sraghuram vswp->mcap = next_p;
18835373Sraghuram }
18845373Sraghuram
18855373Sraghuram vswp->mcap = NULL;
18865373Sraghuram mutex_exit(&vswp->mca_lock);
18875373Sraghuram
18885373Sraghuram D1(vswp, "%s: exit", __func__);
18895373Sraghuram }
18905373Sraghuram
18918275SEric Cheng mblk_t *
vsw_get_same_dest_list(struct ether_header * ehp,mblk_t ** mpp)18928275SEric Cheng vsw_get_same_dest_list(struct ether_header *ehp, mblk_t **mpp)
18935373Sraghuram {
18945935Ssb155480 mblk_t *bp;
18955935Ssb155480 mblk_t *nbp;
18965935Ssb155480 mblk_t *head = NULL;
18975935Ssb155480 mblk_t *tail = NULL;
18985935Ssb155480 mblk_t *prev = NULL;
18995935Ssb155480 struct ether_header *behp;
19005373Sraghuram
19015373Sraghuram /* process the chain of packets */
19025373Sraghuram bp = *mpp;
19035373Sraghuram while (bp) {
19045373Sraghuram nbp = bp->b_next;
19055373Sraghuram behp = (struct ether_header *)bp->b_rptr;
19065373Sraghuram bp->b_prev = NULL;
19075373Sraghuram if (ether_cmp(&ehp->ether_dhost, &behp->ether_dhost) == 0) {
19085373Sraghuram if (prev == NULL) {
19095373Sraghuram *mpp = nbp;
19105373Sraghuram } else {
19115373Sraghuram prev->b_next = nbp;
19125373Sraghuram }
19135373Sraghuram bp->b_next = NULL;
19145373Sraghuram if (head == NULL) {
19155373Sraghuram head = tail = bp;
19165373Sraghuram } else {
19175373Sraghuram tail->b_next = bp;
19185373Sraghuram tail = bp;
19195373Sraghuram }
19205373Sraghuram } else {
19215373Sraghuram prev = bp;
19225373Sraghuram }
19235373Sraghuram bp = nbp;
19245373Sraghuram }
19258275SEric Cheng return (head);
19265373Sraghuram }
19275373Sraghuram
19285373Sraghuram static mblk_t *
vsw_dupmsgchain(mblk_t * mp)19295373Sraghuram vsw_dupmsgchain(mblk_t *mp)
19305373Sraghuram {
19315373Sraghuram mblk_t *nmp = NULL;
19325373Sraghuram mblk_t **nmpp = &nmp;
19335373Sraghuram
19345373Sraghuram for (; mp != NULL; mp = mp->b_next) {
19355373Sraghuram if ((*nmpp = dupmsg(mp)) == NULL) {
19365373Sraghuram freemsgchain(nmp);
19375373Sraghuram return (NULL);
19385373Sraghuram }
19395373Sraghuram
19405373Sraghuram nmpp = &((*nmpp)->b_next);
19415373Sraghuram }
19425373Sraghuram
19435373Sraghuram return (nmp);
19445373Sraghuram }
1945