void log_freemsg(mblk_t *mp) { mblk_t *mp2 = mp->b_cont; ASSERT(MBLKL(mp) == sizeof (log_ctl_t)); ASSERT(mp2->b_rptr == mp2->b_datap->db_base); if ((log_freeq->q_flag & QFULL) == 0 && MBLKL(mp2) <= LOG_MSGSIZE && MBLKSIZE(mp2) >= LOG_MSGSIZE) (void) putq(log_freeq, mp); else freemsg(mp); }
/* * Switch ethernet frame when in layer 3 mode (i.e. using IP * layer to do the routing). * * There is a large amount of overlap between this function and * vsw_switch_l2_frame. At some stage we need to revisit and refactor * both these functions. */ void vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg, mac_resource_handle_t mrh) { struct ether_header *ehp; mblk_t *bp = NULL; vsw_fdbe_t *fp; D1(vswp, "%s: enter (caller %d)", __func__, caller); /* * In layer 3 mode should only ever be switching packets * between IP layer and vnet devices. So make sure thats * who is invoking us. */ if ((caller != VSW_LOCALDEV) && (caller != VSW_VNETPORT)) { DERR(vswp, "%s: unexpected caller (%d)", __func__, caller); freemsgchain(mp); return; } /* process the chain of packets */ bp = mp; while (bp) { ehp = (struct ether_header *)bp->b_rptr; mp = vsw_get_same_dest_list(ehp, &bp); ASSERT(mp != NULL); D2(vswp, "%s: mblk data buffer %lld : actual data size %lld", __func__, MBLKSIZE(mp), MBLKL(mp)); /* * Find fdb entry for the destination * and hold a reference to it. */ fp = vsw_fdbe_find(vswp, &ehp->ether_dhost); if (fp != NULL) { D2(vswp, "%s: sending to target port", __func__); (void) vsw_portsend(fp->portp, mp); /* Release the reference on the fdb entry */ VSW_FDBE_REFRELE(fp); } else { /* * Destination not in FDB * * If the destination is broadcast or * multicast forward the packet to all * (VNETPORTs, PHYSDEV, LOCALDEV), * except the caller. */ if (IS_BROADCAST(ehp)) { D2(vswp, "%s: BROADCAST pkt", __func__); (void) vsw_forward_all(vswp, mp, caller, arg); } else if (IS_MULTICAST(ehp)) { D2(vswp, "%s: MULTICAST pkt", __func__); (void) vsw_forward_grp(vswp, mp, caller, arg); } else { /* * Unicast pkt from vnet that we don't have * an FDB entry for, so must be destinded for * the outside world. Attempt to send up to the * IP layer to allow it to deal with it. */ if (caller == VSW_VNETPORT) { vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_FREEMSG); } } } } D1(vswp, "%s: exit", __func__); }
/* * Switch the given ethernet frame when operating in layer 2 mode. * * vswp: pointer to the vsw instance * mp: pointer to chain of ethernet frame(s) to be switched * caller: identifies the source of this frame as: * 1. VSW_VNETPORT - a vsw port (connected to a vnet). * 2. VSW_PHYSDEV - the physical ethernet device * 3. VSW_LOCALDEV - vsw configured as a virtual interface * arg: argument provided by the caller. * 1. for VNETPORT - pointer to the corresponding vsw_port_t. * 2. for PHYSDEV - NULL * 3. for LOCALDEV - pointer to to this vsw_t(self) */ void vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg, mac_resource_handle_t mrh) { struct ether_header *ehp; mblk_t *bp, *ret_m; vsw_fdbe_t *fp; D1(vswp, "%s: enter (caller %d)", __func__, caller); /* * PERF: rather than breaking up the chain here, scan it * to find all mblks heading to same destination and then * pass that sub-chain to the lower transmit functions. */ /* process the chain of packets */ bp = mp; while (bp) { ehp = (struct ether_header *)bp->b_rptr; mp = vsw_get_same_dest_list(ehp, &bp); ASSERT(mp != NULL); D2(vswp, "%s: mblk data buffer %lld : actual data size %lld", __func__, MBLKSIZE(mp), MBLKL(mp)); if (ether_cmp(&ehp->ether_dhost, &vswp->if_addr) == 0) { /* * If destination is VSW_LOCALDEV (vsw as an eth * interface) and if the device is up & running, * send the packet up the stack on this host. * If the virtual interface is down, drop the packet. */ if (caller != VSW_LOCALDEV) { vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_FREEMSG); } else { freemsgchain(mp); } continue; } /* * Find fdb entry for the destination * and hold a reference to it. */ fp = vsw_fdbe_find(vswp, &ehp->ether_dhost); if (fp != NULL) { /* * If plumbed and in promisc mode then copy msg * and send up the stack. */ vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG); /* * If the destination is in FDB, the packet * should be forwarded to the correponding * vsw_port (connected to a vnet device - * VSW_VNETPORT) */ (void) vsw_portsend(fp->portp, mp); /* Release the reference on the fdb entry */ VSW_FDBE_REFRELE(fp); } else { /* * Destination not in FDB. * * If the destination is broadcast or * multicast forward the packet to all * (VNETPORTs, PHYSDEV, LOCALDEV), * except the caller. */ if (IS_BROADCAST(ehp)) { D2(vswp, "%s: BROADCAST pkt", __func__); (void) vsw_forward_all(vswp, mp, caller, arg); } else if (IS_MULTICAST(ehp)) { D2(vswp, "%s: MULTICAST pkt", __func__); (void) vsw_forward_grp(vswp, mp, caller, arg); } else { /* * If the destination is unicast, and came * from either a logical network device or * the switch itself when it is plumbed, then * send it out on the physical device and also * up the stack if the logical interface is * in promiscious mode. * * NOTE: The assumption here is that if we * cannot find the destination in our fdb, its * a unicast address, and came from either a * vnet or down the stack (when plumbed) it * must be destinded for an ethernet device * outside our ldoms. */ if (caller == VSW_VNETPORT) { /* promisc check copy etc */ vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG); if ((ret_m = vsw_tx_msg(vswp, mp, caller, arg)) != NULL) { DERR(vswp, "%s: drop mblks to " "phys dev", __func__); freemsgchain(ret_m); } } else if (caller == VSW_PHYSDEV) { /* * Pkt seen because card in promisc * mode. Send up stack if plumbed in * promisc mode, else drop it. */ vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_PROMISC | VSW_MACRX_FREEMSG); } else if (caller == VSW_LOCALDEV) { /* * Pkt came down the stack, send out * over physical device. */ if ((ret_m = vsw_tx_msg(vswp, mp, caller, NULL)) != NULL) { DERR(vswp, "%s: drop mblks to " "phys dev", __func__); freemsgchain(ret_m); } } } } } D1(vswp, "%s: exit\n", __func__); }