org.javamrt.mrt.BGPFileReader.java Source code

Java tutorial

Introduction

Here is the source code for org.javamrt.mrt.BGPFileReader.java

Source

// This file is part of java-mrt
// A library to parse MRT files

// This file is released under LGPL 3.0
// http://www.gnu.org/licenses/lgpl-3.0-standalone.html

package org.javamrt.mrt;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.LinkedList;
import java.util.zip.GZIPInputStream;

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.javamrt.utils.Debug;
import org.javamrt.utils.RecordAccess;

public class BGPFileReader {
    private static final boolean debug = false;

    private BufferedInputStream in = null;
    private LinkedList<MRTRecord> recordFifo;

    private boolean eof = false;

    private byte[] header;
    private byte[] record;

    private String toString;

    /*****
     *
     * public BGPFileReader (BufferedInputStream in)
     *
     * create a new BGPFileReader from BufferedInputStream <in>
     */

    public BGPFileReader(BufferedInputStream in) {
        this.in = in;
        this.toString = in.toString();
        this.recordFifo = new LinkedList<MRTRecord>();
        this.header = new byte[12]; // always 12 bytes, create once
        this.record = null;
        this.eof = false;
    }

    /*****
     *
     * public BGPFileReader (String name)
     *
     * create a new BGPFileReader from BufferedInputStream specified by the
     * String name
     * @throws Exception
     */

    public BGPFileReader(String name) throws Exception {
        InputStream inStream = null;
        this.toString = name;

        try { // to open the name as a URL
            java.net.URL url = new java.net.URL(name);
            inStream = url.openStream();
        } catch (java.net.MalformedURLException e) {
            File inFile = new File(name);
            if (!inFile.exists())
                throw new java.io.FileNotFoundException(name);
            inStream = new FileInputStream(inFile);
        }

        if (this.toString.endsWith(".gz")) {
            this.in = new BufferedInputStream(new GZIPInputStream(inStream));
        } else if (this.toString().endsWith(".bz2")) {
            this.in = new BufferedInputStream(new BZip2CompressorInputStream(inStream), 1);
        } else {
            this.in = new BufferedInputStream(inStream);
        }

        this.recordFifo = new LinkedList<MRTRecord>();
        this.header = new byte[12]; // always 12 bytes, create once
        this.record = null;
        this.eof = false;
    }

    public BGPFileReader(File f) throws IOException {
        if (!f.exists())
            throw new java.io.FileNotFoundException();
        FileInputStream inStream = new FileInputStream(f);
        this.toString = f.getCanonicalPath();
        if (this.toString.endsWith(".gz")) {
            this.in = new BufferedInputStream(new GZIPInputStream(inStream));
        } else {
            this.in = new BufferedInputStream(inStream);
        }
        this.recordFifo = new LinkedList<MRTRecord>();
        this.header = new byte[12]; // always 12 bytes, create once
        this.record = null;
        this.eof = false;
    }

    /***
     * void close()
     *
     * close the BGPFileReader
     */
    public void close() throws java.io.IOException {
        this.in.close();
        this.recordFifo.clear();
        this.recordFifo = null;
        this.header = null;
        this.record = null;
    }

    /**
     * toString(): return the name of the input Stream
     */
    public String toString() {
        return this.toString;
    }

    /***
     *
     * MRTRecord readNext()
     *
     * returns next record on successful completion null on EOF
     *
     * throws Exception when something goes wrong
     */

    private int recordlen = 0;
    private int type = 0;
    private int subtype = 0;
    private long time = 0;

    private long recordCounter = 0;

    /**
     * @return the number of MRT binary format records read.<br>
     * In the new MRT record formats, that has little or nothing<br>
     * to do with the number of BGP Events read, since a record might<br>
     * hold several BGP events. We need this in our quest for soft session<br>
     * restarts.
     */
    public long mrtRecords() {
        return recordCounter;
    }

