package org.freertr.clnt; import org.freertr.addr.addrEmpty; import org.freertr.addr.addrIP; import org.freertr.addr.addrType; import org.freertr.ifc.ifcDn; import org.freertr.ifc.ifcNull; import org.freertr.ifc.ifcPolka; import org.freertr.ifc.ifcUp; import org.freertr.ip.ipFwd; import org.freertr.ip.ipFwdIface; import org.freertr.ip.ipMpls; import org.freertr.pack.packHolder; import org.freertr.tab.tabGen; import org.freertr.tab.tabIndex; import org.freertr.tab.tabLabel; import org.freertr.tab.tabRouteEntry; import org.freertr.user.userFormat; 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.notifier; import org.freertr.util.state; /** * mpolka tunnel client * * @author matecsaba */ public class clntMpolka implements Runnable, ifcDn { /** * create instance */ public clntMpolka() { } /** * upper layer */ public ifcUp upper = new ifcNull(); /** * forwarder */ public ipFwd fwdCor; /** * target */ public addrIP target; /** * ttl value */ public int ttl = 255; /** * verify encoding */ public boolean verify = false; /** * counter */ public counter cntr = new counter(); private clntMpolkaTrg[] targets = new clntMpolkaTrg[1]; private clntMpolkaOut[] outputs = null; private boolean working = false; private notifier notif = new notifier(); public String toString() { return "mpolka"; } /** * get hw address * * @return hw address */ public addrType getHwAddr() { return new addrEmpty(); } /** * set filter * * @param promisc promiscous mode */ public void setFilter(boolean promisc) { } /** * get state * * @return state */ public state.states getState() { if (outputs == null) { return state.states.down; } else { return state.states.up; } } /** * close interface */ public void closeDn() { clearState(); } /** * flap interface */ public void flapped() { clearState(); } /** * set upper layer * * @param server upper layer */ public void setUpper(ifcUp server) { upper = server; upper.setParent(this); } /** * get counter * * @return counter */ public counter getCounter() { return cntr; } /** * get mtu size * * @return mtu size */ public int getMTUsize() { return 1500; } /** * get bandwidth * * @return bandwidth */ public long getBandwidth() { return 8000000; } /** * send packet * * @param pck packet */ public void sendPack(packHolder pck) { clntMpolkaOut[] outs = outputs; if (outs == null) { return; } pck.IPprt = pck.msbGetW(0); pck.getSkip(2); cntr.tx(pck); if (ttl >= 0) { pck.NSHttl = ttl; } else { pck.NSHttl = pck.IPttl; } pck.NSHmdt = 1; for (int i = 0; i < outs.length; i++) { pck.NSHmdv = outs[i].rou; outs[i].ifc.lower.sendPolka(pck.copyBytes(true, true), outs[i].hop); } } /** * get resulting route * * @param src source to use * @return route, null if no suitable */ public tabRouteEntry getResultRoute(tabRouteEntry src) { if (outputs == null) { return null; } if (outputs.length < 1) { return null; } src.best.nextHop = outputs[0].hop.copyBytes(); src.best.iface = outputs[0].ifc; src.best.labelRem = tabLabel.int2labels(ipMpls.labelImp); src.best.attribVal = outputs[0].rou; return src; } /** * set targets * * @param s targets */ public void setTargets(String s) { if (s == null) { s = ""; } tabGen trgs = new tabGen(); cmds c = new cmds("adrs", s); for (;;) { s = c.word(); if (s.length() < 1) { break; } clntMpolkaTrg ntry = new clntMpolkaTrg(); ntry.node = new addrIP(); ntry.node.fromString(s); for (;;) { s = c.word(); if (s.length() < 1) { break; } if (s.equals(",")) { break; } addrIP a = new addrIP(); if (s.equals("-")) { if (a.fromString(c.word())) { continue; } ntry.through = a; continue; } if (a.fromString(s)) { continue; } ntry.peers.add(a); } trgs.add(ntry); } setTargets(trgs); } /** * set targets * * @param trg targets */ public void setTargets(tabGen trg) { clearState(); clntMpolkaTrg[] ts = new clntMpolkaTrg[trg.size()]; for (int i = 0; i < ts.length; i++) { ts[i] = trg.get(i); } outputs = null; targets = ts; notif.wakeup(); } /** * get targets * * @return targets */ public String getTargets() { if (targets.length < 1) { return null; } String s = ""; for (int i = 0; i < targets.length; i++) { s += " " + targets[i]; } return s.trim(); } /** * start connection */ public void workStart() { if (debugger.clntMpolkaTraf) { logger.debug("starting work"); } working = true; new Thread(this).start(); } /** * stop connection */ public void workStop() { if (debugger.clntMpolkaTraf) { logger.debug("stopping work"); } working = false; clearState(); } public void run() { for (;;) { if (!working) { break; } try { workDoer(); } catch (Exception e) { logger.traceback(e); } notif.sleep(5000); } } private void clearState() { outputs = null; upper.setState(state.states.down); } private void workDoer() { tabGen outs = new tabGen(); for (int o = 0; o < targets.length; o++) { addrIP adr = targets[o].node; tabRouteEntry rou = fwdCor.actualU.route(adr); if (rou == null) { if (debugger.clntMpolkaTraf) { logger.debug("no route for " + adr); } continue; } if (rou.best.segrouIdx < 1) { if (debugger.clntMpolkaTraf) { logger.debug("no index for " + rou); } continue; } tabIndex idx = fwdCor.actualIU.find(new tabIndex(rou.best.segrouIdx, null)); if (idx == null) { if (debugger.clntMpolkaTraf) { logger.debug("no srindex for " + rou); } continue; } if (idx.neighs == null) { if (debugger.clntMpolkaTraf) { logger.debug("no srneigh for " + rou); } continue; } if (targets[o].through != null) { adr = targets[o].through; rou = fwdCor.actualU.route(adr); if (rou == null) { if (debugger.clntMpolkaTraf) { logger.debug("no route for " + adr); } continue; } } clntMpolkaOut ntry = new clntMpolkaOut(rou.best.nextHop.copyBytes()); ntry.ifc = (ipFwdIface) rou.best.iface; ntry.plk = ntry.ifc.lower.getPolka(); if (ntry.plk == null) { if (debugger.clntMpolkaTraf) { logger.debug("mpolka not enabled for " + ntry.ifc); } continue; } int neis = 0; for (int i = 0; i < targets[o].peers.size(); i++) { adr = targets[o].peers.get(i); if (adr.compareTo(targets[o].node) == 0) { neis |= 1; continue; } rou = fwdCor.actualU.route(adr); if (rou == null) { if (debugger.clntMpolkaTraf) { logger.debug("no route for " + adr); } continue; } if (rou.best.segrouIdx < 1) { if (debugger.clntMpolkaTraf) { logger.debug("no index for " + rou); } continue; } int p = idx.neighs.index(new tabIndex(rou.best.segrouIdx, null)); if (p < 0) { if (debugger.clntMpolkaTraf) { logger.debug("no neighbor for " + rou); } continue; } p++; neis |= 1 << p; } if (neis == 0) { if (debugger.clntMpolkaTraf) { logger.debug("no outputs for " + targets[o]); } continue; } idx = new tabIndex(idx.index, null); idx.bitmap = neis; ntry.nei.add(idx); ntry.end = (neis & 1) != 0; ntry = outs.add(ntry); if (ntry == null) { continue; } ntry.nei.add(idx); ntry.end |= (neis & 1) != 0; } for (int i = 0; i < outs.size(); i++) { clntMpolkaOut ntry = outs.get(i); if (ntry.end) { continue; } tabRouteEntry rou = fwdCor.actualU.route(target); if (rou == null) { if (debugger.clntMpolkaTraf) { logger.debug("no route for " + target); } continue; } if (rou.best.segrouIdx < 1) { if (debugger.clntMpolkaTraf) { logger.debug("no index for " + rou); } continue; } tabIndex idx = fwdCor.actualIU.find(new tabIndex(rou.best.segrouIdx, null)); if (idx == null) { if (debugger.clntMpolkaTraf) { logger.debug("no srindex for " + rou); } continue; } idx = new tabIndex(idx.index, null); idx.bitmap = 1; ntry.nei.add(idx); ntry.end = true; ntry = outs.add(ntry); } if (outs.size() < 1) { if (debugger.clntMpolkaTraf) { logger.debug("no outputs"); } clearState(); return; } clntMpolkaOut[] out = new clntMpolkaOut[outs.size()]; for (int i = 0; i < out.length; i++) { out[i] = outs.get(i); try { out[i].rou = ifcPolka.encodeRouteIdMul(out[i].plk.coeffs, out[i].nei); } catch (Exception e) { if (debugger.clntMpolkaTraf) { logger.debug("error encoding routeid for " + out[i].hop); } clearState(); return; } } outputs = out; upper.setState(state.states.up); if (!verify) { return; } for (int i = 0; i < out.length; i++) { try { doOneVerify(out[i].nei, ifcPolka.decodeRouteIdPoly(out[i].plk.coeffs, out[i].rou), "poly"); doOneVerify(out[i].nei, ifcPolka.decodeRouteIdCrc(out[i].plk.coeffs, out[i].rou), "crc"); } catch (Exception e) { if (debugger.clntMpolkaTraf) { logger.debug("error decoding routeid for " + out[i].hop); } return; } } } private void doOneVerify(tabGen> ids, int[] dec, String mod) { boolean good = true; for (int i = 0; i < ids.size(); i++) { tabIndex c = ids.get(i); if (dec[c.index] != c.bitmap) { good = false; } } if (good) { return; } if (debugger.clntMpolkaTraf) { logger.debug("bad routeid with " + mod); } } /** * get routeid show * * @return show */ public userFormat getShRoute() { if (outputs == null) { return null; } userFormat l = new userFormat("|", "iface|hop|routeid"); for (int i = 0; i < outputs.length; i++) { l.add(outputs[i].ifc + "|" + outputs[i].hop + "|" + bits.byteDump(outputs[i].rou, 0, -1)); } return l; } /** * get decoded show * * @return show */ public userFormat getShDecode() { if (outputs == null) { return null; } userFormat l = new userFormat("|", "index|coeff|poly|crc|equal"); for (int o = 0; o < outputs.length; o++) { ifcPolka plk = outputs[o].ifc.lower.getPolka(); int[] pol = ifcPolka.decodeRouteIdPoly(plk.coeffs, outputs[o].rou); int[] crc = ifcPolka.decodeRouteIdCrc(plk.coeffs, outputs[o].rou); for (int i = 0; i < plk.coeffs.length; i++) { l.add(i + "|" + bits.toHexD(plk.coeffs[i].intCoeff()) + "|" + pol[i] + "|" + crc[i] + "|" + (pol[i] == crc[i])); } } return l; } } class clntMpolkaTrg implements Comparable { public addrIP node; public addrIP through; public tabGen peers = new tabGen(); public String toString() { String a = "" + node; if (through != null) { a += " - " + through; } for (int i = 0; i < peers.size(); i++) { a += " " + peers.get(i); } return a + " ,"; } public int compareTo(clntMpolkaTrg o) { int i = node.compareTo(o.node); if (i != 0) { return i; } if ((through == null) && (o.through == null)) { return 0; } if (through == null) { return -1; } if (o.through == null) { return +1; } return through.compareTo(o.through); } } class clntMpolkaOut implements Comparable { public final addrIP hop; public ipFwdIface ifc; public ifcPolka plk; public tabGen> nei; public boolean end; public byte[] rou; public clntMpolkaOut(addrIP h) { hop = h; nei = new tabGen>(); } public int compareTo(clntMpolkaOut o) { return hop.compareTo(o.hop); } }