[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;
diff --git a/protocols/bgp/bgpio/src/test/java/org/onosproject/bgpio/protocol/BgpOpenMsgTest.java b/protocols/bgp/bgpio/src/test/java/org/onosproject/bgpio/protocol/BgpOpenMsgTest.java
index 2d01fe8..7cfe080 100755
--- a/protocols/bgp/bgpio/src/test/java/org/onosproject/bgpio/protocol/BgpOpenMsgTest.java
+++ b/protocols/bgp/bgpio/src/test/java/org/onosproject/bgpio/protocol/BgpOpenMsgTest.java
@@ -315,12 +315,13 @@
 
         // OPEN Message with capabilities.
         byte[] openMsg = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-                                     (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-                                     (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x38, 0x01, 0x04, 0x00,
-                                     0x64, 0x00, (byte) 0xb4, (byte) 0xc0, (byte) 0xa8, 0x07, 0x35, 0x1b, 0x02, 0x19,
-                                     0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x01, 0x04, 0x40, 0x04, 0x00, 0x47, 0x01,
-                                     0x04, 0x00, 0x01, 0x00, (byte) 0x85, 0x01, 0x05, 0x00, 0x01, 0x00, (byte) 0xc8,
-                                     0x00 }; // Four Octet AS Number-CAPABILITY-TLV
+                                      (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                                      (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                                      0x00, 0x3d, 0x01, 0x04, 0x00, (byte) 0xc8, 0x00, (byte) 0xb4, (byte) 0xc0,
+                                      (byte) 0xa8, 0x07, 0x35, 0x20, 0x02, 0x1e, 0x01,
+                                     0x04, 00, 0x01, 0x00, 0x01, 0x41, 0x04, 0x00, 0x00, 0x00, (byte) 0xc8, 0x01,
+                                     0x04, 0x40, 0x04, 0x00, 0x47, 0x01, 0x04, 0x00, 0x01, 0x00, (byte) 0x85,
+                                     (byte) 0x81, 0x04, 0x00, 0x01, (byte) 0x85, 0x01 }; //RPD capability
 
         byte[] testOpenMsg;
         ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
@@ -352,12 +353,13 @@
 
         // OPEN Message with invalid message type.
         byte[] openMsg = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-                                      (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-                                      (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x38, 0x01, 0x04, 0x00,
-                                      0x64, 0x00, (byte) 0xb4, (byte) 0xc0, (byte) 0xa8, 0x07, 0x35, 0x1b, 0x02, 0x19,
-                                      0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x01, 0x04, 0x40, 0x04, 0x00, 0x47, 0x01,
-                                      0x04, 0x00, 0x01, 0x00, (byte) 0x85, 0x01, 0x04, 0x00, 0x01, 0x00, (byte) 0xc8,
-                                      0x00 };
+                                     (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                                     (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+                                     0x00, 0x3d, 0x01, 0x04, 0x00, (byte) 0xc8, 0x00, (byte) 0xb4, (byte) 0xc0,
+                                     (byte) 0xa8, 0x07, 0x35, 0x20, 0x02, 0x1e, 0x01, 0x04, 00, 0x01, 0x00, 0x01, 0x41,
+                                     0x04, 0x00, 0x00, 0x00, (byte) 0xc8, 0x01, 0x04, 0x40, 0x04, 0x00,
+                                     0x47, 0x01, 0x04, 0x00, 0x01, 0x00, (byte) 0x85,
+                                    (byte) 0x81, 0x05, 0x00, 0x01, (byte) 0x85, 0x01 }; //RPD capability
 
         ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
         buffer.writeBytes(openMsg);
diff --git a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java
index 40c63d4..7a05f31 100755
--- a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java
+++ b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpChannelHandler.java
@@ -44,6 +44,7 @@
 import org.onosproject.bgpio.types.BgpValueType;
 import org.onosproject.bgpio.types.FourOctetAsNumCapabilityTlv;
 import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
+import org.onosproject.bgpio.types.RpdCapabilityTlv;
 import org.onosproject.bgpio.util.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -784,7 +785,9 @@
         log.debug("capabilityValidation");
 
         boolean isFourOctetCapabilityExits = false;
+        boolean isRpdCapabilityExits = false;
         int capAsNum = 0;
+        byte sendReceive = 0;
 
         List<BgpValueType> capabilityTlv = openmsg.getCapabilityTlv();
         ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
@@ -798,7 +801,6 @@
         boolean isFlowSpecVpnv4CapabilityCfg = false;
         MultiProtocolExtnCapabilityTlv tempCapability;
         boolean isMultiProtocolLsCapability = false;
-        boolean isMultiProtocolFlowSpecRpdCapability = false;
         boolean isMultiProtocolFlowSpecCapability = false;
         boolean isMultiProtocolVpnFlowSpecCapability = false;
         BgpCfg.FlowSpec flowSpec = h.bgpconfig.flowSpecCapability();
@@ -827,15 +829,16 @@
                 if (SAFI == tempCapability.getSafi()) {
                     isMultiProtocolLsCapability = true;
                 }
-
-                if (Constants.SAFI_FLOWSPEC_RPD_VALUE == tempCapability.getSafi()) {
-                    isMultiProtocolFlowSpecRpdCapability = true;
-                }
             }
             if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
                 isFourOctetCapabilityExits = true;
                 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
             }
+
+            if (tlv.getType() == RpdCapabilityTlv.TYPE) {
+                isRpdCapabilityExits = true;
+                sendReceive = ((RpdCapabilityTlv) tlv).sendReceive();
+            }
         }
 
         if (isFourOctetCapabilityExits) {
@@ -850,6 +853,12 @@
             }
         }
 
+        if (isRpdCapabilityExits) {
+            if (sendReceive > 2) {
+                throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNSUPPORTED_CAPABILITY, null);
+            }
+        }
+
         if ((isLsCapabilityCfg)) {
             if (!isMultiProtocolLsCapability) {
                 tempTlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
@@ -881,10 +890,8 @@
         }
 
         if ((isFlowSpecRpdCapabilityCfg)) {
-            if (!isMultiProtocolFlowSpecRpdCapability) {
-                tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_RPD_VALUE,
-                                                             RES, Constants.SAFI_FLOWSPEC_RPD_VALUE,
-                                                             Constants.RPD_CAPABILITY_SEND_VALUE);
+            if (!isRpdCapabilityExits) {
+                tempTlv = new RpdCapabilityTlv(Constants.RPD_CAPABILITY_SEND_VALUE);
                 unSupportedCapabilityTlv.add(tempTlv);
             }
         }