    /**
     * The name MRT record is not perfect, because actually it's routing events we get
     * @return a BGP event or a BGP control message.
     * @throws Exception
     */
    public MRTRecord readNext() throws Exception {
        MRTRecord result = null;
        while (true) {
            /*
             * Consume any records waiting in the queue
             *
             * using recordFifo.add(MRTRecord) <=> recordFifo.remove()
             */
            if (recordFifo.size() != 0)
                return recordFifo.remove();

            /*
             * Help GC
             */
            if (record != null)
                record = null;
            /*
             * if the queue is empty, read from the file
             */

            int leidos = this.in.read(header, 0, header.length);
            recordCounter++;
            /*
             * EOF
             */
            if (leidos <= 0) {
                this.eof = true;
                return null;
            }
            /*
             * truncated
             */
            if (leidos != this.header.length) {
                this.eof = true;
                throw new BGPFileReaderException(
                        "Truncated file: " + leidos + " instead of " + this.header.length + " bytes", header);
            }
            if (Debug.compileDebug)
                RecordAccess.dump(Debug.debugStream, header);
            time = RecordAccess.getU32(header, 0);
            type = RecordAccess.getU16(header, 4);
            subtype = RecordAccess.getU16(header, 6);
            recordlen = (int) (0xffffffff & RecordAccess.getU32(header, 8));

            if (Debug.compileDebug)
                Debug.println("TIME: " + time + "\n TYPE: " + type + "\n SUBTYPE: " + subtype + "\n RECORDLENGTH: "
                        + recordlen);

            this.record = new byte[recordlen];

            leidos = this.in.read(record, 0, record.length);

            if (leidos != this.record.length) {
                this.eof = true;
                throw new BGPFileReaderException(
                        "Truncated file: " + leidos + " instead of " + this.record.length + " bytes", record);
            }

            /*
             * Record parsing
             */
            switch (type) {
            case MRTConstants.TABLE_DUMP:
                return parseTableDump(subtype);

            case MRTConstants.TABLE_DUMP_v2:

                switch (subtype) {
                case MRTConstants.PEER_INDEX_TABLE:
                    parsePeerIndexTable();
                    break;
                case 2:
                    parseTableDumpv2(MRTConstants.AFI_IPv4);
                    break;
                case 4:
                    parseTableDumpv2(MRTConstants.AFI_IPv6);
                    break;
                case 6:
                    parseGenericRib();
                    break;
                case 3:
                case 5:
                    parseTableDumpv2Multicast();
                    break;
                default:
                    throw new BGPFileReaderException("Unknown TABLE_DUMP_V2 subtype" + subtype, header);
                }
                break;

            case MRTConstants.BGP4MP:
                if ((result = parseBgp4mp(subtype)) != null)
                    return result;
                break;

            default:
                result = new MRTRecord();
                result.setGeneric(header, record);
                return result;
            }
        }
    }

    private MRTRecord parseTableDump(int subtype) throws Exception {
        switch (subtype) {
        case MRTConstants.AFI_IPv4:
        case MRTConstants.AFI_IPv6:
            return new TableDump(header, record, subtype);
        default:
            throw new BGPFileReaderException("Unknown TABLE_DUMP subtype" + subtype, header);
        }

    }

    private MRTRecord parseBgp4mp(int subtype) throws Exception {
        // System.out.println("parseBgp4mp("+MRTConstants.mpSubType(subtype)+")");
        switch (subtype) {
        case MRTConstants.BGP4MP_MESSAGE:
        case MRTConstants.BGP4MP_MESSAGE_AS4:
            return parseBgp4Update((subtype == MRTConstants.BGP4MP_MESSAGE) ? 2 : 4);

        /*
         * TODO
         * TTOODDOO::::
         *
         *
         * case BGP4MP_SNAPSHOT: return new Bgp4mpSnapshot(header,record);
         */

        case MRTConstants.BGP4MP_ENTRY:
            return parseBgp4Entry(RecordAccess.getU16(record, 6));

        case MRTConstants.BGP4MP_STATE_CHANGE: {
            /*
             * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
             * 9 0 1
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer AS number | Local AS number |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Interface Index | Address Family |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer IP address (variable) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Local IP address (variable) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Old State | New State |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             */

            int afi = RecordAccess.getU16(record, 6);
            int addrOffs = 8;
            int addrSize = (afi == MRTConstants.AFI_IPv4) ? 4 : 16;
            int stateOffs = addrOffs + 2 * addrSize;
            int oldState = RecordAccess.getU16(record, stateOffs);
            stateOffs += 2;
            int newState = RecordAccess.getU16(record, stateOffs);

            return new StateChange(RecordAccess.getU32(header, 0),
                    InetAddress.getByAddress(RecordAccess.getBytes(record, addrOffs, addrSize)),
                    new AS(RecordAccess.getU16(record, 0)), oldState, newState);

        }

        case MRTConstants.BGP4MP_STATE_CHANGE_AS4: {
            /*
             * draft-ietf-grow-mrt-07.txt
             *
             * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
             * 9 0 1
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer AS number |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Local AS number |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Interface Index | Address Family |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer IP address (variable) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Local IP address (variable) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Old State | New State |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             */

            int afi = RecordAccess.getU16(record, 10);
            int addrSize = (afi == MRTConstants.AFI_IPv4) ? 4 : 16;
            int addrOffs = 12;
            int stateOffs = addrOffs + 2 * addrSize;
            int oldState = RecordAccess.getU16(record, stateOffs);
            stateOffs += 2;
            int newState = RecordAccess.getU16(record, stateOffs);

            return new StateChange(RecordAccess.getU32(header, 0),
                    InetAddress.getByAddress(RecordAccess.getBytes(record, addrOffs, addrSize)),
                    new AS(RecordAccess.getU32(record, 0)), oldState, newState);

        }

        default:
            break;
        }

        MRTRecord result = new MRTRecord();
        result.setGeneric(header, record);
        return result;
    }

