ONOS-2739 - OSPF Basic Packet Structures , which includes encoding and decoding

Change-Id: Ifaaa4d3640c6a4fec4931db54a1f03100cc9d9e6
diff --git a/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/lsa/types/RouterLsa.java b/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/lsa/types/RouterLsa.java
new file mode 100644
index 0000000..9ddef5a
--- /dev/null
+++ b/protocols/ospf/protocol/src/main/java/org/onosproject/ospf/protocol/lsa/types/RouterLsa.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ospf.protocol.lsa.types;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.primitives.Bytes;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.ospf.exceptions.OspfErrorType;
+import org.onosproject.ospf.exceptions.OspfParseException;
+import org.onosproject.ospf.protocol.lsa.LsaHeader;
+import org.onosproject.ospf.protocol.lsa.subtypes.OspfLsaLink;
+import org.onosproject.ospf.protocol.util.OspfUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Representation of a Router LSA, and the fields and methods to access them.
+ */
+public class RouterLsa extends LsaHeader {
+    /*
+        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
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |            LS age             |     Options   |       1       |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                        Link State ID                          |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                     Advertising Router                        |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                     LS sequence number                        |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |         LS checksum           |             length            |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |    0    |V|E|B|        0      |            # links            |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                          Link ID                              |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                         Link Data                             |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |     Type      |     # TOS     |            metric             |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                              ...                              |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |      TOS      |        0      |          TOS  metric          |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                          Link ID                              |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                         Link Data                             |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                              ...                              |
+     */
+    private static final Logger log =
+            LoggerFactory.getLogger(RouterLsa.class);
+    private boolean isVirtualEndPoint;
+    private boolean isAsBoundaryRouter;
+    private boolean isAreaBorderRouter;
+    private int noLink;
+    private List<OspfLsaLink> routerLinks = new ArrayList<>();
+
+    /**
+     * Creates an instance of Router LSA.
+     */
+    public RouterLsa() {
+    }
+
+    /**
+     * Creates an instance of Router LSA.
+     *
+     * @param lsaHeader lsa header instance
+     */
+    public RouterLsa(LsaHeader lsaHeader) {
+        populateHeader(lsaHeader);
+    }
+
+    /**
+     * Sets virtual endpoint or not.
+     *
+     * @param isVirtualEndPoint true or false
+     */
+    public void setVirtualEndPoint(boolean isVirtualEndPoint) {
+        this.isVirtualEndPoint = isVirtualEndPoint;
+    }
+
+    /**
+     * Sets if it is an AS boundary router or not.
+     *
+     * @param isAsBoundaryRouter true if AS boundary router else false
+     */
+    public void setAsBoundaryRouter(boolean isAsBoundaryRouter) {
+        this.isAsBoundaryRouter = isAsBoundaryRouter;
+    }
+
+    /**
+     * Sets whether it is an ABR or not.
+     *
+     * @param isAreaBorderRouter true if ABR else false
+     */
+    public void setAreaBorderRouter(boolean isAreaBorderRouter) {
+        this.isAreaBorderRouter = isAreaBorderRouter;
+    }
+
+    /**
+     * Gets number of links.
+     *
+     * @return number of links
+     */
+    public int noLink() {
+        return noLink;
+    }
+
+    /**
+     * Sets number of links.
+     *
+     * @param noLink number of links
+     */
+    public void setNoLink(int noLink) {
+        this.noLink = noLink;
+    }
+
+
+    /**
+     * Adds router link.
+     *
+     * @param lsaLink LSA link
+     */
+    public void addRouterLink(OspfLsaLink lsaLink) {
+        if (!this.routerLinks.contains(lsaLink)) {
+            this.routerLinks.add(lsaLink);
+        }
+    }
+
+    /**
+     * Gets router link.
+     *
+     * @return routerLinks LSA link list
+     */
+    public List<OspfLsaLink> routerLink() {
+        return this.routerLinks;
+    }
+
+    /**
+     * Reads from channel buffer and populate this.
+     *
+     * @param channelBuffer channelBuffer instance.
+     * @throws OspfParseException might throws exception while parsing buffer
+     */
+    public void readFrom(ChannelBuffer channelBuffer) throws OspfParseException {
+
+        try {
+            int veb = channelBuffer.readByte();
+            int unUsed = channelBuffer.readByte();
+            //Convert the byte to veb bits
+            String strVeb = Integer.toBinaryString(veb);
+            if (strVeb.length() == 3) {
+                this.setVirtualEndPoint((Integer.parseInt(Character.toString(strVeb.charAt(0))) == 1) ? true : false);
+                this.setAsBoundaryRouter((Integer.parseInt(Character.toString(strVeb.charAt(1))) == 1) ? true : false);
+                this.setAreaBorderRouter((Integer.parseInt(Character.toString(strVeb.charAt(2))) == 1) ? true : false);
+            } else if (strVeb.length() == 2) {
+                this.setVirtualEndPoint(false);
+                this.setAsBoundaryRouter((Integer.parseInt(Character.toString(strVeb.charAt(0))) == 1) ? true : false);
+                this.setAreaBorderRouter((Integer.parseInt(Character.toString(strVeb.charAt(1))) == 1) ? true : false);
+            } else if (strVeb.length() == 1) {
+                this.setVirtualEndPoint(false);
+                this.setAsBoundaryRouter(false);
+                this.setAreaBorderRouter((Integer.parseInt(Character.toString(strVeb.charAt(0))) == 1) ? true : false);
+            }
+            this.setNoLink(channelBuffer.readUnsignedShort());
+            while (channelBuffer.readableBytes() >= OspfUtil.TWELVE_BYTES) {
+                OspfLsaLink ospfLsaLink = new OspfLsaLink();
+
+                byte[] tempByteArray = new byte[OspfUtil.FOUR_BYTES];
+                channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
+                ospfLsaLink.setLinkId(InetAddress.getByAddress(tempByteArray).getHostName());
+                tempByteArray = new byte[OspfUtil.FOUR_BYTES];
+                channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
+                ospfLsaLink.setLinkData(InetAddress.getByAddress(tempByteArray).getHostName());
+                ospfLsaLink.setLinkType(channelBuffer.readByte());
+                ospfLsaLink.setTos(channelBuffer.readByte());
+                ospfLsaLink.setMetric(channelBuffer.readUnsignedShort());
+                //add the link
+                this.addRouterLink(ospfLsaLink);
+            }
+        } catch (Exception e) {
+            log.debug("Error::RouterLsa:: {}", e.getMessage());
+            throw new OspfParseException(OspfErrorType.OSPF_MESSAGE_ERROR, OspfErrorType.BAD_MESSAGE);
+        }
+    }
+
+    /**
+     * Returns instance as bytes.
+     *
+     * @return instance as bytes
+     * @throws OspfParseException might throws exception while parsing packet
+     */
+    public byte[] asBytes() throws OspfParseException {
+        byte[] lsaMessage = null;
+
+        byte[] lsaHeader = getLsaHeaderAsByteArray();
+        byte[] lsaBody = getLsaBodyAsByteArray();
+        lsaMessage = Bytes.concat(lsaHeader, lsaBody);
+
+        return lsaMessage;
+    }
+
+    /**
+     * Gets the LSA body as bytes.
+     *
+     * @return LSA body as bytes
+     */
+    public byte[] getLsaBodyAsByteArray() {
+        List<Byte> bodyLst = new ArrayList<>();
+
+        try {
+            int isVirtualEndPointVal = this.isVirtualEndPoint ? 1 : 0;
+            int isASBoundaryRouterVal = this.isAsBoundaryRouter ? 1 : 0;
+            int isAreaBorderRouterVal = this.isAreaBorderRouter ? 1 : 0;
+
+            StringBuilder sb = new StringBuilder();
+            sb.append(Integer.toBinaryString(isVirtualEndPointVal));
+            sb.append(Integer.toBinaryString(isASBoundaryRouterVal));
+            sb.append(Integer.toBinaryString(isAreaBorderRouterVal));
+
+            //added VEB
+            bodyLst.add((byte) Integer.parseInt(sb.toString(), 2));
+            //second byte is 0.
+            bodyLst.add((byte) 0);
+            //Number of links
+            bodyLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.noLink())));
+
+            //add each link details
+            for (OspfLsaLink lsaLink : routerLinks) {
+                bodyLst.addAll(Bytes.asList(InetAddress.getByName(lsaLink.linkId()).getAddress()));
+                bodyLst.addAll(Bytes.asList(InetAddress.getByName(lsaLink.linkData()).getAddress()));
+                bodyLst.add((byte) lsaLink.linkType());
+                bodyLst.add((byte) lsaLink.tos());
+                bodyLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(lsaLink.metric())));
+            }
+        } catch (Exception e) {
+            log.debug("Error::getLsrBodyAsByteArray {}", e.getMessage());
+            return Bytes.toArray(bodyLst);
+        }
+
+        return Bytes.toArray(bodyLst);
+    }
+
+    /**
+     * Increment the link by 1.
+     */
+    public void incrementLinkNo() {
+        this.noLink++;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .omitNullValues()
+                .add("isVirtualEndPoint", isVirtualEndPoint)
+                .add("isAsBoundaryRouter", isAsBoundaryRouter)
+                .add("isAreaBorderRouter", isAreaBorderRouter)
+                .add("noLink", noLink)
+                .add("routerLinks", routerLinks)
+                .toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        RouterLsa that = (RouterLsa) o;
+        return Objects.equal(isVirtualEndPoint, that.isVirtualEndPoint) &&
+                Objects.equal(isAsBoundaryRouter, that.isAsBoundaryRouter) &&
+                Objects.equal(isAreaBorderRouter, that.isAreaBorderRouter) &&
+                Objects.equal(noLink, that.noLink) &&
+                Objects.equal(routerLinks, that.routerLinks);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(isVirtualEndPoint, isAsBoundaryRouter, isAreaBorderRouter,
+                                noLink, routerLinks);
+    }
+}
\ No newline at end of file