[ONOS-4242] Capability support for wide community

Change-Id: Ib29a4aeddde863d3ecf281cea8d31c6a945834bd
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpOpenMsg.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpOpenMsg.java
index 99c5c82..f762852 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpOpenMsg.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpOpenMsg.java
@@ -139,6 +139,15 @@
          */
         Builder setVpnFlowSpecCapabilityTlv(boolean isVpnFlowSpecCapabilitySet);
 
+        /**
+         * Sets flow specification route distribution policy capability and return its builder.
+         *
+         * @param isFlowSpecRpdCapabilitySet boolean value to know whether flow spec RPD capability is set or not
+         *
+         * @return builder by setting capabilities
+         */
+        Builder setFlowSpecRpdCapabilityTlv(boolean isFlowSpecRpdCapabilitySet);
+
         @Override
         Builder setHeader(BgpHeader bgpMsgHeader);
     }
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 dfaf665..b55b178 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
@@ -258,16 +258,24 @@
                 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();
-                tlv = new MultiProtocolExtnCapabilityTlv(afi, res, safi);
+                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);
+                }
                 break;
             default:
                 log.debug("Warning: Unsupported TLV: " + type);
@@ -297,6 +305,7 @@
         private boolean isLsCapabilityTlvSet = false;
         private boolean isFlowSpecCapabilityTlvSet = false;
         private boolean isVpnFlowSpecCapabilityTlvSet = false;
+        private boolean isFlowSpecRpdCapabilityTlvSet = false;
 
         LinkedList<BgpValueType> capabilityTlv = new LinkedList<>();
 
@@ -347,6 +356,15 @@
                 this.capabilityTlv.add(tlv);
             }
 
+            if (this.isFlowSpecRpdCapabilityTlvSet) {
+                BgpValueType tlv;
+                tlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_RPD_VALUE,
+                                                         RES, Constants.SAFI_FLOWSPEC_RPD_VALUE,
+                                                         Constants.RPD_CAPABILITY_SEND_VALUE);
+                this.capabilityTlv.add(tlv);
+            }
+
+
             return new BgpOpenMsgVer4(bgpMsgHeader, PACKET_VERSION, this.asNumber, holdTime, this.bgpId,
                        this.capabilityTlv);
         }
@@ -407,6 +425,12 @@
             this.isVpnFlowSpecCapabilityTlvSet = isVpnFlowSpecCapabilitySet;
             return this;
         }
+
+        @Override
+        public Builder setFlowSpecRpdCapabilityTlv(boolean isFlowSpecRpdCapabilityTlvSet) {
+            this.isFlowSpecRpdCapabilityTlvSet = isFlowSpecRpdCapabilityTlvSet;
+            return this;
+        }
     }
 
     @Override
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 1231214..832cd59 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,6 +19,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.onosproject.bgpio.util.Constants;
 
 import java.util.Objects;
 
@@ -45,6 +46,7 @@
     private final short afi;
     private final byte res;
     private final byte safi;
+    private final byte rpdSendReceive;
 
     /**
      * Constructor to initialize variables.
@@ -56,6 +58,24 @@
         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;
     }
 
     /**
@@ -120,9 +140,16 @@
 
     @Override
     public int write(ChannelBuffer cb) {
+        boolean isFsRpd = false;
         int iLenStartIndex = cb.writerIndex();
         cb.writeByte(TYPE);
-        cb.writeByte(LENGTH);
+
+        if ((afi == Constants.AFI_FLOWSPEC_RPD_VALUE) && (safi == Constants.SAFI_FLOWSPEC_RPD_VALUE)) {
+            cb.writeByte(LENGTH + 1);
+            isFsRpd = true;
+        } else {
+            cb.writeByte(LENGTH);
+        }
 
         // write afi
         cb.writeShort(afi);
@@ -133,6 +160,11 @@
         // write safi
         cb.writeByte(safi);
 
+        if (isFsRpd) {
+            // write Send/Receive (1 octet)
+            cb.writeByte(rpdSendReceive);
+        }
+
         return cb.writerIndex() - iLenStartIndex;
     }
 
@@ -145,6 +177,10 @@
         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/util/Constants.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/util/Constants.java
index 3e7e4ad..0bb5e7b 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
@@ -40,6 +40,16 @@
     public static final byte SAFI_FLOWSPEC_VALUE = (byte) 133;
     public static final byte VPN_SAFI_FLOWSPEC_VALUE = (byte) 134;
 
+    /* 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 RPD_CAPABILITY_RECEIVE_VALUE = 0;
+    public static final byte RPD_CAPABILITY_SEND_VALUE = 1;
+    public static final byte RPD_CAPABILITY_SEND_RECEIVE_VALUE = 2;
+
     public static final int EXTRA_TRAFFIC = 0x01;
     public static final int UNPROTECTED = 0x02;
     public static final int SHARED = 0x04;