    private void parsePeerIndexTable() throws Exception {
        /*
         * System.out.println("in BGPFileReader.parsePeerIndexTable\nheader:");
         * RecordAccess.dump(header); System.out.println("record");
         * RecordAccess.dump(record);
         */
        // System.err.println("\nin parsePeerIndexTable()...");
        /*
         * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
         * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
         * Collector BGP ID |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
         * View Name Length | View Name (variable) |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
         * Peer Count | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */

        int here = 0;
        // long CollectorBGPId = RecordAccess.getU32 (this.record,here);
        here += 4;
        int ViewNameLen = RecordAccess.getU16(this.record, here);
        here += 2;
        // String ViewName = null;
        if (ViewNameLen > 0) {
            // TODO extract ViewName
            here += ViewNameLen;
        }
        int PeerCount = RecordAccess.getU16(this.record, here);
        here += 2;

        /*
         * System.out.printf("Collector BGP Id: 0x%08X\n",CollectorBGPId);
         * System.out.printf("View Name Length = %d\n",ViewNameLen);
         * System.out.printf(" has %d peers\n",PeerCount);
         */
        bgpId = new long[PeerCount];
        peerAS = new org.javamrt.mrt.AS[PeerCount];
        peerIP = new InetAddress[PeerCount];

        for (int i = 0; i < PeerCount; i++) {
            /*
             * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
             * 9 0 1
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer Type |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer BGP ID |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer IP address (variable) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             * | Peer AS (variable) |
             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             *
             * The Peer Type field is a bit field which encodes the type of the
             * AS and IP address as follows:
             *
             * Bit 0 - unset for IPv4 Peer IP address, set for IPv6 Bit 1 -
             * unset when Peer AS field is 16 bits, set when it's 32 bits
             */
            int peerType = RecordAccess.getU8(this.record, here++);
            bgpId[i] = RecordAccess.getU32(this.record, here);
            here += 4;
            if ((peerType & 0x01) == 0) {
                peerIP[i] = InetAddress.getByAddress(RecordAccess.getBytes(this.record, here, 4));
                here += 4;
            } else {
                peerIP[i] = InetAddress.getByAddress(RecordAccess.getBytes(this.record, here, 16));
                here += 16;
            }
            if ((peerType & 0x02) == 0) {
                peerAS[i] = new AS(RecordAccess.getU16(this.record, here));
                here += 2;
            } else {
                peerAS[i] = new AS(RecordAccess.getU32(this.record, here));
                here += 4;
            }

            // System.out.println("Peer "+i+"("+bgpId[i]+"): "+peerIP[i].getHostAddress()+" "+peerAS[i]);
        }

        // System.exit(0);
    }

    private long[] bgpId = null;
    private org.javamrt.mrt.AS peerAS[] = null;
    private java.net.InetAddress peerIP[] = null;

