package org.freertr.tab; import java.util.ArrayList; import java.util.List; import org.freertr.addr.addrIP; import org.freertr.ifc.ifcDot1ad; import org.freertr.ifc.ifcDot1ah; import org.freertr.ifc.ifcDot1q; import org.freertr.ifc.ifcQinq1; import org.freertr.ifc.ifcQinq2; import org.freertr.ifc.ifcQinq3; import org.freertr.ip.ipCor; import org.freertr.ip.ipCor4; import org.freertr.ip.ipCor6; import org.freertr.ip.ipIcmp4; import org.freertr.ip.ipIcmp6; import org.freertr.ip.ipIfc4; import org.freertr.ip.ipIfc6; import org.freertr.ip.ipMpls; import org.freertr.pack.packHolder; import org.freertr.prt.prtDccp; import org.freertr.prt.prtLudp; import org.freertr.prt.prtSctp; import org.freertr.prt.prtTcp; import org.freertr.prt.prtUdp; import org.freertr.user.userFormat; import org.freertr.util.bits; import org.freertr.util.counter; /** * quality of service worker * * @author matecsaba */ public class tabQos { /** * name of policy */ public String policyName; /** * last left value */ public long lastLeft; /** * list of classes */ protected final List classesD; private int classesP; private ipCor ip4cor; private ipCor ip6cor; /** * create new qos class */ protected tabQos() { classesD = new ArrayList(); ip4cor = new ipCor4(); ip6cor = new ipCor6(); } public String toString() { return policyName; } /** * get one class * * @param i index * @return class, null if not found */ public tabQosN getClass(int i) { if (i >= classesD.size()) { return null; } return classesD.get(i); } /** * get statistics * * @param dump dump entries * @return statistics */ public userFormat getStats(boolean dump) { String a = ""; if (dump) { a = "|ace"; } userFormat l = new userFormat("|", "seq|chld|queue|intrvl|byt/int|rxb|rxp|trnsmt" + a); for (int i = 0; i < classesD.size(); i++) { tabQosN cls = classesD.get(i); if (cls == null) { continue; } a = ""; if (dump) { try { a = "|" + cls.entry.aclMatch.get(0); } catch (Exception e) { } } l.add(cls.entry.sequence + "|" + cls.childs + "|" + cls.packets.size() + "/" + cls.getQueues() + "|" + cls.getInterval() + "|" + cls.getBytePerInt() + cls.entry.getCounters(2) + "|" + cls.cntr.getShStat() + a); } return l; } private static boolean convertSubPlcy(tabQos res, tabQosN prnt, tabListing pm) { int frst = res.classesD.size(); for (int i = 0; i < pm.size(); i++) { tabQosN no = new tabQosN(); no.entry = pm.get(i); if (no.entry == null) { continue; } no.parent = prnt; if (no.entry.action == tabListingEntry.actionType.actPriorty) { res.classesD.add(frst, no); frst++; } else { res.classesD.add(no); } if (no.entry.child == null) { continue; } if (prnt != null) { return true; } int old = res.classesD.size(); if (convertSubPlcy(res, no, no.entry.child)) { return true; } no.childs = res.classesD.size() - old; } return false; } /** * compile policy map * * @param pm policy map to convert * @return compiled qos worker, null on error */ public static tabQos convertPolicy(tabListing pm) { if (pm == null) { return null; } tabQos res = new tabQos(); res.policyName = pm.listName; if (convertSubPlcy(res, null, pm)) { return null; } if (res.classesD.size() < 1) { return null; } return res; } private boolean classifyLayer3(packHolder pck) { pck.ETHtype = pck.msbGetW(0); pck.getSkip(2); switch (pck.ETHtype) { case ipIfc4.type: return ip4cor.parseIPheader(pck, true); case ipIfc6.type: return ip6cor.parseIPheader(pck, true); case ipMpls.typeB: case ipMpls.typeM: case ipMpls.typeU: int i = pck.dataSize(); ipMpls.parseMPLSheader(pck); pck.setBytesLeft(i); return true; case ifcDot1q.type: pck.getSkip(-2); new ifcDot1q().parseHeader(pck); pck.getSkip(-ifcDot1q.size); pck.getSkip(2); return true; case ifcDot1ah.type: pck.getSkip(-2); new ifcDot1ah().parseHeader(pck); pck.getSkip(-ifcDot1ah.size); pck.getSkip(2); return true; case ifcDot1ad.type: pck.getSkip(-2); new ifcDot1ad().parseHeader(pck); pck.getSkip(-ifcDot1ad.size); pck.getSkip(2); return true; case ifcQinq1.type: pck.getSkip(-2); new ifcQinq1().parseHeader(pck); pck.getSkip(-ifcQinq1.size); pck.getSkip(2); return true; case ifcQinq2.type: pck.getSkip(-2); new ifcQinq2().parseHeader(pck); pck.getSkip(-ifcQinq2.size); pck.getSkip(2); return true; case ifcQinq3.type: pck.getSkip(-2); new ifcQinq3().parseHeader(pck); pck.getSkip(-ifcQinq3.size); pck.getSkip(2); return true; default: return true; } } /** * classify layer4 headers * * @param pck packet to parse */ public static void classifyLayer4(packHolder pck) { pck.UDPsrc = 0; pck.UDPtrg = 0; pck.UDPsiz = 0; switch (pck.IPprt) { case prtTcp.protoNum: prtTcp.parseTCPports(pck); break; case prtUdp.protoNum: prtUdp.parseUDPports(pck); break; case prtLudp.protoNum: prtLudp.parseLUDPports(pck); break; case prtDccp.protoNum: prtDccp.parseDCCPports(pck); break; case prtSctp.protoNum: prtSctp.parseSCTPports(pck); break; case ipIcmp4.protoNum: ipIcmp4.parseICMPports(pck); pck.UDPtrg = pck.UDPsrc; break; case ipIcmp6.protoNum: ipIcmp6.parseICMPports(pck); pck.UDPtrg = pck.UDPsrc; break; } } private void doClassifycation(packHolder pck) { pck.INTclass = -1; for (int i = 0; i < classesD.size(); i++) { tabQosN cls = classesD.get(i); if (cls == null) { continue; } if (!cls.entry.matches(pck)) { i += cls.childs; continue; } if (cls.childs > 0) { continue; } pck.INTclass = i; break; } } /** * classify packet * * @param pck packet to classify */ public void classifyPack(packHolder pck) { if (!classifyLayer3(pck)) { pck.getSkip(pck.IPsiz); classifyLayer4(pck); pck.getSkip(-pck.IPsiz); } pck.getSkip(-2); doClassifycation(pck); } /** * update one packet * * @param pck packet to update * @param cls class to use */ public void updatePack(packHolder pck, tabQosN cls) { pck.INTqosGrp = cls.entry.qosSet.update(pck.INTqosGrp); pck.SGTid = cls.entry.sgtSet.update(pck.SGTid); int o = cls.entry.ttlSet.update(pck.IPttl); int p = cls.entry.flowSet.update(pck.IPid); switch (pck.ETHtype) { case ipIfc4.type: int i = cls.entry.updateTos(pck.IPtos, cls); if ((pck.IPtos == i) && (pck.IPttl == o) && (pck.IPid == p)) { return; } pck.getSkip(2); ip4cor.updateIPheader(pck, null, null, -1, o, i, p, -1); pck.getSkip(-2); return; case ipIfc6.type: i = cls.entry.updateTos(pck.IPtos, cls); if ((pck.IPtos == i) && (pck.IPttl == o) && (pck.IPid == p)) { return; } pck.getSkip(2); ip6cor.updateIPheader(pck, null, null, -1, o, i, p, -1); pck.getSkip(-2); return; case ipMpls.typeB: case ipMpls.typeM: case ipMpls.typeU: i = pck.MPLSexp; pck.MPLSexp = cls.entry.expSet.update(i); if (i == pck.MPLSexp) { return; } pck.getSkip(2 + ipMpls.sizeL); ipMpls.createMPLSheader(pck); pck.getSkip(-2); return; case ifcDot1q.type: i = pck.ETHcos; pck.ETHcos = cls.entry.cosSet.update(i); if (i == pck.ETHcos) { return; } pck.getSkip(ifcDot1q.size); new ifcDot1q().createHeader(pck); return; case ifcDot1ah.type: i = pck.ETHcos; pck.ETHcos = cls.entry.cosSet.update(i); if (i == pck.ETHcos) { return; } pck.getSkip(ifcDot1ah.size); new ifcDot1ah().createHeader(pck); return; case ifcDot1ad.type: i = pck.ETHcos; pck.ETHcos = cls.entry.cosSet.update(i); if (i == pck.ETHcos) { return; } pck.getSkip(ifcDot1ad.size); new ifcDot1ad().createHeader(pck); return; case ifcQinq1.type: i = pck.ETHcos; pck.ETHcos = cls.entry.cosSet.update(i); if (i == pck.ETHcos) { return; } pck.getSkip(ifcQinq1.size); new ifcQinq1().createHeader(pck); return; case ifcQinq2.type: i = pck.ETHcos; pck.ETHcos = cls.entry.cosSet.update(i); if (i == pck.ETHcos) { return; } pck.getSkip(ifcQinq2.size); new ifcQinq2().createHeader(pck); return; case ifcQinq3.type: i = pck.ETHcos; pck.ETHcos = cls.entry.cosSet.update(i); if (i == pck.ETHcos) { return; } pck.getSkip(ifcQinq3.size); new ifcQinq3().createHeader(pck); return; default: return; } } /** * put one packet to queue * * @param pck packet to queue */ public void enqueuePack(packHolder pck) { if (pck.INTclass < 0) { return; } tabQosN cls = classesD.get(pck.INTclass); if (cls == null) { return; } synchronized (cls) { cls.enqueuePack(pck); } cls.cntr.rx(pck); } /** * check packet * * @param pck packet to process * @return false if allowed, true if droping */ public synchronized boolean checkPacket(packHolder pck) { pck.getSkip(pck.IPsiz); classifyLayer4(pck); pck.getSkip(-pck.IPsiz); doClassifycation(pck); if (pck.INTclass < 0) { return true; } tabQosN cls = classesD.get(pck.INTclass); if (cls == null) { return true; } cls.recUpdateTime(bits.getTime()); if (cls.checkPacket(pck)) { cls.cntr.drop(pck, counter.reasons.noBuffer); return true; } cls.updateBytes(pck.dataSize()); cls.updateDivert(pck); cls.cntr.tx(pck); return false; } /** * get one packet from queue * * @param curr current time * @return packet read, null if nothing */ public synchronized packHolder dequeuePack(long curr) { lastLeft = 0; int classesN = classesD.size(); for (int rnd = 0; rnd < classesN; rnd++) { tabQosN cls = classesD.get(classesP); if (cls == null) { classesP = (classesP + 1) % classesN; continue; } long left = cls.updateTime(curr); if (left < 1) { rnd = 0; } else if (cls.packets.size() > 0) { if (lastLeft < left) { lastLeft = left; } } packHolder pck; synchronized (cls) { pck = cls.dequeuePack(); } if (pck == null) { classesP = (classesP + 1) % classesN; continue; } updatePack(pck, cls); cls.updateBytes(pck.dataSize()); cls.updateDivert(pck); cls.cntr.tx(pck); return pck; } return null; } }