/* ------------------------------------------------------------------------ */ void ipf_lookup_iterderef(ipf_main_softc_t *softc, u_32_t type, void *data) { ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; struct iplookupiterkey *lkey; iplookupiterkey_t key; int i; key.ilik_key = type; lkey = &key.ilik_unstr; if (lkey->ilik_ival != IPFGENITER_LOOKUP) return; WRITE_ENTER(&softc->ipf_poolrw); for (i = 0; i < MAX_BACKENDS; i++) { if (lkey->ilik_type == backends[i]->ipfl_type) { (*backends[i]->ipfl_iter_deref)(softc, softl->ipf_back[i], lkey->ilik_otype, lkey->ilik_unit, data); break; } } RWLOCK_EXIT(&softc->ipf_poolrw); }
static int ipf_modunload(void) { int error, i; if (fr_refcnt) return EBUSY; if (fr_running >= 0) { ipf_pfil_unhook(); ipf_event_dereg(); WRITE_ENTER(&ipf_global); error = ipfdetach(); RWLOCK_EXIT(&ipf_global); if (error != 0) return error; } else error = 0; RW_DESTROY(&ipf_global); RW_DESTROY(&ipf_mutex); RW_DESTROY(&ipf_frcache); fr_running = -2; for (i = 0; ipf_devfiles[i]; i++) { if (ipf_devs[i] != NULL) destroy_dev(ipf_devs[i]); } printf("%s unloaded\n", ipfilter_version); return error; }
/* * Program unicast and multicast addresses of vsw interface and the ports * into the network device. */ void vsw_set_addrs(vsw_t *vswp) { vsw_port_list_t *plist = &vswp->plist; vsw_port_t *port; int rv; READ_ENTER(&vswp->if_lockrw); if (vswp->if_state & VSW_IF_UP) { /* Open a mac client and program addresses */ rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV); if (rv != 0) { cmn_err(CE_NOTE, "!vsw%d: failed to program interface " "unicast address\n", vswp->instance); } /* * Notify the MAC layer of the changed address. */ if (rv == 0) { mac_unicst_update(vswp->if_mh, (uint8_t *)&vswp->if_addr); } } RW_EXIT(&vswp->if_lockrw); WRITE_ENTER(&plist->lockrw); /* program unicast address of ports in the network device */ for (port = plist->head; port != NULL; port = port->p_next) { if (port->addr_set) /* addr already set */ continue; /* Open a mac client and program addresses */ rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT); if (rv != 0) { cmn_err(CE_NOTE, "!vsw%d: failed to program port(%d) " "unicast address\n", vswp->instance, port->p_instance); } } /* announce macaddr of vnets to the physical switch */ if (vsw_publish_macaddr_count != 0) { /* enabled */ for (port = plist->head; port != NULL; port = port->p_next) { vsw_publish_macaddr(vswp, port); } } RW_EXIT(&plist->lockrw); }
/* ------------------------------------------------------------------------ */ void ipf_lookup_expire(ipf_main_softc_t *softc) { ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; int i; WRITE_ENTER(&softc->ipf_poolrw); for (i = 0; i < MAX_BACKENDS; i++) (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]); RWLOCK_EXIT(&softc->ipf_poolrw); }
/* ------------------------------------------------------------------------ */ static int ipf_lookup_iterate(ipf_main_softc_t *softc, void *data, int uid, void *ctx) { ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; ipflookupiter_t iter; ipftoken_t *token; int err, i; SPL_INT(s); err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER); if (err != 0) return err; if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) { IPFERROR(50038); return EINVAL; } if (iter.ili_ival != IPFGENITER_LOOKUP) { IPFERROR(50039); return EINVAL; } SPL_SCHED(s); token = ipf_token_find(softc, iter.ili_key, uid, ctx); if (token == NULL) { SPL_X(s); IPFERROR(50040); return ESRCH; } for (i = 0; i < MAX_BACKENDS; i++) { if (iter.ili_type == backends[i]->ipfl_type) { err = (*backends[i]->ipfl_iter_next)(softc, softl->ipf_back[i], token, &iter); break; } } SPL_X(s); if (i == MAX_BACKENDS) { IPFERROR(50041); err = EINVAL; } WRITE_ENTER(&softc->ipf_tokens); ipf_token_deref(softc, token); RWLOCK_EXIT(&softc->ipf_tokens); return err; }
/* * vsw_port_mac_reconfig -- Cleanup and close the MAC client * and reopen and re-configure the MAC client with new flags etc. * This function is useful for two different purposes: * 1) To update the MAC client with new vlan-ids. This is done * by freeing the existing vlan-ids and reopen with the new * vlan-ids. * * 2) If the Hybrid mode status of a port changes, then the * MAC client need to be closed and re-opened, otherwise, * Share related resources may not be freed(hybird mode disabled) * or assigned(hybrid mode enabled). To accomplish this, * this function simply closes and reopens the MAC client. * The reopen will result in using the flags based on the * new hybrid mode of the port. */ void vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans, uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids) { vsw_t *vswp = portp->p_vswp; int rv; D1(vswp, "%s: enter", __func__); /* * Remove the multi-cast addresses, unicast address * and close the mac-client. */ mutex_enter(&vswp->mac_lock); WRITE_ENTER(&portp->maccl_rwlock); vsw_mac_multicast_remove_all(vswp, portp, VSW_VNETPORT); vsw_unset_hw(vswp, portp, VSW_VNETPORT); vsw_maccl_close(vswp, portp, VSW_VNETPORT); if (update_vlans == B_TRUE) { if (portp->nvids != 0) { kmem_free(portp->vids, sizeof (vsw_vlanid_t) * portp->nvids); portp->vids = NULL; portp->nvids = 0; } portp->vids = new_vids; portp->nvids = new_nvids; portp->pvid = new_pvid; } /* * Now re-open the mac-client and * configure unicast addr and multicast addrs. */ rv = vsw_maccl_open(vswp, portp, VSW_VNETPORT); if (rv != 0) { goto recret; } if (vsw_set_hw(vswp, portp, VSW_VNETPORT)) { cmn_err(CE_NOTE, "!vsw%d: port:%d failed to " "set unicast address\n", vswp->instance, portp->p_instance); goto recret; } vsw_mac_multicast_add_all(vswp, portp, VSW_VNETPORT); recret: RW_EXIT(&portp->maccl_rwlock); mutex_exit(&vswp->mac_lock); D1(vswp, "%s: exit", __func__); }
int ipsc_add(caddr_t data) { ipscan_t *i, *isc; int err; KMALLOC(isc, ipscan_t *); if (!isc) return ENOMEM; err = copyinptr(data, isc, sizeof(*isc)); if (err) { KFREE(isc); return err; } WRITE_ENTER(&ipsc_rwlock); i = ipsc_lookup(isc->ipsc_tag); if (i) { RWLOCK_EXIT(&ipsc_rwlock); KFREE(isc); return EEXIST; } if (ipsc_tail) { ipsc_tail->ipsc_next = isc; isc->ipsc_pnext = &ipsc_tail->ipsc_next; ipsc_tail = isc; } else { ipsc_list = isc; ipsc_tail = isc; isc->ipsc_pnext = &ipsc_list; } isc->ipsc_next = NULL; isc->ipsc_hits = 0; isc->ipsc_fref = 0; isc->ipsc_sref = 0; isc->ipsc_active = 0; ipsc_stat.iscs_entries++; RWLOCK_EXIT(&ipsc_rwlock); return 0; }
/* ------------------------------------------------------------------------ */ void ipf_lookup_deref(ipf_main_softc_t *softc, int type, void *ptr) { ipf_lookup_softc_t *softl = softc->ipf_lookup_soft; int i; if (ptr == NULL) return; for (i = 0; i < MAX_BACKENDS; i++) { if (type == backends[i]->ipfl_type) { WRITE_ENTER(&softc->ipf_poolrw); (*backends[i]->ipfl_table_deref)(softc, softl->ipf_back[i], ptr); RWLOCK_EXIT(&softc->ipf_poolrw); break; } } }
int ipsc_delete(caddr_t data) { ipscan_t isc, *i; int err; err = copyinptr(data, &isc, sizeof(isc)); if (err) return err; WRITE_ENTER(&ipsc_rwlock); i = ipsc_lookup(isc.ipsc_tag); if (i == NULL) err = ENOENT; else { if (i->ipsc_fref) { RWLOCK_EXIT(&ipsc_rwlock); return EBUSY; } *i->ipsc_pnext = i->ipsc_next; if (i->ipsc_next) i->ipsc_next->ipsc_pnext = i->ipsc_pnext; else { if (i->ipsc_pnext == &ipsc_list) ipsc_tail = NULL; else ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext; } ipsc_stat.iscs_entries--; KFREE(i); } RWLOCK_EXIT(&ipsc_rwlock); return err; }
/* ------------------------------------------------------------------------ */ int ipf_lookup_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, int uid, void *ctx) { int err; SPL_INT(s); mode = mode; /* LINT */ SPL_NET(s); switch (cmd) { case SIOCLOOKUPADDNODE : case SIOCLOOKUPADDNODEW : WRITE_ENTER(&softc->ipf_poolrw); err = ipf_lookup_addnode(softc, data, uid); RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPDELNODE : case SIOCLOOKUPDELNODEW : WRITE_ENTER(&softc->ipf_poolrw); err = ipf_lookup_delnode(softc, data, uid); RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPADDTABLE : WRITE_ENTER(&softc->ipf_poolrw); err = ipf_lookup_addtable(softc, data); RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPDELTABLE : WRITE_ENTER(&softc->ipf_poolrw); err = ipf_lookup_deltable(softc, data); RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPSTAT : case SIOCLOOKUPSTATW : WRITE_ENTER(&softc->ipf_poolrw); err = ipf_lookup_stats(softc, data); RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPFLUSH : WRITE_ENTER(&softc->ipf_poolrw); err = ipf_lookup_flush(softc, data); RWLOCK_EXIT(&softc->ipf_poolrw); break; case SIOCLOOKUPITER : err = ipf_lookup_iterate(softc, data, uid, ctx); break; case SIOCIPFDELTOK : err = ipf_lookup_deltok(softc, data, uid, ctx); break; default : IPFERROR(50001); err = EINVAL; break; } SPL_X(s); return err; }
/* * Remove a multicast entry from the hashtable. * * Search hash table based on address. If match found, scan * list of ports associated with address. If specified port * found remove it from list. */ int vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg) { mfdb_ent_t *ment = NULL; mfdb_ent_t *curr_p, *prev_p; void *tgt = NULL; D1(vswp, "%s: enter", __func__); if (devtype == VSW_VNETPORT) { tgt = (vsw_port_t *)arg; D2(vswp, "%s: removing port %d from mFDB for address" " 0x%llx", __func__, ((vsw_port_t *)tgt)->p_instance, addr); } else { D2(vswp, "%s: removing entry", __func__); tgt = (void *)vswp; } WRITE_ENTER(&vswp->mfdbrw); if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t *)&ment) != 0) { D2(vswp, "%s: address 0x%llx not in table", __func__, addr); RW_EXIT(&vswp->mfdbrw); return (1); } prev_p = curr_p = ment; while (curr_p != NULL) { if (curr_p->d_addr == (void *)tgt) { if (devtype == VSW_VNETPORT) { D2(vswp, "%s: port %d found", __func__, ((vsw_port_t *)tgt)->p_instance); } else { D2(vswp, "%s: instance found", __func__); } if (prev_p == curr_p) { /* * head of list, if no other element is in * list then destroy this entry, otherwise * just replace it with updated value. */ ment = curr_p->nextp; if (ment == NULL) { (void) mod_hash_destroy(vswp->mfdb, (mod_hash_val_t)addr); } else { (void) mod_hash_replace(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t)ment); } } else { /* * Not head of list, no need to do * replacement, just adjust list pointers. */ prev_p->nextp = curr_p->nextp; } break; } prev_p = curr_p; curr_p = curr_p->nextp; } RW_EXIT(&vswp->mfdbrw); D1(vswp, "%s: exit", __func__); if (curr_p == NULL) return (1); kmem_free(curr_p, sizeof (mfdb_ent_t)); return (0); }
/* * Add a new multicast entry. * * Search hash table based on address. If match found then * update associated val (which is chain of ports), otherwise * create new key/val (addr/port) pair and insert into table. */ int vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg) { int dup = 0; int rv = 0; mfdb_ent_t *ment = NULL; mfdb_ent_t *tmp_ent = NULL; mfdb_ent_t *new_ent = NULL; void *tgt = NULL; if (devtype == VSW_VNETPORT) { /* * Being invoked from a vnet. */ ASSERT(arg != NULL); tgt = arg; D2(NULL, "%s: port %d : address 0x%llx", __func__, ((vsw_port_t *)arg)->p_instance, addr); } else { /* * We are being invoked via the m_multicst mac entry * point. */ D2(NULL, "%s: address 0x%llx", __func__, addr); tgt = (void *)vswp; } WRITE_ENTER(&vswp->mfdbrw); if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t *)&ment) != 0) { /* address not currently in table */ ment = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP); ment->d_addr = (void *)tgt; ment->d_type = devtype; ment->nextp = NULL; if (mod_hash_insert(vswp->mfdb, (mod_hash_key_t)addr, (mod_hash_val_t)ment) != 0) { DERR(vswp, "%s: hash table insertion failed", __func__); kmem_free(ment, sizeof (mfdb_ent_t)); rv = 1; } else { D2(vswp, "%s: added initial entry for 0x%llx to " "table", __func__, addr); } } else { /* * Address in table. Check to see if specified port * is already associated with the address. If not add * it now. */ tmp_ent = ment; while (tmp_ent != NULL) { if (tmp_ent->d_addr == (void *)tgt) { if (devtype == VSW_VNETPORT) { DERR(vswp, "%s: duplicate port entry " "found for portid %ld and key " "0x%llx", __func__, ((vsw_port_t *)arg)->p_instance, addr); } else { DERR(vswp, "%s: duplicate entry found" "for key 0x%llx", __func__, addr); } rv = 1; dup = 1; break; } tmp_ent = tmp_ent->nextp; } /* * Port not on list so add it to end now. */ if (0 == dup) { D2(vswp, "%s: added entry for 0x%llx to table", __func__, addr); new_ent = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP); new_ent->d_addr = (void *)tgt; new_ent->d_type = devtype; new_ent->nextp = NULL; tmp_ent = ment; while (tmp_ent->nextp != NULL) tmp_ent = tmp_ent->nextp; tmp_ent->nextp = new_ent; } } RW_EXIT(&vswp->mfdbrw); return (rv); }