package org.freertr.rtr; import java.util.List; import org.freertr.addr.addrIP; import org.freertr.addr.addrIPv4; import org.freertr.addr.addrPrefix; import org.freertr.ip.ipFwd; import org.freertr.ip.ipFwdIface; import org.freertr.ip.ipRtr; import org.freertr.pack.packHolder; import org.freertr.prt.prtGenConn; import org.freertr.prt.prtServP; import org.freertr.prt.prtUdp; import org.freertr.tab.tabGen; import org.freertr.tab.tabIndex; import org.freertr.tab.tabRoute; import org.freertr.tab.tabRouteAttr; import org.freertr.tab.tabRouteEntry; 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; /** * routing information protocol (rfc2453) version 2 * * @author matecsaba */ public class rtrRip4 extends ipRtr implements prtServP { /** * port number */ public final static int port = 520; /** * version number */ public final static int version = 2; /** * address family identifier */ public final static int afiID = 2; /** * size of header */ public final static int sizeHead = 4; /** * size of routing entry */ public final static int sizeNtry = 20; /** * minimum metric */ public final static int metricMin = 1; /** * maximum metric this is the inaccessibly one */ public final static int metricMax = 16; /** * entries per update */ public final static int entryPerUpdate = 23; /** * the udp protocol */ protected prtUdp udpCore; /** * forwarding core */ public final ipFwd fwdCore; /** * suppress interface addresses */ public boolean suppressAddr; private tabGen ifaces; private tabGen neighs; /** * create one rip process * * @param forwarder the ip protocol * @param protocol the udp protocol * @param id process id */ public rtrRip4(ipFwd forwarder, prtUdp protocol, int id) { if (debugger.rtrRip4evnt) { logger.debug("startup"); } fwdCore = forwarder; udpCore = protocol; ifaces = new tabGen(); neighs = new tabGen(); routerCreateComputed(); fwdCore.routerAdd(this, tabRouteAttr.routeType.rip4, id); } /** * get neighbor count * * @return count */ public int routerNeighCount() { return neighs.size(); } /** * list neighbors * * @param tab list */ public void routerNeighList(tabRoute tab) { for (int i = 0; i < neighs.size(); i++) { rtrRip4neigh nei = neighs.get(i); if (nei == null) { continue; } if (nei.iface.iface.lower.getState() != state.states.up) { continue; } tabRouteEntry ntry = new tabRouteEntry(); ntry.prefix = new addrPrefix(nei.conn.peerAddr, addrIP.size * 8); tabRoute.addUpdatedEntry(tabRoute.addType.better, tab, rtrBgpUtil.sfiUnicast, 0, ntry, true, null, null, routerAutoMesh); } } /** * get interface count * * @return count */ public int routerIfaceCount() { return ifaces.size(); } /** * maximum recursion depth * * @return allowed number */ public int routerRecursions() { return 1; } /** * get list of link states * * @param tab table to update * @param par parameter * @param asn asn * @param adv advertiser */ public void routerLinkStates(tabRoute tab, int par, int asn, addrIPv4 adv) { } /** * convert to string * * @return string */ public String toString() { return "rip on " + fwdCore; } /** * add one interface to work on * * @param ifc ip forwarder interface * @return false if successful, true if error happened */ public rtrRip4iface addInterface(ipFwdIface ifc) { if (debugger.rtrRip4evnt) { logger.debug("add iface " + ifc); } if (ifc == null) { return null; } rtrRip4iface ntry = new rtrRip4iface(this, ifc); rtrRip4iface old = ifaces.add(ntry); if (old != null) { ntry = old; } ntry.register2udp(); routerCreateComputed(); return ntry; } /** * close interface * * @param iface interface */ public void closedInterface(ipFwdIface iface) { rtrRip4iface ifc = new rtrRip4iface(this, iface); ifc = ifaces.del(ifc); if (ifc == null) { return; } ifc.unregister2udp(); for (int i = neighs.size() - 1; i >= 0; i--) { rtrRip4neigh nei = neighs.get(i); if (nei.iface.iface.ifwNum != iface.ifwNum) { continue; } neighs.del(nei); nei.unregister2udp(); } routerCreateComputed(); } /** * start connection * * @param id connection * @return false on success, true on error */ public boolean datagramAccept(prtGenConn id) { rtrRip4iface ifc = new rtrRip4iface(this, id.iface); ifc = ifaces.find(ifc); if (ifc == null) { logger.warn("no interface " + id); return true; } if ((ifc.connectedCheck) && (!ifc.iface.lower.checkConnected(id.peerAddr))) { logger.warn("got from out of subnet peer " + id); return true; } logger.warn("neighbor " + id.peerAddr + " up"); rtrRip4neigh ntry = new rtrRip4neigh(id, ifc); rtrRip4neigh old = neighs.add(ntry); if (old != null) { ntry = old; } ntry.conn = id; if (ifc.bfdTrigger) { ifc.iface.bfdAdd(id.peerAddr, ntry, "rip"); } return false; } /** * connection ready * * @param id connection */ public void datagramReady(prtGenConn id) { } /** * close connection * * @param id connection */ public void datagramClosed(prtGenConn id) { rtrRip4neigh ntry = new rtrRip4neigh(id, null); ntry = neighs.del(ntry); if (ntry == null) { return; } logger.error("neighbor " + id.peerAddr + " down"); id.iface.bfdDel(id.peerAddr, ntry); routerCreateComputed(); } /** * work connection * * @param id connection */ public void datagramWork(prtGenConn id) { rtrRip4neigh nei = new rtrRip4neigh(id, null); nei = neighs.find(nei); if (nei != null) { if (nei.doWork()) { routerCreateComputed(); } return; } rtrRip4iface ifc = new rtrRip4iface(this, id.iface); ifc = ifaces.find(ifc); if (ifc != null) { ifc.doWork(); return; } id.setClosing(); } /** * received error * * @param id connection * @param pck packet * @param rtr reporting router * @param err error happened * @param lab error label * @return false on success, true on error */ public boolean datagramError(prtGenConn id, packHolder pck, addrIP rtr, counter.reasons err, int lab) { return false; } /** * notified that state changed * * @param id id number to reference connection * @param stat state * @return return false if successful, true if error happened */ public boolean datagramState(prtGenConn id, state.states stat) { if (stat == state.states.up) { return false; } rtrRip4neigh ntry = new rtrRip4neigh(id, null); ntry = neighs.find(ntry); if (ntry == null) { return false; } ntry.bfdPeerDown(); return false; } /** * received packet * * @param id connection * @param pck packet * @return false on success, true on error */ public boolean datagramRecv(prtGenConn id, packHolder pck) { rtrRip4neigh ntry = new rtrRip4neigh(id, null); ntry = neighs.find(ntry); if (ntry == null) { id.setClosing(); return false; } if (ntry.gotPack(pck)) { return false; } routerCreateComputed(); return false; } /** * create computed */ public synchronized void routerCreateComputed() { if (debugger.rtrRip4evnt) { logger.debug("create table"); } tabRoute tab = new tabRoute("rip"); tabRouteEntry ntry; for (int i = 0; i < ifaces.size(); i++) { rtrRip4iface ifc = ifaces.get(i); if (ifc == null) { continue; } if (ifc.iface.lower.getState() != state.states.up) { continue; } if ((suppressAddr || ifc.suppressAddr) && (!ifc.unsuppressAddr)) { continue; } ntry = tab.add(tabRoute.addType.better, ifc.iface.network, null); ntry.best.rouTyp = tabRouteAttr.routeType.conn; ntry.best.iface = ifc.iface; ntry.best.distance = tabRouteAttr.distanIfc; } for (int i = 0; i < neighs.size(); i++) { rtrRip4neigh nei = neighs.get(i); if (nei == null) { continue; } if (!nei.iface.allowRx) { continue; } if (nei.iface.iface.lower.getState() != state.states.up) { continue; } tab.mergeFrom(tabRoute.addType.ecmp, nei.learned, tabRouteAttr.distanLim); } routerDoAggregates(rtrBgpUtil.sfiUnicast, tab, tab, fwdCore.commonLabel, null, 0); tab.setProto(routerProtoTyp, routerProcNum); if (tab.preserveTime(routerComputedU)) { return; } routerComputedU = tab; routerComputedM = tab; routerComputedF = new tabRoute("rx"); routerComputedI = new tabGen>(); fwdCore.routerChg(this, false); } /** * redistribution changed */ public void routerRedistChanged() { routerCreateComputed(); } /** * others changed */ public void routerOthersChanged() { } /** * stop work */ public void routerCloseNow() { for (int i = ifaces.size() - 1; i >= 0; i--) { rtrRip4iface ntry = ifaces.get(i); if (ntry == null) { continue; } ifaces.del(ntry); ntry.unregister2udp(); } for (int i = neighs.size() - 1; i >= 0; i--) { rtrRip4neigh ntry = neighs.get(i); if (ntry == null) { continue; } neighs.del(ntry); ntry.unregister2udp(); } fwdCore.routerDel(this); } /** * get help * * @param l list */ public void routerGetHelp(userHelping l) { l.add(null, "1 . suppress-prefix do not advertise interfaces"); } /** * get config * * @param l list * @param beg beginning * @param filter filter */ public void routerGetConfig(List l, String beg, int filter) { cmds.cfgLine(l, !suppressAddr, beg, "suppress-prefix", ""); } /** * configure * * @param cmd command * @return false on success, true on error */ public boolean routerConfigure(cmds cmd) { String s = cmd.word(); boolean negated = false; if (s.equals(cmds.negated)) { s = cmd.word(); negated = true; } if (s.equals("suppress-prefix")) { suppressAddr = !negated; return false; } return true; } /** * list neighbors * * @return list of neighbors */ public userFormat showNeighs() { userFormat l = new userFormat("|", "interface|learn|neighbor|uptime"); for (int i = 0; i < neighs.size(); i++) { rtrRip4neigh ntry = neighs.get(i); if (ntry == null) { continue; } l.add(ntry.iface.iface + "|" + ntry.learned.size() + "|" + ntry.conn.peerAddr + "|" + bits.timePast(ntry.upTime)); } return l; } /** * list interfaces * * @return list of interfaces */ public userFormat showIfaces() { userFormat l = new userFormat("|", "interface|neighbors"); for (int i = 0; i < ifaces.size(); i++) { rtrRip4iface ifc = ifaces.get(i); l.add(ifc.iface + "|" + countNeighs(ifc.iface.ifwNum)); } return l; } private int countNeighs(int ifc) { int o = 0; for (int i = 0; i < neighs.size(); i++) { rtrRip4neigh nei = neighs.get(i); if (nei.iface.iface.ifwNum == ifc) { o++; } } return o; } /** * find peer * * @param addr address to find * @return neighbor, null if not found */ public rtrRip4neigh findPeer(addrIP addr) { for (int i = 0; i < neighs.size(); i++) { rtrRip4neigh ntry = neighs.get(i); if (ntry == null) { continue; } if (addr.compareTo(ntry.conn.peerAddr) != 0) { continue; } return ntry; } return null; } }