package org.freertr.rtr; import java.util.ArrayList; import java.util.List; import org.freertr.addr.addrIP; import org.freertr.addr.addrIPv4; import org.freertr.addr.addrIPv6; import org.freertr.enc.encTlv; import org.freertr.pack.packHolder; import org.freertr.tab.tabIpv6comm; import org.freertr.tab.tabLargeComm; import org.freertr.tab.tabRouteBlob; import org.freertr.tab.tabRouteEntry; import org.freertr.tab.tabRouteUtil; import org.freertr.util.bits; import org.freertr.util.logger; /** * one bgp4 attribute * * @author matecsaba */ public interface rtrBgpAttr { /** * origin type attribute */ public rtrBgpAttr attrOriginType = new rtrBgpAttrOriginType(); /** * as path attribute */ public rtrBgpAttr attrAsPath = new rtrBgpAttrAsPath(); /** * metric attribute */ public rtrBgpAttr attrMetric = new rtrBgpAttrMetric(); /** * next hop attribute */ public rtrBgpAttr attrNextHop = new rtrBgpAttrNextHop(); /** * local preference attribute */ public rtrBgpAttr attrLocPref = new rtrBgpAttrLocPref(); /** * atomic aggregator attribute */ public rtrBgpAttr attrAtomicAggr = new rtrBgpAttrAtomicAggr(); /** * entropy label attribute */ public rtrBgpAttr attrEntropyLab = new rtrBgpAttrEntropyLab(); /** * aggregator attribute */ public rtrBgpAttr attrAggregator = new rtrBgpAttrAggregator(); /** * destination preference attribute */ public rtrBgpAttr attrDestPref = new rtrBgpAttrDestPref(); /** * connector attribute */ public rtrBgpAttr attrConnector = new rtrBgpAttrConnector(); /** * path limit attribute */ public rtrBgpAttr attrPathLimit = new rtrBgpAttrPathLimit(); /** * pe distinguisher attribute */ public rtrBgpAttr attrPeDistLab = new rtrBgpAttrPeDistLab(); /** * standard community */ public rtrBgpAttr attrStdComm = new rtrBgpAttrStdComm(); /** * extended community */ public rtrBgpAttr attrExtComm = new rtrBgpAttrExtComm(); /** * large community */ public rtrBgpAttr attrLrgComm = new rtrBgpAttrLrgComm(); /** * ipv6 community */ public rtrBgpAttr attrIpv6comm = new rtrBgpAttrIp6comm(); /** * originator attribute */ public rtrBgpAttr attrOriginator = new rtrBgpAttrOriginator(); /** * traffic engineering attribute */ public rtrBgpAttr attrTraffEng = new rtrBgpAttrTraffEng(); /** * accumulated igp attribute */ public rtrBgpAttr attrAccIgp = new rtrBgpAttrAccIgp(); /** * pmsi tunnel attribute */ public rtrBgpAttr attrPmsiTun = new rtrBgpAttrPmsiTun(); /** * link state attribute */ public rtrBgpAttr attrLinkState = new rtrBgpAttrLinkState(); /** * tunnel encap attribute */ public rtrBgpAttr attrTunEnc = new rtrBgpAttrTunEnc(); /** * attribute set attribute */ public rtrBgpAttr attrAttribSet = new rtrBgpAttrAttribSet(); /** * nsh chain attribute */ public rtrBgpAttr attrNshChain = new rtrBgpAttrNshChain(); /** * domain path attribute */ public rtrBgpAttr attrDomainPath = new rtrBgpAttrDomainPath(); /** * safi specific attribute */ public rtrBgpAttr attrSafiSpec = new rtrBgpAttrSafiSpec(); /** * bfd discriminator attribute */ public rtrBgpAttr attrBfdDisc = new rtrBgpAttrBfdDisc(); /** * hop capabilities attribute */ public rtrBgpAttr attrHopCapa = new rtrBgpAttrHopCapa(); /** * prefix sid attribute */ public rtrBgpAttr attrPrefSid = new rtrBgpAttrPrefSid(); /** * bier attribute */ public rtrBgpAttr attrBier = new rtrBgpAttrBier(); /** * cluster list attribute */ public rtrBgpAttr attrClustList = new rtrBgpAttrClustList(); /** * only to customer attribute */ public rtrBgpAttr attrOnlyCust = new rtrBgpAttrOnlyCust(); /** * unknown attribute */ public rtrBgpAttr attrUnknown = new rtrBgpAttrUnknown(); /** * reachable attribute */ public rtrBgpAttr attrReachable = new rtrBgpAttrReachable(); /** * unreachable attribute */ public rtrBgpAttr attrUnReach = new rtrBgpAttrUnReach(); /** * layer2 behavior */ public final static int behavDx2 = 0x15; /** * ipv4 behavior */ public final static int behavDt4 = 0x13; /** * ipv6 behavior */ public final static int behavDt6 = 0x12; /** * read attribute * * @param spkr where to signal * @param ntry table entry * @param pck packet to parse */ public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck); /** * write attribute * * @param spkr where to signal * @param trg target packet * @param hlp helper packet * @param ntry table entry */ public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry); /** * interpret attribute * * @param spkr where to signal * @param ntry table entry * @param pck packet to parse */ public static void interpretAttribute(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { rtrBgpUtil.updtStatsArr(false, spkr.parent.attrStats, pck.ETHtype, pck); rtrBgpUtil.updtStatsArr(false, spkr.neigh.attrStats, pck.ETHtype, pck); if (spkr.neigh.attribFilter != null) { if (spkr.neigh.attribFilter.matches(pck.ETHtype)) { logger.info("filtered attribute " + pck.ETHtype + " from " + spkr.neigh.peerAddr + " (" + pck.dump() + ")"); return; } } rtrBgp.bgpAttrsRx[pck.ETHtype & 0xff].readAttrib(spkr, ntry, pck); } /** * parse attribute * * @param src source where from read * @param attr attribute read to * @return false on success, true on error */ public static boolean parseAttrib(packHolder src, packHolder attr) { int flg = src.getByte(0); // flags int typ = src.getByte(1); // type int len = 0; if ((flg & rtrBgpUtil.flagLength) == 0) { len = src.getByte(2); src.getSkip(3); // length } else { len = src.msbGetW(2); src.getSkip(4); // length } if (len > src.dataSize()) { return true; } byte[] buf = new byte[len]; src.getCopy(buf, 0, 0, len); src.getSkip(len); attr.clear(); attr.ETHcos = flg; attr.ETHtype = typ; attr.putCopy(buf, 0, 0, buf.length); attr.putSkip(buf.length); attr.merge2beg(); return false; } /** * place one attribute * * @param spkr where to signal * @param flg flags * @param typ type * @param trg taget * @param attr attribute */ public static void placeAttrib(rtrBgpSpeak spkr, int flg, int typ, packHolder trg, packHolder attr) { attr.merge2beg(); rtrBgpUtil.updtStatsArr(true, spkr.parent.attrStats, typ, attr); rtrBgpUtil.updtStatsArr(true, spkr.neigh.attrStats, typ, attr); byte[] buf = attr.getCopy(); if (buf.length > 0xff) { flg |= rtrBgpUtil.flagLength; } trg.putByte(0, flg); // flags trg.putByte(1, typ); // type if ((flg & rtrBgpUtil.flagLength) == 0) { trg.putByte(2, buf.length); // length trg.putSkip(3); } else { trg.msbPutW(2, buf.length); // length trg.putSkip(4); } trg.putCopy(buf, 0, 0, buf.length); trg.putSkip(buf.length); } /** * place reachable attribute * * @param spkr where to signal * @param idx sub address family * @param addpath additional path * @param trg target packet * @param hlp helper packet * @param lst list of table entries */ public static void placeReachable(rtrBgpSpeak spkr, int idx, boolean addpath, packHolder trg, packHolder hlp, List> lst) { int safi = spkr.parent.idx2safi[idx]; rtrBgpAfi rdr = spkr.parent.safi2rdr[idx]; boolean oneLab = !spkr.peerMltLab[idx]; int afi = safi & rtrBgpUtil.afiMask; int sfi = safi & rtrBgpUtil.sfiMask; addrIP nextHop = lst.get(0).best.nextHop; boolean v6nh = afi == rtrBgpUtil.afiIpv6; if (!v6nh) { v6nh = !nextHop.isIPv4(); } int i = v6nh ? addrIPv6.size : addrIPv4.size; if ((sfi == rtrBgpUtil.sfiMplsVpnU) || (sfi == rtrBgpUtil.sfiMplsVpnM) || (sfi == rtrBgpUtil.sfiClsTrnPl)) { i += 8; } hlp.clear(); hlp.msbPutD(0, rtrBgpUtil.safi2triplet(safi)); hlp.putByte(3, i); hlp.putSkip(4); if ((sfi == rtrBgpUtil.sfiMplsVpnU) || (sfi == rtrBgpUtil.sfiMplsVpnM) || (sfi == rtrBgpUtil.sfiClsTrnPl)) { hlp.msbPutQ(0, 0); // rd hlp.putSkip(8); } if (v6nh) { rtrBgpAfi.writeAddress(rtrBgpUtil.afiIpv6, hlp, nextHop); } else { rtrBgpAfi.writeAddress(rtrBgpUtil.afiIpv4, hlp, nextHop); } hlp.putByte(0, 0); hlp.putSkip(1); for (i = 0; i < lst.size(); i++) { tabRouteEntry ntry = lst.get(i); if (addpath) { hlp.msbPutD(0, ntry.best.ident); hlp.putSkip(4); } rdr.writePrefix(oneLab, hlp, ntry); } placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrReachable, trg, hlp); } /** * place unreachable attribute * * @param spkr where to signal * @param idx sub address family * @param addpath additional path * @param trg target packet * @param hlp helper packet * @param lst list of table entries */ public static void placeUnreach(rtrBgpSpeak spkr, int idx, boolean addpath, packHolder trg, packHolder hlp, List> lst) { int safi = spkr.parent.idx2safi[idx]; rtrBgpAfi rdr = spkr.parent.safi2rdr[idx]; hlp.clear(); hlp.msbPutD(0, rtrBgpUtil.safi2triplet(safi)); hlp.putSkip(3); for (int i = 0; i < lst.size(); i++) { tabRouteEntry ntry = lst.get(i); if (addpath) { hlp.msbPutD(0, ntry.best.ident); hlp.putSkip(4); } rdr.writePrefix(true, hlp, ntry); } placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrUnReach, trg, hlp); } } class rtrBgpAttrOriginType implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.originType = pck.getByte(0); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { hlp.clear(); hlp.putByte(0, ntry.best.originType % 3); hlp.putSkip(1); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagTransitive, rtrBgpUtil.attrOriginType, trg, hlp); } } class rtrBgpAttrAsPath implements rtrBgpAttr { private static void rdLst(boolean longAs, List lst, packHolder pck) { int max = pck.getByte(0); pck.getSkip(1); if (longAs) { for (int pos = 0; pos < max; pos++) { int i = pck.msbGetD(0); pck.getSkip(4); lst.add(i); } return; } for (int pos = 0; pos < max; pos++) { int i = pck.msbGetW(0); pck.getSkip(2); lst.add(i); } } private static void wrLst(boolean longAs, packHolder pck, int typ, List lst) { if (lst == null) { return; } int pos = 0; int max = lst.size(); for (; pos < max;) { int end = pos + 255; if (end > max) { end = max; } pck.putByte(0, typ); pck.putByte(1, end - pos); pck.putSkip(2); if (longAs) { for (; pos < end; pos++) { int i = lst.get(pos); pck.msbPutD(0, i); pck.putSkip(4); } continue; } for (; pos < end; pos++) { int i = lst.get(pos); i = tabRouteUtil.asNum16bit(i); pck.msbPutW(0, i); pck.putSkip(2); } } } public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.pathSeq = new ArrayList(); ntry.best.pathSet = new ArrayList(); ntry.best.confSeq = new ArrayList(); ntry.best.confSet = new ArrayList(); for (; pck.dataSize() > 0;) { int i = pck.getByte(0); pck.getSkip(1); switch (i) { case 1: // as set rdLst(spkr.peer32bitAS, ntry.best.pathSet, pck); break; case 2: // as seq rdLst(spkr.peer32bitAS, ntry.best.pathSeq, pck); break; case 3: // confed seq rdLst(spkr.peer32bitAS, ntry.best.confSeq, pck); break; case 4: // confed set rdLst(spkr.peer32bitAS, ntry.best.pathSet, pck); break; } } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { hlp.clear(); wrLst(spkr.peer32bitAS, hlp, 3, ntry.best.confSeq); // confed seq wrLst(spkr.peer32bitAS, hlp, 4, ntry.best.confSet); // confed set wrLst(spkr.peer32bitAS, hlp, 2, ntry.best.pathSeq); // as seq wrLst(spkr.peer32bitAS, hlp, 1, ntry.best.pathSet); // as set rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagTransitive, rtrBgpUtil.attrAsPath, trg, hlp); } } class rtrBgpAttrMetric implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.metric = pck.msbGetD(0); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.metric < 1) { return; } hlp.clear(); hlp.msbPutD(0, ntry.best.metric); hlp.putSkip(4); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrMetric, trg, hlp); } } class rtrBgpAttrNextHop implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { addrIPv4 adr = new addrIPv4(); pck.getAddr(adr, 0); ntry.best.nextHop = new addrIP(); ntry.best.nextHop.fromIPv4addr(adr); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { hlp.clear(); hlp.putAddr(0, ntry.best.nextHop.toIPv4()); hlp.putSkip(addrIPv4.size); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagTransitive, rtrBgpUtil.attrNextHop, trg, hlp); } } class rtrBgpAttrLocPref implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.locPref = pck.msbGetD(0); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.locPref < 1) { return; } hlp.clear(); hlp.msbPutD(0, ntry.best.locPref); hlp.putSkip(4); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagTransitive, rtrBgpUtil.attrLocPref, trg, hlp); } } class rtrBgpAttrAtomicAggr implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.atomicAggr = true; } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (!ntry.best.atomicAggr) { return; } hlp.clear(); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagTransitive, rtrBgpUtil.attrAtomicAggr, trg, hlp); } } class rtrBgpAttrEntropyLab implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.entropyLabel = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.entropyLabel == null) { return; } if (ntry.best.entropyLabel.length < 1) { return; } hlp.clear(); hlp.putCopy(ntry.best.entropyLabel, 0, 0, ntry.best.entropyLabel.length); hlp.putSkip(ntry.best.entropyLabel.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagTransitive, rtrBgpUtil.attrEntropyLab, trg, hlp); } } class rtrBgpAttrAggregator implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { if (spkr.peer32bitAS) { ntry.best.aggrAs = pck.msbGetD(0); pck.getSkip(4); } else { ntry.best.aggrAs = pck.msbGetW(0); pck.getSkip(2); } addrIPv4 adr = new addrIPv4(); pck.getAddr(adr, 0); ntry.best.aggrRtr = new addrIP(); ntry.best.aggrRtr.fromIPv4addr(adr); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.aggrRtr == null) { return; } hlp.clear(); if (spkr.peer32bitAS) { hlp.msbPutD(0, ntry.best.aggrAs); hlp.putSkip(4); } else { hlp.msbPutW(0, tabRouteUtil.asNum16bit(ntry.best.aggrAs)); hlp.putSkip(2); } hlp.putAddr(0, ntry.best.aggrRtr.toIPv4()); hlp.putSkip(addrIPv4.size); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrAggregator, trg, hlp); } } class rtrBgpAttrDestPref implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { if (spkr.peer32bitAS) { ntry.best.destPrefAsn = pck.msbGetD(0); pck.getSkip(4); } else { ntry.best.destPrefAsn = pck.msbGetW(0); pck.getSkip(2); } ntry.best.destPrefVal = pck.msbGetD(0); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.destPrefVal < 1) { return; } hlp.clear(); if (spkr.peer32bitAS) { hlp.msbPutD(0, ntry.best.destPrefAsn); hlp.putSkip(4); } else { hlp.msbPutW(0, tabRouteUtil.asNum16bit(ntry.best.destPrefAsn)); hlp.putSkip(2); } hlp.msbPutD(0, ntry.best.destPrefVal); hlp.putSkip(4); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrDestPref, trg, hlp); } } class rtrBgpAttrConnector implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { addrIPv4 adr = new addrIPv4(); pck.getAddr(adr, 4); ntry.best.connRtr = new addrIP(); ntry.best.connRtr.fromIPv4addr(adr); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.connRtr == null) { return; } hlp.clear(); hlp.msbPutD(0, 1); hlp.putAddr(4, ntry.best.connRtr.toIPv4()); hlp.putSkip(4 + addrIPv4.size); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrConnector, trg, hlp); } } class rtrBgpAttrPathLimit implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.pathLimVal = pck.getByte(0); ntry.best.pathLimAsn = pck.msbGetD(1); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.pathLimVal < 1) { return; } hlp.clear(); hlp.putByte(0, ntry.best.pathLimVal); hlp.msbPutD(1, ntry.best.pathLimAsn); hlp.putSkip(5); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrPathLimit, trg, hlp); } } class rtrBgpAttrPeDistLab implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { int i; ntry.best.pediRtr = new addrIP(); if (pck.dataSize() > 8) { addrIPv6 adr = new addrIPv6(); pck.getAddr(adr, 0); ntry.best.pediRtr.fromIPv6addr(adr); pck.getSkip(addrIPv6.size); } else { addrIPv4 adr = new addrIPv4(); pck.getAddr(adr, 0); ntry.best.pediRtr.fromIPv4addr(adr); pck.getSkip(addrIPv4.size); } ntry.best.pediLab = pck.msbGetD(0) >>> 12; } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.pediRtr == null) { return; } hlp.clear(); if (ntry.best.pediRtr.isIPv4()) { hlp.putAddr(0, ntry.best.pediRtr.toIPv4()); hlp.putSkip(addrIPv4.size); } else { hlp.putAddr(0, ntry.best.pediRtr.toIPv6()); hlp.putSkip(addrIPv6.size); } hlp.msbPutD(0, ntry.best.pediLab << 12); hlp.putSkip(3); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrPeDistLab, trg, hlp); } } class rtrBgpAttrStdComm implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.stdComm = new ArrayList(); for (; pck.dataSize() >= 4;) { ntry.best.stdComm.add(pck.msbGetD(0)); pck.getSkip(4); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.stdComm == null) { return; } if (ntry.best.stdComm.size() < 1) { return; } hlp.clear(); for (int i = 0; i < ntry.best.stdComm.size(); i++) { hlp.msbPutD(0, ntry.best.stdComm.get(i)); hlp.putSkip(4); } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrStdComm, trg, hlp); } } class rtrBgpAttrExtComm implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.extComm = new ArrayList(); for (; pck.dataSize() >= 8;) { ntry.best.extComm.add(pck.msbGetQ(0)); pck.getSkip(8); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.extComm == null) { return; } if (ntry.best.extComm.size() < 1) { return; } hlp.clear(); for (int i = 0; i < ntry.best.extComm.size(); i++) { hlp.msbPutQ(0, ntry.best.extComm.get(i)); hlp.putSkip(8); } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrExtComm, trg, hlp); } } class rtrBgpAttrLrgComm implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.lrgComm = new ArrayList(); for (; pck.dataSize() >= 12;) { tabLargeComm d = new tabLargeComm(); d.as = pck.msbGetD(0); d.d1 = pck.msbGetD(4); d.d2 = pck.msbGetD(8); ntry.best.lrgComm.add(d); pck.getSkip(12); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.lrgComm == null) { return; } if (ntry.best.lrgComm.size() < 1) { return; } hlp.clear(); for (int i = 0; i < ntry.best.lrgComm.size(); i++) { tabLargeComm d = ntry.best.lrgComm.get(i); hlp.msbPutD(0, d.as); hlp.msbPutD(4, d.d1); hlp.msbPutD(8, d.d2); hlp.putSkip(12); } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrLrgComm, trg, hlp); } } class rtrBgpAttrIp6comm implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.ip6comm = new ArrayList(); for (; pck.dataSize() >= 20;) { tabIpv6comm d = new tabIpv6comm(); d.typ = pck.msbGetW(0); pck.getAddr(d.adr, 2); d.loc = pck.msbGetD(18); ntry.best.ip6comm.add(d); pck.getSkip(20); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.ip6comm == null) { return; } if (ntry.best.ip6comm.size() < 1) { return; } hlp.clear(); for (int i = 0; i < ntry.best.ip6comm.size(); i++) { tabIpv6comm d = ntry.best.ip6comm.get(i); hlp.msbPutW(0, d.typ); hlp.putAddr(2, d.adr); hlp.msbPutW(18, d.loc); hlp.putSkip(20); } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrIpv6comm, trg, hlp); } } class rtrBgpAttrOriginator implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { addrIPv4 adr = new addrIPv4(); pck.getAddr(adr, 0); ntry.best.originator = new addrIP(); ntry.best.originator.fromIPv4addr(adr); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.originator == null) { return; } hlp.clear(); hlp.putAddr(0, ntry.best.originator.toIPv4()); hlp.putSkip(addrIPv4.size); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrOriginator, trg, hlp); } } class rtrBgpAttrTraffEng implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.bandwidth = ((Float) Float.intBitsToFloat(pck.msbGetD(4))).intValue() * 8; } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.bandwidth < 1) { return; } hlp.clear(); hlp.putByte(0, 1); // psc1 hlp.putByte(1, 1); // packet hlp.msbPutW(2, 0); // reserved int i = Float.floatToIntBits(ntry.best.bandwidth / 8); hlp.msbPutD(4, i); // pri0 hlp.msbPutD(8, i); // pri1 hlp.msbPutD(12, i); // pri2 hlp.msbPutD(16, i); // pri3 hlp.msbPutD(20, i); // pri4 hlp.msbPutD(24, i); // pri5 hlp.msbPutD(28, i); // pri6 hlp.msbPutD(32, i); // pri7 hlp.msbPutD(36, Float.floatToIntBits(1)); // minimum hlp.msbPutW(40, 1500); // mtu hlp.putSkip(42); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrTraffEng, trg, hlp); } } class rtrBgpAttrAccIgp implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { if (pck.getByte(0) != 1) { return; } if (pck.msbGetW(1) < 11) { return; } ntry.best.accIgp = (int) pck.msbGetQ(3); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.accIgp < 1) { return; } hlp.clear(); hlp.putByte(0, 1); // type hlp.msbPutW(1, 11); // length hlp.msbPutQ(3, ntry.best.accIgp); // value hlp.putSkip(11); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrAccIgp, trg, hlp); } } class rtrBgpAttrPmsiTun implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.pmsiTyp = pck.msbGetW(0); ntry.best.pmsiLab = pck.msbGetD(2) >>> 8; pck.getSkip(5); ntry.best.pmsiTun = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.pmsiTun == null) { return; } hlp.clear(); hlp.msbPutW(0, ntry.best.pmsiTyp); hlp.msbPutD(2, ntry.best.pmsiLab << 8); hlp.putSkip(5); hlp.putCopy(ntry.best.pmsiTun, 0, 0, ntry.best.pmsiTun.length); hlp.putSkip(ntry.best.pmsiTun.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrPmsiTun, trg, hlp); } } class rtrBgpAttrLinkState implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.linkStat = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.linkStat == null) { return; } hlp.clear(); hlp.putCopy(ntry.best.linkStat, 0, 0, ntry.best.linkStat.length); hlp.putSkip(ntry.best.linkStat.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrLinkState, trg, hlp); } } class rtrBgpAttrTunEnc implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.tunelTyp = pck.msbGetW(0); int len = pck.msbGetW(2); pck.getSkip(4); if (pck.dataSize() < len) { return; } pck.setDataSize(len); ntry.best.tunelVal = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.tunelVal == null) { return; } hlp.clear(); hlp.msbPutW(0, ntry.best.tunelTyp); hlp.msbPutW(2, ntry.best.tunelVal.length); hlp.putSkip(4); hlp.putCopy(ntry.best.tunelVal, 0, 0, ntry.best.tunelVal.length); hlp.putSkip(ntry.best.tunelVal.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrTunEnc, trg, hlp); } } class rtrBgpAttrAttribSet implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.attribAs = pck.msbGetD(0); pck.getSkip(4); ntry.best.attribVal = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.attribVal == null) { return; } hlp.clear(); hlp.msbPutD(0, ntry.best.attribAs); hlp.putSkip(4); hlp.putCopy(ntry.best.attribVal, 0, 0, ntry.best.attribVal.length); hlp.putSkip(ntry.best.attribVal.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrAttribSet, trg, hlp); } } class rtrBgpAttrNshChain implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.nshChain = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.nshChain == null) { return; } hlp.clear(); hlp.putCopy(ntry.best.nshChain, 0, 0, ntry.best.nshChain.length); hlp.putSkip(ntry.best.nshChain.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrNshChain, trg, hlp); } } class rtrBgpAttrDomainPath implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.domainPath = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.domainPath == null) { return; } hlp.clear(); hlp.putCopy(ntry.best.domainPath, 0, 0, ntry.best.domainPath.length); hlp.putSkip(ntry.best.domainPath.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrDomainPath, trg, hlp); } } class rtrBgpAttrSafiSpec implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.safiSpec = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.safiSpec == null) { return; } hlp.clear(); hlp.putCopy(ntry.best.safiSpec, 0, 0, ntry.best.safiSpec.length); hlp.putSkip(ntry.best.safiSpec.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrSafiSpec, trg, hlp); } } class rtrBgpAttrBfdDisc implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.bfdDiscr = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.bfdDiscr == null) { return; } hlp.clear(); hlp.putCopy(ntry.best.bfdDiscr, 0, 0, ntry.best.bfdDiscr.length); hlp.putSkip(ntry.best.bfdDiscr.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrHopCapa, trg, hlp); } } class rtrBgpAttrHopCapa implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.hopCapa = pck.getCopy(); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.hopCapa == null) { return; } hlp.clear(); hlp.putCopy(ntry.best.hopCapa, 0, 0, ntry.best.hopCapa.length); hlp.putSkip(ntry.best.hopCapa.length); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrBfdDisc, trg, hlp); } } class rtrBgpAttrPrefSid implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { encTlv tlv = rtrBgpUtil.getPrefSidTlv(); for (;;) { if (tlv.getBytes(pck)) { break; } switch (tlv.valTyp) { case 1: // label index ntry.best.segrouIdx = bits.msbGetD(tlv.valDat, 3); // index break; case 3: // srgb ntry.best.segrouBeg = bits.msbGetD(tlv.valDat, 2) >>> 8; // base ntry.best.segrouSiz = bits.msbGetD(tlv.valDat, 5) >>> 8; // range break; case 4: // prefix sid addrIPv6 adr6 = new addrIPv6(); ntry.best.segrouPrf = new addrIP(); adr6.fromBuf(tlv.valDat, 3); ntry.best.segrouPrf.fromIPv6addr(adr6); break; case 5: // layer3 service case 6: // layer2 service if (tlv.valDat[1] != 1) { // subtlv break; } adr6 = new addrIPv6(); ntry.best.segrouEth = tlv.valTyp == 6; ntry.best.segrouBeh = bits.msbGetW(tlv.valDat, 22); ntry.best.segrouPrf = new addrIP(); adr6.fromBuf(tlv.valDat, 5); ntry.best.segrouPrf.fromIPv6addr(adr6); if (tlv.valDat[25] != 1) { // sid structure break; } ntry.best.segrouSiz = tlv.valDat[32] & 0xff; // transposition length ntry.best.segrouOfs = tlv.valDat[33] & 0xff; // transposition offset break; } } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { hlp.clear(); encTlv tlv = rtrBgpUtil.getPrefSidTlv(); if (ntry.best.segrouIdx != 0) { tlv.valDat[0] = 0; // reserved bits.msbPutW(tlv.valDat, 1, 0); // flags bits.msbPutD(tlv.valDat, 3, ntry.best.segrouIdx); // index tlv.putBytes(hlp, 1, 7, tlv.valDat); } if (ntry.best.segrouSiz != 0) { bits.msbPutW(tlv.valDat, 0, 0); // flags bits.msbPutD(tlv.valDat, 2, ntry.best.segrouBeg << 8); // base bits.msbPutD(tlv.valDat, 5, ntry.best.segrouSiz << 8); // range tlv.putBytes(hlp, 3, 8, tlv.valDat); } if (ntry.best.segrouPrf != null) { tlv.valDat[0] = 0; // reserved tlv.valDat[1] = 1; // subtlv type bits.msbPutW(tlv.valDat, 2, 30); // size tlv.valDat[4] = 0; // reserved ntry.best.segrouPrf.toIPv6().toBuffer(tlv.valDat, 5); tlv.valDat[21] = 0; // sid flags bits.msbPutW(tlv.valDat, 22, ntry.best.segrouBeh); // behavior tlv.valDat[24] = 0; // reserved tlv.valDat[25] = 1; // sid structure bits.msbPutW(tlv.valDat, 26, 6); // subsubtlv length tlv.valDat[28] = 32; // locator block length tlv.valDat[29] = 16; // locator node length tlv.valDat[30] = 16; // locator function length tlv.valDat[31] = 0; // locator argument length tlv.valDat[32] = (byte) ntry.best.segrouSiz; // transposition length tlv.valDat[33] = (byte) ntry.best.segrouOfs; // transposition offset tlv.putBytes(hlp, ntry.best.segrouEth ? 6 : 5, 34, tlv.valDat); } if (hlp.headSize() < 1) { return; } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrPrefSid, trg, hlp); } } class rtrBgpAttrBier implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { encTlv tlv = rtrBgpUtil.getBierTlv(); for (;;) { if (tlv.getBytes(pck)) { break; } switch (tlv.valTyp) { case 1: // bier ntry.best.bierSub = tlv.valDat[0]; // subdomain ntry.best.bierIdx = bits.msbGetW(tlv.valDat, 1); // bfr id break; case 2: // mpls ntry.best.bierBeg = bits.msbGetD(tlv.valDat, 0) & 0xfffff; // base ntry.best.bierSiz = tlv.valDat[0] & 0xff; // range ntry.best.bierHdr = (tlv.valDat[1] >>> 4) & 0xf; // bsl break; } } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.bierIdx == 0) { return; } hlp.clear(); encTlv tlv = rtrBgpUtil.getBierTlv(); tlv.valDat[0] = (byte) ntry.best.bierSub; // subdomain bits.msbPutW(tlv.valDat, 1, ntry.best.bierIdx); // bfr id tlv.putBytes(hlp, 1, 4, tlv.valDat); if (ntry.best.bierSiz != 0) { bits.msbPutD(tlv.valDat, 0, ntry.best.bierBeg); // base + bsl tlv.valDat[1] |= (byte) (ntry.best.bierHdr << 4); // bsl tlv.valDat[0] = (byte) ntry.best.bierSiz; // range tlv.putBytes(hlp, 2, 4, tlv.valDat); } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrBier, trg, hlp); } } class rtrBgpAttrClustList implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.clustList = new ArrayList(); for (; pck.dataSize() >= 4;) { addrIPv4 adr4 = new addrIPv4(); pck.getAddr(adr4, 0); pck.getSkip(addrIPv4.size); addrIP addr = new addrIP(); addr.fromIPv4addr(adr4); ntry.best.clustList.add(addr); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.clustList == null) { return; } hlp.clear(); for (int i = 0; i < ntry.best.clustList.size(); i++) { hlp.putAddr(0, ntry.best.clustList.get(i).toIPv4()); hlp.putSkip(addrIPv4.size); } rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional, rtrBgpUtil.attrClustList, trg, hlp); } } class rtrBgpAttrOnlyCust implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { ntry.best.onlyCust = pck.msbGetD(0); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.onlyCust == 0) { return; } hlp.clear(); hlp.msbPutD(0, ntry.best.onlyCust); hlp.putSkip(4); rtrBgpAttr.placeAttrib(spkr, rtrBgpUtil.flagOptional | rtrBgpUtil.flagTransitive, rtrBgpUtil.attrOnlyCust, trg, hlp); } } class rtrBgpAttrUnknown implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { if (spkr.neigh.unknownsLog) { logger.info("got unknown (" + pck.ETHtype + ") attribute " + spkr.neigh.peerAddr + " -> " + spkr.neigh.localAddr + " " + pck.dump()); } if (ntry.best.unknown == null) { ntry.best.unknown = new ArrayList(); } tabRouteBlob blb = new tabRouteBlob(); blb.type = pck.ETHtype; blb.flag = pck.ETHcos; blb.data = pck.getCopy(); ntry.best.unknown.add(blb); } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { if (ntry.best.unknown == null) { return; } for (int i = 0; i < ntry.best.unknown.size(); i++) { tabRouteBlob blb = ntry.best.unknown.get(i); hlp.clear(); hlp.putCopy(blb.data, 0, 0, blb.data.length); hlp.putSkip(blb.data.length); if (spkr.neigh.unknownsLog) { logger.info("sent unknown (" + blb.type + ") attribute " + spkr.neigh.peerAddr + " -> " + spkr.neigh.localAddr + " " + hlp.dump()); } rtrBgpAttr.placeAttrib(spkr, blb.flag, blb.type, trg, hlp); } } } class rtrBgpAttrReachable implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { int safi = rtrBgpUtil.triplet2safi(pck.msbGetD(0)); int idx = spkr.parent.safi2idx(safi); if (idx < 0) { return; } int sfi = safi & rtrBgpUtil.sfiMask; int len = pck.getByte(3); rtrBgpAfi rdr = spkr.parent.safi2rdr[idx]; boolean addpath = spkr.addpathRx[idx]; boolean oneLab = !spkr.peerMltLab[idx]; boolean v6nh = len >= addrIPv6.size; pck.getSkip(4); len = pck.dataSize() - len; addrIP nextHop = null; for (; pck.dataSize() > len;) { if ((sfi == rtrBgpUtil.sfiMplsVpnU) || (sfi == rtrBgpUtil.sfiMplsVpnM) || (sfi == rtrBgpUtil.sfiClsTrnPl)) { pck.getSkip(8); // rd } addrIP adr; if (v6nh) { adr = rtrBgpAfi.readAddress(rtrBgpUtil.afiIpv6, pck); } else { adr = rtrBgpAfi.readAddress(rtrBgpUtil.afiIpv4, pck); } if (adr == null) { continue; } if (nextHop == null) { nextHop = adr; continue; } if (!v6nh) { addrIPv4 adr4 = adr.toIPv4(); if (adr4.isEmpty()) { continue; } } else { addrIPv6 adr6 = adr.toIPv6(); if (adr6.isEmpty()) { continue; } if (adr6.isLinkLocal()) { continue; } } nextHop = adr; } pck.setBytesLeft(len); len = pck.getByte(0); pck.getSkip(1); for (int i = 0; i < len; i++) { pck.getSkip(pck.getByte(0) + 1); } int ident = 0; for (; pck.dataSize() > 0;) { if (addpath) { ident = pck.msbGetD(0); pck.getSkip(4); } tabRouteEntry res = rdr.readPrefix(oneLab, pck); if (res == null) { continue; } res.oldDst = idx; res.best.ident = ident; res.best.nextHop = nextHop; spkr.currAdd.add(res); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { } } class rtrBgpAttrUnReach implements rtrBgpAttr { public void readAttrib(rtrBgpSpeak spkr, tabRouteEntry ntry, packHolder pck) { pck.merge2beg(); int safi = rtrBgpUtil.triplet2safi(pck.msbGetD(0)); pck.getSkip(3); int idx = spkr.parent.safi2idx(safi); if (idx < 0) { return; } boolean addpath = spkr.addpathRx[idx]; rtrBgpAfi rdr = spkr.parent.safi2rdr[idx]; int ident = 0; for (; pck.dataSize() > 0;) { if (addpath) { ident = pck.msbGetD(0); pck.getSkip(4); } tabRouteEntry res = rdr.readPrefix(true, pck); if (res == null) { continue; } res.oldDst = idx; res.best.ident = ident; spkr.currDel.add(res); } } public void writeAttrib(rtrBgpSpeak spkr, packHolder trg, packHolder hlp, tabRouteEntry ntry) { } }