[ONOS-4240] Support wide community optional path attribute

Change-Id: I667cf229b02c8bcb0d4defd953bcde1595d03802
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpOpenMsgVer4.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpOpenMsgVer4.java
index b55b178..a273b99 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpOpenMsgVer4.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpOpenMsgVer4.java
@@ -32,6 +32,7 @@
 import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
 import org.onosproject.bgpio.util.Validation;
 import org.onosproject.bgpio.util.Constants;
+import org.onosproject.bgpio.types.RpdCapabilityTlv;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -256,26 +257,36 @@
                 int as4Num = cb.readInt();
                 tlv = new FourOctetAsNumCapabilityTlv(as4Num);
                 break;
+            case RpdCapabilityTlv.TYPE:
+                log.debug("RpdCapability");
+                if (RpdCapabilityTlv.LENGTH != length) {
+                    throw new BgpParseException("Invalid length received for RpdCapability.");
+                }
+                if (length > cb.readableBytes()) {
+                    throw new BgpParseException("Four octet as num tlv length"
+                            + " is more than readableBytes.");
+                }
+                short rpdAfi = cb.readShort();
+                byte rpdAsafi = cb.readByte();
+                byte sendReceive = cb.readByte();
+                tlv = new RpdCapabilityTlv(sendReceive);
+                break;
+
             case MultiProtocolExtnCapabilityTlv.TYPE:
                 log.debug("MultiProtocolExtnCapabilityTlv");
 
+                if (MultiProtocolExtnCapabilityTlv.LENGTH != length) {
+                    throw new BgpParseException("Invalid length received for MultiProtocolExtnCapabilityTlv.");
+                }
+
                 if (length > cb.readableBytes()) {
                     throw new BgpParseException("BGP LS tlv length is more than readableBytes.");
                 }
                 short afi = cb.readShort();
                 byte res = cb.readByte();
                 byte safi = cb.readByte();
-                if ((afi == Constants.AFI_FLOWSPEC_RPD_VALUE) && (safi == Constants.SAFI_FLOWSPEC_RPD_VALUE)) {
-                    if ((MultiProtocolExtnCapabilityTlv.LENGTH + 1) != length) {
-                        throw new BgpParseException("Invalid length received for MultiProtocolExtnCapabilityTlv.");
-                    }
-                    tlv = new MultiProtocolExtnCapabilityTlv(afi, res, safi, cb.readByte());
-                } else {
-                    if (MultiProtocolExtnCapabilityTlv.LENGTH != length) {
-                        throw new BgpParseException("Invalid length received for MultiProtocolExtnCapabilityTlv.");
-                    }
-                    tlv = new MultiProtocolExtnCapabilityTlv(afi, res, safi);
-                }
+                tlv = new MultiProtocolExtnCapabilityTlv(afi, res, safi);
+
                 break;
             default:
                 log.debug("Warning: Unsupported TLV: " + type);
@@ -358,9 +369,7 @@
 
             if (this.isFlowSpecRpdCapabilityTlvSet) {
                 BgpValueType tlv;
-                tlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_RPD_VALUE,
-                                                         RES, Constants.SAFI_FLOWSPEC_RPD_VALUE,
-                                                         Constants.RPD_CAPABILITY_SEND_VALUE);
+                tlv = new RpdCapabilityTlv(Constants.RPD_CAPABILITY_SEND_VALUE);
                 this.capabilityTlv.add(tlv);
             }
 
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java
index d60adce..9f8ec82 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpPathAttributes.java
@@ -36,6 +36,7 @@
 import org.onosproject.bgpio.util.UnSupportedAttribute;
 import org.onosproject.bgpio.util.Validation;
 import org.onosproject.bgpio.util.Constants;
+import org.onosproject.bgpio.types.attr.WideCommunity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -149,6 +150,9 @@
             case EXTENDED_COMMUNITY_TYPE:
                 pathAttribute = BgpExtendedCommunity.read(cb);
                 break;
+            case WideCommunity.TYPE:
+                pathAttribute = WideCommunity.read(cb);
+                break;
             default:
                 //skip bytes for unsupported attribute types
                 UnSupportedAttribute.read(cb);
@@ -214,6 +218,10 @@
                 BgpExtendedCommunity extendedCommunity = (BgpExtendedCommunity) attr;
                 extendedCommunity.write(cb);
                 break;
+            case WideCommunity.TYPE:
+                WideCommunity wideCommunity = (WideCommunity) attr;
+                wideCommunity.write(cb);
+                break;
             case MpReachNlri.MPREACHNLRI_TYPE:
                 MpReachNlri mpReach = (MpReachNlri) attr;
                 mpReach.write(cb);
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/MultiProtocolExtnCapabilityTlv.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/MultiProtocolExtnCapabilityTlv.java
index 832cd59..1231214 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/MultiProtocolExtnCapabilityTlv.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/MultiProtocolExtnCapabilityTlv.java
@@ -19,7 +19,6 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.onosproject.bgpio.util.Constants;
 
 import java.util.Objects;
 
@@ -46,7 +45,6 @@
     private final short afi;
     private final byte res;
     private final byte safi;
