package org.freertr.tab; import java.util.ArrayList; import java.util.List; import org.freertr.ip.ipCor4; import org.freertr.pack.packHolder; import org.freertr.util.bits; import org.freertr.util.counter; /** * qos entry * * @author matecsaba */ public class tabQosN { /** * traffic class entry */ public tabPlcmapN entry; /** * parent of this node (common bandwidth pool) */ protected tabQosN parent; /** * skip them if not matches */ protected int childs; /** * bytes used in this interval */ protected long bytes; /** * beginning of interval */ protected long time; /** * list of packets */ protected final List packets; /** * packet counter */ protected counter cntr = new counter(); /** * create new qos class */ public tabQosN() { packets = new ArrayList(); } /** * update byte counts (in parents also) * * @param add bytes to add */ protected void updateBytes(int add) { if (entry.action == tabListingEntry.actionType.actPps) { bytes++; } else { bytes += add; } if (parent == null) { return; } parent.updateBytes(add); } /** * update divert * * @param pck packet to update */ protected void updateDivert(packHolder pck) { if ((entry.vrfSet4 != null) && (entry.vrfSet6 != null)) { if (pck.IPver == ipCor4.protocolVersion) { pck.IPdivert = entry.vrfSet4; } else { pck.IPdivert = entry.vrfSet6; } } if (parent == null) { return; } parent.updateDivert(pck); } /** * get interval in ms * * @return interval */ public int getInterval() { int i = entry.interval; if (i < 1) { return 100; } else { return i; } } /** * get bytes/interval * * @return bytes/int */ public long getBytePerInt() { int i = getInterval(); if (i > 1000) { return entry.accessRate * (i / 1000); } return entry.accessRate / (1000 / i); } /** * get queue size * * @return queue size */ protected int getQueues() { int i = entry.queues; if (i > 0) { return i; } else { return 128; } } /** * check if there is room for bytes * * @param add bytes to check * @return false if available, true if full */ protected boolean checkMyBytes(int add) { if (bytes < 1) { return false; } return (bytes + add) > getBytePerInt(); } /** * check if there is room for bytes * * @param add bytes to check * @return false if available, true if full */ protected boolean checkPrntBytes(int add) { if (parent == null) { return false; } if (parent.checkMyBytes(add)) { return true; } return parent.checkPrntBytes(add); } /** * update time * * @param curr current time * @return ms left from interval, 0 means just reset */ protected long updateTime(long curr) { long left = getInterval() - (curr - time); if (left > 0) { return left; } time = curr; bytes -= (entry.accessRate - entry.exceedRate); if (bytes < 0) { bytes = 0; } return 0; } /** * recursively update time * * @param curr current time */ protected void recUpdateTime(long curr) { updateTime(curr); if (parent == null) { return; } parent.recUpdateTime(curr); } /** * enqueue one packet * * @param pck packet to enqueue */ public void enqueuePack(packHolder pck) { entry.cntr.rx(pck); if (packets.size() > getQueues()) { if (!entry.randomDetect) { return; } packets.remove(bits.random(0, packets.size())); } packets.add(pck.copyBytes(true, true)); } /** * check packet * * @param pck packet * @return false if allowed, true if droping */ public boolean checkPacket(packHolder pck) { entry.cntr.rx(pck); int len = pck.dataSize(); switch (entry.action) { case actPermit: return false; case actPolice: case actPriorty: case actShaper: case actBndwdth: if (checkMyBytes(len)) { return true; } if (checkPrntBytes(len)) { return true; } return false; case actPps: if (checkMyBytes(1)) { return true; } if (checkPrntBytes(1)) { return true; } return false; case actDeny: default: return true; } } /** * dequeue one packet * * @return packet got, null if nothing */ public packHolder dequeuePack() { if (packets.size() < 1) { return null; } switch (entry.action) { case actPermit: return packets.remove(0); case actPolice: case actPriorty: packHolder pck = packets.remove(0); if (checkMyBytes(pck.dataSize())) { packets.clear(); return null; } if (checkPrntBytes(pck.dataSize())) { return null; } return pck; case actPps: pck = packets.remove(0); if (checkMyBytes(1)) { packets.clear(); return null; } if (checkPrntBytes(1)) { return null; } return pck; case actShaper: pck = packets.get(0); if (checkMyBytes(pck.dataSize())) { return null; } if (checkPrntBytes(pck.dataSize())) { return null; } packets.remove(0); return pck; case actBndwdth: pck = packets.get(0); if (checkMyBytes(pck.dataSize())) { bytes = 0; return null; } if (checkPrntBytes(pck.dataSize())) { return null; } packets.remove(0); return pck; case actDeny: default: packets.clear(); return null; } } }