[Emu] [ONOS-2601] Implement BGP Update protocol message and parse all basic path attributes.

Change-Id: I5d4abb58e3484f56e629ab97cb0995ab03a5b235
diff --git a/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java b/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java
new file mode 100644
index 0000000..08fea4c
--- /dev/null
+++ b/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2015 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.bgpio.protocol.ver4;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.As4Path;
+import org.onosproject.bgpio.types.AsPath;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.types.LocalPref;
+import org.onosproject.bgpio.types.Med;
+import org.onosproject.bgpio.types.NextHop;
+import org.onosproject.bgpio.types.Origin;
+import org.onosproject.bgpio.util.UnSupportedAttribute;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides Implementation of BGP Path Attribute.
+ */
+public class BgpPathAttributes {
+
+    /* Path attribute:
+           <attribute type, attribute length, attribute value>
+
+           0                   1
+           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           |  Attr. Flags  |Attr. Type Code|
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           REFERENCE : RFC 4271
+    */
+    protected static final Logger log = LoggerFactory.getLogger(BgpPathAttributes.class);
+
+    public static final int LINK_STATE_ATTRIBUTE_TYPE = 50;
+    public static final int MPREACHNLRI_TYPE = 14;
+    public static final int MPUNREACHNLRI_TYPE = 15;
+
+    private final List<BGPValueType> pathAttribute;
+
+    /**
+     * Initialize parameter.
+     */
+    public BgpPathAttributes() {
+        this.pathAttribute = null;
+    }
+
+    /**
+     * Constructor to initialize parameters for BGP path attributes.
+     *
+     * @param pathAttribute list of path attributes
+     */
+    public BgpPathAttributes(List<BGPValueType> pathAttribute) {
+        this.pathAttribute = pathAttribute;
+    }
+
+    /**
+     * Returns list of path attributes.
+     *
+     * @return list of path attributes
+     */
+    public List<BGPValueType> pathAttributes() {
+        return this.pathAttribute;
+    }
+
+    /**
+     * Reads from channelBuffer and parses BGP path attributes.
+     *
+     * @param cb channelBuffer
+     * @return object of BgpPathAttributes
+     * @throws BGPParseException while parsing BGP path attributes
+     */
+    public static BgpPathAttributes read(ChannelBuffer cb)
+            throws BGPParseException {
+
+        BGPValueType pathAttribute = null;
+        List<BGPValueType> pathAttributeList = new LinkedList<>();
+        boolean isOrigin = false;
+        boolean isAsPath = false;
+        boolean isNextHop = false;
+        boolean isMpReach = false;
+        boolean isMpUnReach = false;
+        while (cb.readableBytes() > 0) {
+            cb.markReaderIndex();
+            byte flags = cb.readByte();
+            byte typeCode = cb.readByte();
+            cb.resetReaderIndex();
+            switch (typeCode) {
+            case Origin.ORIGIN_TYPE:
+                pathAttribute = Origin.read(cb);
+                isOrigin = ((Origin) pathAttribute).isOriginSet();
+                break;
+            case AsPath.ASPATH_TYPE:
+                pathAttribute = AsPath.read(cb);
+                isAsPath = ((AsPath) pathAttribute).isaspathSet();
+                break;
+            case As4Path.AS4PATH_TYPE:
+                pathAttribute = As4Path.read(cb);
+                break;
+            case NextHop.NEXTHOP_TYPE:
+                pathAttribute = NextHop.read(cb);
+                isNextHop = ((NextHop) pathAttribute).isNextHopSet();
+                break;
+            case Med.MED_TYPE:
+                pathAttribute = Med.read(cb);
+                break;
+            case LocalPref.LOCAL_PREF_TYPE:
+                pathAttribute = LocalPref.read(cb);
+                break;
+            case MPREACHNLRI_TYPE:
+                //TODO: To be merged later
+                break;
+            case MPUNREACHNLRI_TYPE:
+                //TODO: To be merged later
+                break;
+            case LINK_STATE_ATTRIBUTE_TYPE:
+                //TODO: To be merged later
+                break;
+            default:
+                //skip bytes for unsupported attribute types
+                UnSupportedAttribute.read(cb);
+            }
+            pathAttributeList.add(pathAttribute);
+        }
+
+        checkMandatoryAttr(isOrigin, isAsPath, isNextHop, isMpReach, isMpUnReach);
+        //TODO:if mp_reach or mp_unreach not present ignore the packet
+        return new BgpPathAttributes(pathAttributeList);
+    }
+
+    /**
+     * Checks mandatory attributes are presents, if not present throws exception.
+     *
+     * @param isOrigin say whether origin attribute is present
+     * @param isAsPath say whether aspath attribute is present
+     * @param isNextHop say whether nexthop attribute is present
+     * @param isMpReach say whether mpreach attribute is present
+     * @param isMpUnReach say whether mpunreach attribute is present
+     * @throws BGPParseException if mandatory path attribute is not present
+     */
+    public static void checkMandatoryAttr(boolean isOrigin, boolean isAsPath,
+            boolean isNextHop, boolean isMpReach, boolean isMpUnReach)
+            throws BGPParseException {
+        if (!isOrigin) {
+            log.debug("Mandatory Attributes not Present");
+            Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                    BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE,
+                    Origin.ORIGIN_TYPE);
+        }
+        if (!isAsPath) {
+            log.debug("Mandatory Attributes not Present");
+            Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                    BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE,
+                    AsPath.ASPATH_TYPE);
+        }
+        if (!isMpUnReach && !isMpReach && !isNextHop) {
+            log.debug("Mandatory Attributes not Present");
+            Validation.validateType(BGPErrorType.UPDATE_MESSAGE_ERROR,
+                    BGPErrorType.MISSING_WELLKNOWN_ATTRIBUTE,
+                    NextHop.NEXTHOP_TYPE);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("pathAttribute", pathAttribute)
+                .toString();
+    }
+}