-    private final byte rpdSendReceive;
 
     /**
      * Constructor to initialize variables.
@@ -58,24 +56,6 @@
         this.afi = afi;
         this.res = res;
         this.safi = safi;
-        this.rpdSendReceive = Constants.RPD_CAPABILITY_SEND_VALUE;
-    }
-
-        /**
-     * Constructor to initialize variables.
-     * @param afi Address Family Identifiers
-     * @param res reserved field
-     * @param safi Subsequent Address Family Identifier
-     * @param rpdSendReceive indicates whether the sender is
-                                    (a) willing  to receive Route Policies via BGP FLowSpec from its peer (value 1).
-                                    (b) would like to send Route Policies via BGP FLowSpec to its peer (value 2).
-                                    (c) both (value 3).
-     */
-    public MultiProtocolExtnCapabilityTlv(short afi, byte res, byte safi, byte rpdSendReceive) {
-        this.afi = afi;
-        this.res = res;
-        this.safi = safi;
-        this.rpdSendReceive = rpdSendReceive;
     }
 
     /**
@@ -140,16 +120,9 @@
 
     @Override
     public int write(ChannelBuffer cb) {
-        boolean isFsRpd = false;
         int iLenStartIndex = cb.writerIndex();
         cb.writeByte(TYPE);
-
-        if ((afi == Constants.AFI_FLOWSPEC_RPD_VALUE) && (safi == Constants.SAFI_FLOWSPEC_RPD_VALUE)) {
-            cb.writeByte(LENGTH + 1);
-            isFsRpd = true;
-        } else {
-            cb.writeByte(LENGTH);
-        }
+        cb.writeByte(LENGTH);
 
         // write afi
         cb.writeShort(afi);
@@ -160,11 +133,6 @@
         // write safi
         cb.writeByte(safi);
 
-        if (isFsRpd) {
-            // write Send/Receive (1 octet)
-            cb.writeByte(rpdSendReceive);
-        }
-
         return cb.writerIndex() - iLenStartIndex;
     }
 
@@ -177,10 +145,6 @@
         short afi = cb.readShort();
         byte res = cb.readByte();
         byte safi = cb.readByte();
-
-        if ((afi == Constants.AFI_FLOWSPEC_RPD_VALUE) && (safi == Constants.SAFI_FLOWSPEC_RPD_VALUE)) {
-            return new MultiProtocolExtnCapabilityTlv(afi, res, safi, cb.readByte());
-        }
         return new MultiProtocolExtnCapabilityTlv(afi, res, safi);
     }
 
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/RpdCapabilityTlv.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/RpdCapabilityTlv.java
new file mode 100644
index 0000000..1542d33
--- /dev/null
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/RpdCapabilityTlv.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2016-present 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.types;
+
+import java.util.Objects;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.util.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides implementation of BGP route policy distribution capability tlv.
+ */
+public class RpdCapabilityTlv implements BgpValueType {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(RpdCapabilityTlv.class);
+
+    public static final byte TYPE = (byte) 129;
+    public static final byte LENGTH = 4;
+    private short afi = Constants.AFI_FLOWSPEC_RPD_VALUE;
+    private byte sAfi = Constants.SAFI_FLOWSPEC_RPD_VALUE;
+
+    private final byte sendReceive;
+
+    /**
+     * Creates instance of route policy distribution capability.
+     * @param sendReceive value indicate wherether flow route is only for receive or send or both.
+     */
+    public RpdCapabilityTlv(byte sendReceive) {
+        this.sendReceive = sendReceive;
+    }
+
+    /**
+     * Creates instance of RpdCapabilityTlv.
+     * @param sendReceive value indicate wherether flow route is only for receive or send or both.
+     * @return object of RpdCapabilityTlv
+     */
+    public static RpdCapabilityTlv of(final byte sendReceive) {
+        return new RpdCapabilityTlv(sendReceive);
+    }
+
+    /**
+     * Returns value of send receive field of route policy distribution capability.
+     * @return send receive value of route policy distribution capability
+     */
+    public byte sendReceive() {
+        return sendReceive;
+    }
+
+    @Override
+    public short getType() {
+        return TYPE;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(sendReceive);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof RpdCapabilityTlv) {
+            RpdCapabilityTlv other = (RpdCapabilityTlv) obj;
+            return Objects.equals(sendReceive, other.sendReceive);
+        }
+        return false;
+    }
+
+    @Override
+    public int write(ChannelBuffer cb) {
+        int iLenStartIndex = cb.writerIndex();
+        cb.writeByte(TYPE);
+        cb.writeByte(LENGTH);
+        cb.writeShort(afi);
+        cb.writeByte(sAfi);
+        cb.writeByte(sendReceive);
+        return cb.writerIndex() - iLenStartIndex;
+    }
+
+    /**
+     * Reads the channel buffer and returns object of RpdCapabilityTlv.
+     * @param cb type of channel buffer
+     * @return object of RpdCapabilityTlv
+     */
+    public static RpdCapabilityTlv read(ChannelBuffer cb) {
+        short afi = cb.readShort();
+        byte sAfi = cb.readByte();
+        return RpdCapabilityTlv.of(cb.readByte());
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("Type", TYPE)
+                .add("Length", LENGTH)
+                .add("afi", afi)
+                .add("safi", sAfi)
+                .add("sendReceive", sendReceive).toString();
+    }
+
+    @Override
+    public int compareTo(Object o) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+}
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Constants.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Constants.java
index 0bb5e7b..bd3edbf 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Constants.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Constants.java
@@ -43,8 +43,8 @@
     /* TODO: The Capability Code
    for this capability is to be specified by the IANA.*/
     public static final short AFI_FLOWSPEC_RPD_VALUE = 1;
-    public static final byte SAFI_FLOWSPEC_RPD_VALUE = (byte) 200;
-    public static final byte VPN_SAFI_FLOWSPEC_RDP_VALUE = (byte) 201;
+    public static final byte SAFI_FLOWSPEC_RPD_VALUE = (byte) 133;
+    public static final byte VPN_SAFI_FLOWSPEC_RDP_VALUE = (byte) 134;
 
     public static final byte RPD_CAPABILITY_RECEIVE_VALUE = 0;
     public static final byte RPD_CAPABILITY_SEND_VALUE = 1;