    private void parseTableDumpv2(int NLRItype) throws Exception {

        if (Debug.compileDebug) {
            Debug.printf("parseTableDumpv2(%d)\nheader:", NLRItype);
            Debug.dump(header);
            Debug.println("record:");
            Debug.dump(record);
        }

        int offset = 0;
        long sequenceNo = RecordAccess.getU32(this.record, offset);
        offset = 4;
        Nlri nlri = new Nlri(this.record, offset, NLRItype);
        offset += nlri.getOffset();

        int entryCount = RecordAccess.getU16(this.record, offset);
        offset += 2;

        if (debug) {
            System.out.println("Sequence = " + sequenceNo);
            System.out.println("NLRI     = " + nlri.toPrefix().toString() + " [" + nlri.getOffset() + "]");
            System.out.println("entries  = " + entryCount);
        }

        for (int i = 0; i < entryCount; i++) {
            int peerIndex = RecordAccess.getU16(this.record, offset);

            if (debug) {
                System.out.printf("peerIndex = %d; peer = %s(%s)\n", peerIndex,
                        MRTConstants.ipAddressString(peerIP[peerIndex]), peerAS[peerIndex].toString("AS"));
            }

            offset += 2;
            // TODO use origTime if appropriate
            //
            // long timeOrig=RecordAccess.getU32(this.record,offset);
            offset += 4;
            int attrLen = RecordAccess.getU16(this.record, offset);
            offset += 2;
            Attributes attributes = new Attributes(record, attrLen, offset, 4);
            offset += attrLen;

            recordFifo.add(new TableDumpv2(1, // int view,
                    (int) (sequenceNo & 0xffff), nlri, time, peerIP[peerIndex], // InetAddress
                    // peer,
                    peerAS[peerIndex], attributes));
        }
    }

    private MRTRecord parseBgp4Update(int asSize) throws Exception {
        // Bgp4Update update;

        // TODO reconocer los AS de 4 bytes aqu

        int offset = 0;
        AS srcAs = new AS(RecordAccess.getUINT(record, offset, asSize));
        offset = asSize;
        AS dstAs = new AS(RecordAccess.getUINT(record, offset, asSize));
        offset += asSize;
        int iface = RecordAccess.getU16(record, offset);
        offset += 2;
        int afi = RecordAccess.getU16(record, offset);
        offset += 2;
        //      int offset = 2 * asSize + 4;
        int addrSize = (afi == MRTConstants.AFI_IPv4) ? 4 : 16;

        InetAddress srcIP = InetAddress.getByAddress(RecordAccess.getBytes(record, offset, addrSize));
        offset += addrSize;
        InetAddress dstIP = InetAddress.getByAddress(RecordAccess.getBytes(record, offset, addrSize));
        offset += addrSize;

        /*
         * skip the following 16 bytes which are the signature of the BGP header
         */
        offset += 16;

        int bgpSize = RecordAccess.getU16(record, offset);
        offset += 2;
        int bgpType = RecordAccess.getU8(record, offset);
        offset++;

        if (Debug.compileDebug) {
            Debug.printf("Bgp4Update(asSize = %d)\n", asSize);
            Debug.printf("AS srcAs     = %s\n", srcAs.toString());
            Debug.printf("AS dstAs     = %s\n", dstAs.toString());
            Debug.printf("int iface    = %d\n", iface);
            Debug.printf("int Afi      = %d\n", afi);
            Debug.printf("int addrSize = %d\n", addrSize);
            Debug.println("srcIP        = " + srcIP.getHostAddress());
            Debug.println("dstIP        = " + dstIP.getHostAddress());
            Debug.printf("bgpSize      = %d\n", bgpSize);
            Debug.println("bgpType      = " + MRTConstants.bgpType(bgpType));
            Debug.dump(record);
        }
        switch (bgpType) {
        case MRTConstants.BGP4MSG_KEEPALIVE:
            return new KeepAlive(header, record);

        case MRTConstants.BGP4MSG_OPEN:
            return new Open(header, record);

        case MRTConstants.BGP4MSG_NOTIFICATION:
            return new Notification(header, record);

        case MRTConstants.BGP4MSG_UPDATE:
            break; // to continue after case()

        case MRTConstants.BGP4MSG_REFRESH:
            return new Refresh(header, record);

        default:
            throw new Exception("Unknown BGP4 record type(" + bgpType + ")");
        }

        /*
         * Here is where the update starts
         */

        int unfeasibleLen = RecordAccess.getU16(record, offset);
        offset += 2;
        if (Debug.compileDebug)
            Debug.printf("int unfeasibleLen = %d\n", unfeasibleLen);

        for (int i = 0; i < unfeasibleLen;) {
            Nlri wNlri = new Nlri(record, offset, afi);
            offset += wNlri.getOffset();
            i += wNlri.getOffset();

            recordFifo.add(new Withdraw(header, srcIP, srcAs, wNlri.toPrefix()));
        }

        int attrLen = RecordAccess.getU16(record, offset);
        if (Debug.compileDebug)
            Debug.printf("attrLen = %d, offset =%d (%d)\n", attrLen, offset, offset + attrLen + 2);
        offset += 2;

        if (attrLen > 0) {
            Attributes attributes = null;
            try {
                attributes = new Attributes(record, attrLen, offset, asSize);
            } catch (RFC4893Exception rfce) {
                //
                // piggyback peer and time info
                //
                rfce.setTimestamp(this.time);
                rfce.setPeer(srcIP);
                rfce.setAS(srcAs);
                throw rfce;
            } catch (Exception e) {
                throw e;
            }
            //
            // Process MP_REACH and MP_UNREACH
            //

            MpUnReach mpUnreach = (MpUnReach) attributes.getAttribute(MRTConstants.ATTRIBUTE_MP_UNREACH);

            if (mpUnreach != null) {
                for (Nlri mpu : mpUnreach.getNlri()) {
                    recordFifo.add(new Withdraw(header, srcIP, srcAs, mpu.toPrefix()));
                }
            }

            MpReach mpReach = (MpReach) attributes.getAttribute(MRTConstants.ATTRIBUTE_MP_REACH);

            if (mpReach != null) {
                if (Debug.compileDebug)
                    Debug.printf("Has MP_REACH (%s)\n", mpReach.getNlri());
                for (Nlri mpu : mpReach.getNlri()) {
                    recordFifo.add(new Advertisement(header, srcIP, srcAs, mpu.toPrefix(), attributes));
                }
            }

            /*
             * if (mpReach != null || mpUnreach != null)
             * System.out.println("This is the whole record");
             * RecordAccess.dump(record);
             * System.out.println("These are the attributes");
             * RecordAccess.dump(record,offset,attrLen);
             * System.out.println("int attrLen = "+attrLen);
             *
             * throw new Exception("MP_REACH attribute!");
             */

            offset += attrLen;

            if (Debug.compileDebug)
                Debug.debug("offset(%d) record.length (%d)\n", offset, record.length);
            while (offset < record.length) {
                Nlri aNlri = new Nlri(record, offset, afi);
                offset += aNlri.getOffset();

                recordFifo.add(new Advertisement(header, srcIP, srcAs, aNlri.toPrefix(), attributes));
            }
        }
        if (recordFifo.isEmpty()) {
            if (Debug.compileDebug)
                if (Debug.doDebug)
                    throw new BGPFileReaderException("recordFifo empty!", record);
            return null;
        }
        return recordFifo.remove();
    }

