package org.freertr.ifc; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import org.freertr.addr.addrBridge; import org.freertr.addr.addrMac; import org.freertr.addr.addrType; import org.freertr.ip.ipCor; import org.freertr.ip.ipCor4; import org.freertr.ip.ipCor6; import org.freertr.ip.ipIcmp6; import org.freertr.ip.ipIfc4; import org.freertr.ip.ipIfc4arp; import org.freertr.ip.ipIfc6; import org.freertr.ip.ipMhost4; import org.freertr.ip.ipMhost6; import org.freertr.pack.packHolder; import org.freertr.pack.packPim; import org.freertr.pack.packPimGrp; import org.freertr.pack.packStp; import org.freertr.tab.tabGen; import org.freertr.tab.tabLabel; import org.freertr.tab.tabLabelEntry; import org.freertr.tab.tabRouteUtil; import org.freertr.tab.tabSession; import org.freertr.user.userFormat; import org.freertr.user.userHelping; import org.freertr.util.bits; import org.freertr.util.cmds; import org.freertr.util.counter; import org.freertr.util.debugger; import org.freertr.util.logger; import org.freertr.util.state; /** * bridges interfaces to one broadcast domain * * @author matecsaba */ public class ifcBridge implements ifcDn { /** * ethernet type of serial lines */ public final static int serialType = 0x6558; /** * size of serial header */ public final static int serialSize = 2; /** * description of this bridge */ public String description = ""; /** * label */ public tabLabelEntry label; /** * route distinguisher */ public long rd; /** * route target import */ public long rtImp; /** * route target export */ public long rtExp; /** * hardware address of the bridge */ public addrMac hwaddr; /** * mac address aging time */ public int macAgeTime = 10 * 60 * 1000; /** * group aging time */ public int grpAgeTime = 3 * 60 * 1000; /** * limit mac addresses */ public int macLimit; /** * log mac movements */ public boolean macMove; /** * block unicast with unknown destination */ public boolean blockUnicast; /** * block multicast with unknown destination */ public boolean blockMulticast; /** * disable peer communication */ public boolean privateBridge; /** * pad to minimum */ public boolean padupSmall; /** * hw address is static */ public boolean staticAddr; /** * spantree mode: 0=none, 1=ieee, 2=drop */ public int needStp; /** * spantree priority */ public int stpPrio = 32768; /** * max age */ public int stpAge = 20000; /** * forward time */ public int stpFwd = 15000; /** * hello time */ public int stpHlo = 2000; /** * mac router to notify */ public ifcBridgeRtr macRouter = null; /** * inspection */ public tabSession inspect; private tabGen ifaces; private tabGen learned; private ifcUp upper = new ifcNull(); private int nextIfaceNum; private counter cntr = new counter(); private Timer timer; private long currTim = bits.getTime(); private int stpPort; private boolean upProm; private final ifcBridgeIfc upNtry; private ipCor core4 = new ipCor4(); private ipCor core6 = new ipCor6(); /** * root id */ protected addrBridge stpRoot; /** * root cost */ protected int stpCost; public counter getCounter() { return cntr; } public state.states getState() { return state.states.up; } public void setFilter(boolean promisc) { upProm = promisc; } public addrType getHwAddr() { return hwaddr; } /** * set upper layer * * @param server upper layer */ public void setUpper(ifcUp server) { upper = server; upper.setParent(this); } public void closeDn() { upper = null; } public void flapped() { } /** * create new instance */ public ifcBridge() { hwaddr = addrMac.getRandom(); if (debugger.ifcBridgeTraf) { logger.debug("started, addr=" + hwaddr); } nextIfaceNum = 1; ifaces = new tabGen(); upNtry = new ifcBridgeIfc(null, true, false, false); upNtry.ifcNum = 0; upNtry.publicPort = true; upNtry.lowerIf = null; } /** * get show output * * @return list of interface */ public userFormat getShowIfc() { userFormat lst = new userFormat("|", "iface|fwd|phys|tx|rx|drop|tx|rx|drop|grp", "3|3packet|3byte|1"); lst.add("" + upNtry); for (int i = 0; i < ifaces.size(); i++) { lst.add("" + ifaces.get(i).getShowIfc()); } return lst; } /** * get show output * * @return list of interface */ public userFormat getShowStp() { if (needStp == 0) { return null; } userFormat lst = new userFormat("|", "iface|fwd|phys|tx|rx|drop"); lst.add("" + upNtry); for (int i = 0; i < ifaces.size(); i++) { lst.add("" + ifaces.get(i).getShowStp()); } return lst; } /** * get show output * * @return list of interface */ public userFormat getShowAdr() { if (learned == null) { return null; } userFormat lst = new userFormat("|", "addr|iface|static|time|tx|rx|drop|tx|rx|drop", "4|3packet|3byte"); for (int i = 0; i < learned.size(); i++) { lst.add("" + learned.get(i)); } return lst; } /** * get show output * * @return list of interface */ public userFormat getShowInsp() { if (inspect == null) { return null; } return inspect.doShowInsp(); } /** * get upper mac list * * @return list of macs */ public List getMacList() { List lst = new ArrayList(); if (learned == null) { return lst; } for (int i = 0; i < learned.size(); i++) { ifcBridgeAdr ntry = learned.get(i); if (!ntry.ifc.physical) { continue; } lst.add(ntry.adr); } return lst; } /** * get mac address * * @param i sequence * @return address, null if not found */ public ifcBridgeAdr getMacAddr(int i) { if (learned == null) { return null; } return learned.get(i); } /** * find mac address * * @param mac address to find * @return address, null if not found */ public ifcBridgeAdr findMacAddr(addrMac mac) { if (learned == null) { return null; } ifcBridgeAdr ntry = new ifcBridgeAdr(mac); return learned.find(ntry); } /** * get interface * * @param i sequence * @return interface, null if not found */ public ifcBridgeIfc getIface(int i) { return ifaces.get(i); } /** * get help text * * @param l storage */ public static void getHelp(userHelping l) { l.add(null, "1 2,. description description of this bridge"); l.add(null, "2 2,. [text] text describing this bridge"); l.add(null, "1 2 rd specify route distinguisher"); l.add(null, "2 . rd in ASnum:IDnum format"); l.add(null, "1 2 rt-import specify route target import"); l.add(null, "2 . rt in ASnum:IDnum format"); l.add(null, "1 2 rt-export specify route target export"); l.add(null, "2 . rt in ASnum:IDnum format"); l.add(null, "1 2 rt-both specify route target"); l.add(null, "2 . rt in ASnum:IDnum format"); l.add(null, "1 . mac-learn enable mac address learning"); l.add(null, "1 2,. inspect enable session inspection"); l.add(null, "2 2,. mac enable mac logging"); l.add(null, "2 2,. before log on session start"); l.add(null, "2 2,. after log on session stop"); l.add(null, "1 . mac-move enable mac move logging"); l.add(null, "1 2 mac-limit limit number of addesses"); l.add(null, "2 . maximum"); l.add(null, "1 . private-bridge disable peer communication"); l.add(null, "1 . block-unicast block unknown destination unicast"); l.add(null, "1 . block-multicast block unwanted destination multicast"); l.add(null, "1 . padup-small pad up small packets"); l.add(null, "1 2 mac-age set mac aging time"); l.add(null, "2 . time in ms"); l.add(null, "1 2 stp-mode set spantree mode"); l.add(null, "2 . ieee ieee"); l.add(null, "2 . none pass through"); l.add(null, "2 . drop drop"); l.add(null, "1 2 stp-time set spantree timers"); l.add(null, "2 3 hello in ms"); l.add(null, "3 4 maxage in ms"); l.add(null, "4 . forward delay in ms"); l.add(null, "1 2 stp-priority set spantree priority"); l.add(null, "2 . priority in 1024 increments"); l.add(null, "1 2 mac-address set mac address"); l.add(null, "2 . mac address"); } /** * get configuration * * @param l storage * @param beg beginning */ public void getConfig(List l, String beg) { cmds.cfgLine(l, description.length() < 1, cmds.tabulator, "description", description); l.add(cmds.tabulator + "rd " + tabRouteUtil.rd2string(rd)); l.add(cmds.tabulator + "rt-import " + tabRouteUtil.rd2string(rtImp)); l.add(cmds.tabulator + "rt-export " + tabRouteUtil.rd2string(rtExp)); cmds.cfgLine(l, !staticAddr, beg, "mac-address", "" + hwaddr); cmds.cfgLine(l, learned == null, beg, "mac-learn", ""); cmds.cfgLine(l, inspect == null, beg, "inspect", "" + inspect); cmds.cfgLine(l, !macMove, beg, "mac-move", ""); cmds.cfgLine(l, !privateBridge, beg, "private-bridge", ""); cmds.cfgLine(l, !blockUnicast, beg, "block-unicast", ""); cmds.cfgLine(l, !blockMulticast, beg, "block-multicast", ""); cmds.cfgLine(l, !padupSmall, beg, "padup-small", ""); l.add(beg + "mac-limit " + macLimit); l.add(beg + "mac-age " + macAgeTime); l.add(beg + "stp-priority " + stpPrio); l.add(beg + "stp-time " + stpHlo + " " + stpAge + " " + stpFwd); String a; switch (needStp) { case 0: a = "none"; break; case 1: a = "ieee"; break; case 2: a = "drop"; break; default: a = "unknown"; break; } l.add(beg + "stp-mode " + a); } /** * do configuration * * @param cmd command */ public void doConfig(cmds cmd) { String a = cmd.word(); if (a.equals("description")) { description = cmd.getRemaining(); return; } if (a.equals("rd")) { rd = tabRouteUtil.string2rd(cmd.word()); return; } if (a.equals("rt-import")) { rtImp = tabRouteUtil.string2rd(cmd.word()); return; } if (a.equals("rt-export")) { rtExp = tabRouteUtil.string2rd(cmd.word()); return; } if (a.equals("rt-both")) { rtExp = tabRouteUtil.string2rd(cmd.word()); rtImp = rtExp; return; } if (a.equals("inspect")) { if (inspect != null) { inspect.stopTimer(); } inspect = new tabSession(true, 180000); inspect.fromString(cmd); inspect.startTimer(); return; } if (a.equals("mac-limit")) { macLimit = bits.str2num(cmd.word()); return; } if (a.equals("mac-move")) { macMove = true; return; } if (a.equals("mac-learn")) { learned = new tabGen(); return; } if (a.equals("private-bridge")) { privateBridge = true; return; } if (a.equals("padup-small")) { padupSmall = true; return; } if (a.equals("block-unicast")) { blockUnicast = true; return; } if (a.equals("block-multicast")) { blockMulticast = true; return; } if (a.equals("mac-age")) { macAgeTime = bits.str2num(cmd.word()); return; } if (a.equals("stp-mode")) { a = cmd.word(); if (a.equals("none")) { needStp = 0; setBlocking(false); return; } if (a.equals("ieee")) { needStp = 1; setBlocking(true); return; } if (a.equals("drop")) { needStp = 2; setBlocking(false); return; } cmd.badCmd(); return; } if (a.equals("stp-time")) { stpHlo = bits.str2num(cmd.word()); stpAge = bits.str2num(cmd.word()); stpFwd = bits.str2num(cmd.word()); return; } if (a.equals("mac-address")) { addrMac adr = new addrMac(); if (adr.fromString(cmd.word())) { cmd.error("bad address"); return; } hwaddr.setAddr(adr); staticAddr = true; return; } if (a.equals("stp-priority")) { stpPrio = bits.str2num(cmd.word()); return; } if (!a.equals(cmds.negated)) { cmd.badCmd(); return; } a = cmd.word(); if (a.equals("description")) { description = ""; return; } if (a.equals("rd")) { rd = 0; return; } if (a.equals("rt-import")) { rtImp = 0; return; } if (a.equals("rt-export")) { rtExp = 0; return; } if (a.equals("mac-learn")) { learned = null; return; } if (a.equals("inspect")) { if (inspect != null) { inspect.stopTimer(); } inspect = null; return; } if (a.equals("mac-limit")) { macLimit = 0; return; } if (a.equals("mac-move")) { macMove = false; return; } if (a.equals("private-bridge")) { privateBridge = false; return; } if (a.equals("padup-small")) { padupSmall = false; return; } if (a.equals("block-unicast")) { blockUnicast = false; return; } if (a.equals("block-multicast")) { blockMulticast = false; return; } if (a.equals("mac-address")) { staticAddr = false; return; } cmd.badCmd(); } /** * add new interface to this virtual bridge * * @param physical true if physical interface * @param notEther true if dst,src mac is embedded in data * @param needType true if ethertype need appened * @return interface handler that will pass packets to this bridge */ public ifcBridgeIfc newIface(boolean physical, boolean notEther, boolean needType) { if (debugger.ifcBridgeTraf) { logger.debug("add iface"); } ifcBridgeIfc ntry = new ifcBridgeIfc(this, physical, notEther, needType); ntry.ifcNum = nextIfaceNum++; ntry.blocked = needStp == 1; ifaces.add(ntry); return ntry; } /** * delete one interface from this virtual bridge * * @param num inteface number * @return lower interface handler (null=error) */ public ifcDn delIface(int num) { if (debugger.ifcBridgeTraf) { logger.debug("del iface"); } ifcBridgeIfc ntry = new ifcBridgeIfc(this, false, false, false); ntry.ifcNum = num; ntry = ifaces.del(ntry); if (ntry == null) { return null; } delMacs(ntry); return ntry.lowerIf; } /** * add mac on interface * * @param ifc interface * @param adr address */ public void addMac(ifcBridgeIfc ifc, addrMac adr) { if (adr == null) { return; } if (learned == null) { return; } ifcBridgeAdr ntry = new ifcBridgeAdr(adr.copyBytes()); ntry.stat = true; ntry.ifc = ifc; ntry.cntr = new counter(); learned.put(ntry); } /** * add macs on interface * * @param ifc interface * @param lst addresses */ public void addMacs(ifcBridgeIfc ifc, tabGen lst) { if (lst == null) { return; } for (int i = 0; i < lst.size(); i++) { addMac(ifc, lst.get(i)); } } /** * add macs on all the interface */ public void addMacs() { for (int i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ntry = ifaces.get(i); if (ntry == null) { continue; } addMacs(ntry, ntry.statAddr); } } /** * delete macs on interface * * @param ifc interface, null means all */ public void delMacs(ifcBridgeIfc ifc) { if (learned == null) { return; } if (ifc == null) { learned.clear(); addMacs(); if (macRouter != null) { macRouter.bridgeChanged(); } return; } int seen = 0; for (int i = learned.size() - 1; i >= 0; i--) { ifcBridgeAdr mac = learned.get(i); if (mac == null) { continue; } if (ifc != mac.ifc) { continue; } learned.del(mac); seen++; } if (seen < 1) { return; } if ((macRouter != null) && (ifc.physical)) { macRouter.bridgeChanged(); } } private void send2upper(ifcBridgeIfc ifc, packHolder pck) { if (ifc.ifcNum == 0) { return; } cntr.tx(pck); if (upper == null) { cntr.drop(pck, counter.reasons.noIface); return; } upper.recvPack(pck); } public void sendPack(packHolder pck) { cntr.rx(pck); pck.merge2beg(); doRxPack(upNtry, pck); } public String toString() { return "bridge " + hwaddr; } public int getMTUsize() { int p = 1500; for (int i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ntry = ifaces.get(i); int o = ntry.lowerIf.getMTUsize(); if (p > o) { p = o; } } return p; } public long getBandwidth() { long p = 100000000; for (int i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ntry = ifaces.get(i); long o = ntry.lowerIf.getBandwidth(); if (p > o) { p = o; } } return p; } private void resetTimer(boolean needRun) { try { timer.cancel(); } catch (Exception e) { } timer = null; if (!needRun) { return; } timer = new Timer(); ifcBridgeTimer task = new ifcBridgeTimer(this); timer.schedule(task, 500, 1000); } /** * do startup */ public void doStartup() { if (debugger.ifcBridgeTraf) { logger.debug("startup"); } label = tabLabel.allocate(tabLabelEntry.owner.bridge); label.setFwdDrop(tabLabelEntry.owner.bridge); resetTimer(true); } /** * do startup */ public void doShutdown() { if (debugger.ifcBridgeTraf) { logger.debug("shutdown"); } tabLabel.release(label, tabLabelEntry.owner.bridge); resetTimer(false); } /** * purge group addresses * * @param rnd round number */ protected void doGroupPurge(int rnd) { if ((rnd % 60) != 0) { return; } currTim = bits.getTime(); if (debugger.ifcBridgeTraf) { logger.debug("purge"); } for (int o = 0; o < ifaces.size(); o++) { ifcBridgeIfc ifc = ifaces.get(o); if (ifc == null) { continue; } if (ifc.groups == null) { continue; } for (int i = ifc.groups.size() - 1; i >= 0; i--) { ifcBridgeGrp grp = ifc.groups.get(i); if (grp == null) { continue; } if ((currTim - grp.time) < grpAgeTime) { continue; } ifc.groups.del(grp); } } } /** * purge mac address cache * * @param rnd round number */ protected void doCachePurge(int rnd) { if ((rnd % 60) != 0) { return; } currTim = bits.getTime(); if (debugger.ifcBridgeTraf) { logger.debug("purge"); } if (learned == null) { return; } for (int i = learned.size() - 1; i >= 0; i--) { ifcBridgeAdr ntry = learned.get(i); if (ntry == null) { continue; } if (ntry.stat) { continue; } if ((currTim - ntry.time) < macAgeTime) { continue; } if (debugger.ifcBridgeTraf) { logger.debug("purge " + ntry); } if (macMove) { logger.info(ntry.adr + " disappeared from " + ntry.ifc.getIfcName()); } learned.del(ntry); if ((macRouter != null) && (ntry.ifc.physical)) { macRouter.bridgeChanged(); } } } /** * flood stp packets * * @param rnd round number */ protected void doStpFloop(int rnd) { if (needStp != 1) { return; } if ((rnd % (stpHlo / 1000)) != 0) { return; } long rootTime = 0; for (int i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ntry = ifaces.get(i); if (ntry == null) { continue; } if ((currTim - ntry.stpTime) > stpFwd) { ntry.blocked = false; } if (ntry.ifcNum == stpPort) { rootTime = ntry.stpTime; } if (ntry.fltrStpOut) { continue; } packStp pckS = ntry.getStpId(); if (debugger.ifcBridgeTraf) { logger.debug("tx " + pckS); } packHolder pckB = new packHolder(true, true); pckS.createHeader(pckB); ntry.stpCntr.tx(pckB); ntry.doTxPack(pckB); } if (stpPort == 0) { return; } if ((currTim - rootTime) > stpAge) { setBlocking(true); } } private void floodPack(ifcBridgeIfc ifc, packHolder pck) { for (int i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ntry = ifaces.get(i); if (ntry == null) { continue; } if (ifc.ifcNum == ntry.ifcNum) { continue; } if (ntry.blocked) { continue; } if (!(ifc.physical | ntry.physical)) { continue; } if ((privateBridge | ifc.privatePort | ntry.privatePort) && !ifc.publicPort && !ntry.publicPort) { continue; } ntry.doTxPack(pck.copyBytes(true, true)); } send2upper(ifc, pck); } /** * notify the bridge that a packet arrived to a virtual interface * * @param ifc interface handler that got the packet * @param pck the packet that arrived */ protected void doRxPack(ifcBridgeIfc ifc, packHolder pck) { if (!doRxStp(ifc, pck)) { return; } if (ifc.blocked) { return; } if (inspect != null) { int i = pck.dataSize(); pck.getSkip(2); boolean b; boolean bb = false; switch (pck.ETHtype) { case ipIfc4arp.type: b = false; bb = true; break; case ipIfc4.type: b = core4.parseIPheader(pck, false); break; case ipIfc6.type: b = core6.parseIPheader(pck, false); break; default: b = true; break; } if (!b && !bb) { b = inspect.doPack(pck, false); } int o = pck.dataSize(); pck.getSkip(o - i); if (b) { return; } } if (padupSmall) { int pad = 48 - pck.dataSize(); if (pad > 0) { pck.putFill(0, pad, 0); pck.putSkip(pad); pck.merge2end(); } } if (learned == null) { floodPack(ifc, pck); return; } ifcBridgeAdr lrn = new ifcBridgeAdr(pck.ETHsrc.copyBytes()); lrn.ifc = ifc; lrn.cntr = new counter(); ifcBridgeAdr old = learned.add(lrn); if (old != null) { if (ifc != old.ifc) { if (old.stat) { cntr.drop(pck, counter.reasons.denied); return; } if (macMove) { logger.info(pck.ETHsrc + " moved from " + old.ifc.getIfcName() + " to " + ifc.getIfcName()); } } lrn = old; } else { if (macLimit > 0) { if (learned.size() > macLimit) { learned.del(lrn); return; } } if (macMove) { logger.info(pck.ETHsrc + " learned from " + ifc.getIfcName()); } if ((ifc.physical) && (macRouter != null)) { macRouter.bridgeChanged(); } } lrn.ifc = ifc; lrn.time = currTim; lrn.cntr.rx(pck); if (pck.ETHtrg.isFloodable()) { if (!blockMulticast) { floodPack(ifc, pck); return; } int i = pck.dataSize(); pck.getSkip(2); boolean b = false; switch (pck.ETHtype) { case ipIfc4arp.type: b = true; break; case ipIfc4.type: if (core4.parseIPheader(pck, false)) { return; } pck.getSkip(pck.IPsiz); if (pck.IPprt == ipMhost4.protoNum) { b = !ipMhost4.parsePacket(ifc, ifc, pck); } break; case ipIfc6.type: if (core6.parseIPheader(pck, false)) { return; } pck.getSkip(pck.IPsiz); if (pck.IPprt == ipIcmp6.protoNum) { ipIcmp6.parseICMPports(pck); pck.getSkip(ipIcmp6.size); b = !ipMhost6.parsePacket(ifc, ifc, pck); } break; default: return; } if (pck.IPprt == packPim.proto) { packPim pckPim = new packPim(); if (!pckPim.parseHeader(pck)) { pckPim.parsePayload(pck); } if (pckPim.groups != null) { for (int o = 0; o < pckPim.groups.size(); o++) { packPimGrp grp = pckPim.groups.get(o); for (int p = 0; p < grp.joins.size(); p++) { ifc.mhostReport(ifc, grp.group.network, grp.joins.get(p).network, true); } for (int p = 0; p < grp.prunes.size(); p++) { ifc.mhostReport(ifc, grp.group.network, grp.prunes.get(p).network, false); } } } b = true; } int o = pck.dataSize(); pck.getSkip(o - i); if (b) { floodPack(ifc, pck); return; } if (pck.IPbrd) { floodPack(ifc, pck); return; } if (!pck.IPmlt) { return; } if (!pck.IPmlr) { floodPack(ifc, pck); return; } ifcBridgeGrp grp = new ifcBridgeGrp(pck.IPtrg); for (i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ntry = ifaces.get(i); if (ntry == null) { continue; } if (ifc.ifcNum == ntry.ifcNum) { continue; } if (ntry.blocked) { continue; } if (!(ifc.physical | ntry.physical)) { continue; } if (ntry.groups == null) { continue; } if ((privateBridge | ifc.privatePort | ntry.privatePort) && !ifc.publicPort && !ntry.publicPort) { continue; } if (ntry.groups.find(grp) == null) { continue; } ntry.doTxPack(pck.copyBytes(true, true)); } send2upper(ifc, pck); return; } lrn = new ifcBridgeAdr(pck.ETHtrg.copyBytes()); lrn = learned.find(lrn); if (lrn == null) { if (blockUnicast) { if (upProm) { send2upper(ifc, pck); } return; } floodPack(ifc, pck); return; } if (lrn.ifc.ifcNum == ifc.ifcNum) { return; } lrn.cntr.tx(pck); if (lrn.ifc.ifcNum == 0) { send2upper(ifc, pck); return; } if (upProm) { send2upper(ifc, pck.copyBytes(true, true)); } if ((privateBridge | ifc.privatePort | lrn.ifc.privatePort) && !ifc.publicPort && !lrn.ifc.publicPort) { return; } if (!(ifc.physical | lrn.ifc.physical)) { return; } lrn.ifc.doTxPack(pck); } /** * get spantree id * * @return spantree id */ protected addrBridge getStpId() { addrBridge b = new addrBridge(); b.adr.setAddr(hwaddr); b.pri = stpPrio; return b; } private void setBlocking(boolean blk) { if (debugger.ifcBridgeTraf) { logger.debug("setting ports"); } stpRoot = getStpId(); stpPort = 0; stpCost = 0; if (learned != null) { learned.clear(); addMacs(); } if (macMove) { logger.info("table flush"); } if (macRouter != null) { macRouter.bridgeChanged(); } for (int i = 0; i < ifaces.size(); i++) { ifcBridgeIfc ifc = ifaces.get(i); if (ifc == null) { continue; } ifc.blocked = blk; ifc.stpTime = currTim; } } private boolean doRxStp(ifcBridgeIfc ifc, packHolder pck) { ifc.stpCntr.rx(pck); if (needStp == 0) { ifc.stpCntr.drop(pck, counter.reasons.notUp); return true; } packStp stp = new packStp(); if (stp.parseHeader(pck)) { ifc.stpCntr.drop(pck, counter.reasons.badHdr); return true; } if (needStp == 2) { ifc.stpCntr.drop(pck, counter.reasons.noBuffer); return false; } if (debugger.ifcBridgeTraf) { logger.debug("rx " + stp); } ifc.stpTime = currTim; if (ifc.fltrStpIn) { ifc.blocked = true; return false; } int cst = stp.rootCost + addrBridge.bandwidth2cost(ifc.lowerIf.getBandwidth()); int i = stpRoot.compareTo(stp.rootId); if (i < 0) { // worst root ifc.blocked = true; return false; } if (i > 0) { // better root if (ifc.fltrStpRoot) { ifc.blocked = true; return false; } setBlocking(true); stpRoot = stp.rootId.copyBytes(); stpCost = cst; stpPort = ifc.ifcNum; ifc.blocked = false; return false; } if (stpCost > cst) { // better cost if (ifc.fltrStpRoot) { ifc.blocked = true; return false; } stpCost = cst; stpPort = ifc.ifcNum; ifc.blocked = false; return false; } if (stpCost == cst) { // alternate port ifc.blocked = ifc.ifcNum != stpPort; return false; } if (stpCost < stp.rootCost) { // worst cost ifc.blocked = false; return false; } i = getStpId().compareTo(stp.brdgId); if (i == 0) { ifc.blocked = ifc.ifcNum <= stp.portId; } else { ifc.blocked = i < 0; } return false; } } class ifcBridgeTimer extends TimerTask { private ifcBridge lower; private int cntr; public ifcBridgeTimer(ifcBridge parent) { lower = parent; } public void run() { try { cntr = (cntr + 1) & 0xffff; lower.doGroupPurge(cntr); lower.doCachePurge(cntr); lower.doStpFloop(cntr); } catch (Exception e) { logger.traceback(e); } } }