    private MRTRecord parseBgp4Entry(int AFI) throws Exception {
        /*
         * TODO: this doesn't work as expected yet
         */
        if (Debug.compileDebug) {
            Debug.debug("in parseBgp4Entry\n");
            Debug.dump(record);
        }
        int addrSize = (AFI == MRTConstants.AFI_IPv4) ? 4 : 16;

        int view = RecordAccess.getU16(record, 0);
        int status = RecordAccess.getU16(record, 2);
        long rtime = RecordAccess.getU32(record, 4);
        int af = RecordAccess.getU16(record, 8);
        int safi = RecordAccess.getU8(record, 10);
        int nhl = RecordAccess.getU8(record, 11);

        if (Debug.compileDebug) {
            Debug.debug("int  view   = %d\n", view);
            Debug.debug("int  status = %d\n", status);
            Debug.debug("long rtime  = %d\n", rtime);
            Debug.debug("int  af     = %d\n", af);
            Debug.debug("int  safi   = %d\n", safi);
            Debug.debug("int  nhl    = %d\n", nhl);
        }
        int offset = 12;
        InetAddress nextHop = InetAddress.getByAddress(RecordAccess.getBytes(record, offset, addrSize));
        offset += addrSize;
        Nlri prefix = new Nlri(record, offset, AFI);
        offset += prefix.getOffset();

        Attributes attrs = new Attributes(record, record.length - offset, offset);
        ASPath aspath = attrs.getASPath();

        AS neighborAS = null;

        if (aspath != null)
            neighborAS = aspath.get(0);

        return new TableDumpv2(view, 1, prefix, rtime, nextHop, neighborAS, attrs);
    }

    private void parseGenericRib() throws BGPFileReaderException {
        // TODO: implement
        throw new BGPFileReaderException("TODO : parseGenericRib", new byte[1]);
    }

    private void parseTableDumpv2Multicast() throws BGPFileReaderException {
        // TODO: implement
        throw new BGPFileReaderException("TODO: parseTableDumpv2Multicast()", new byte[1]);
    }

    public boolean eof() {
        return this.eof;
    }

}