[ONOS-4242] Capability support for wide community

Change-Id: Ib29a4aeddde863d3ecf281cea8d31c6a945834bd
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 7f4f59a..40c63d4 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
@@ -55,9 +55,9 @@
 import java.net.UnknownHostException;
 import java.nio.channels.ClosedChannelException;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.RejectedExecutionException;
 
 /**
@@ -85,6 +85,7 @@
     static final short AFI = 16388;
     static final byte RES = 0;
     static final byte SAFI = 71;
+    static final byte MAX_UNSUPPORTED_CAPABILITY = 5;
 
     // State needs to be volatile because the HandshakeTimeoutHandler
     // needs to check if the handshake is complete
@@ -520,7 +521,7 @@
             byte errorSubCode = errMsg.getErrorSubCode();
             ChannelBuffer tempCb = errMsg.getData();
             if (tempCb != null) {
-                int dataLength = tempCb.capacity();
+                int dataLength = tempCb.readableBytes();
                 data = new byte[dataLength];
                 tempCb.readBytes(data, 0, dataLength);
             }
@@ -685,7 +686,8 @@
                 .setLsCapabilityTlv(bgpconfig.getLsCapability())
                 .setLargeAsCapabilityTlv(bgpconfig.getLargeASCapability())
                 .setFlowSpecCapabilityTlv(flowSpecStatus)
-                .setVpnFlowSpecCapabilityTlv(vpnFlowSpecStatus).build();
+                .setVpnFlowSpecCapabilityTlv(vpnFlowSpecStatus)
+                .setFlowSpecRpdCapabilityTlv(bgpconfig.flowSpecRpdCapability()).build();
         log.debug("Sending open message to {}", channel.getRemoteAddress());
         channel.write(Collections.singletonList(msg));
 
@@ -786,20 +788,28 @@
 
         List<BgpValueType> capabilityTlv = openmsg.getCapabilityTlv();
         ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
-        List<BgpValueType> unSupportedCapabilityTlv = new LinkedList<>();
+        List<BgpValueType> unSupportedCapabilityTlv = new CopyOnWriteArrayList<BgpValueType>();
         ListIterator<BgpValueType> unSupportedCaplistIterator = unSupportedCapabilityTlv.listIterator();
         BgpValueType tempTlv;
         boolean isLargeAsCapabilityCfg = h.bgpconfig.getLargeASCapability();
+        boolean isFlowSpecRpdCapabilityCfg = h.bgpconfig.flowSpecRpdCapability();
         boolean isLsCapabilityCfg = h.bgpconfig.getLsCapability();
-        boolean isFlowSpecCapabilityCfg = false;
+        boolean isFlowSpecIpv4CapabilityCfg = false;
+        boolean isFlowSpecVpnv4CapabilityCfg = false;
         MultiProtocolExtnCapabilityTlv tempCapability;
         boolean isMultiProtocolLsCapability = false;
+        boolean isMultiProtocolFlowSpecRpdCapability = false;
         boolean isMultiProtocolFlowSpecCapability = false;
         boolean isMultiProtocolVpnFlowSpecCapability = false;
         BgpCfg.FlowSpec flowSpec = h.bgpconfig.flowSpecCapability();
 
-        if (flowSpec != BgpCfg.FlowSpec.NONE) {
-            isFlowSpecCapabilityCfg = true;
+        if (flowSpec == BgpCfg.FlowSpec.IPV4) {
+            isFlowSpecIpv4CapabilityCfg = true;
+        } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
+            isFlowSpecVpnv4CapabilityCfg = true;
+        } else if (flowSpec == BgpCfg.FlowSpec.IPV4_VPNV4) {
+            isFlowSpecIpv4CapabilityCfg = true;
+            isFlowSpecVpnv4CapabilityCfg = true;
         }
 
         while (listIterator.hasNext()) {
@@ -817,6 +827,10 @@
                 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;
@@ -843,13 +857,15 @@
             }
         }
 
-        if ((isFlowSpecCapabilityCfg)) {
+        if (isFlowSpecIpv4CapabilityCfg) {
             if (!isMultiProtocolFlowSpecCapability) {
                 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
                                                              RES, Constants.SAFI_FLOWSPEC_VALUE);
                 unSupportedCapabilityTlv.add(tempTlv);
             }
+        }
 
+        if (isFlowSpecVpnv4CapabilityCfg) {
             if (!isMultiProtocolVpnFlowSpecCapability) {
                 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
                                                              RES, Constants.VPN_SAFI_FLOWSPEC_VALUE);
@@ -864,7 +880,16 @@
             }
         }
 
-        if (unSupportedCapabilityTlv.size() == 3) {
+        if ((isFlowSpecRpdCapabilityCfg)) {
+            if (!isMultiProtocolFlowSpecRpdCapability) {
+                tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_RPD_VALUE,
+                                                             RES, Constants.SAFI_FLOWSPEC_RPD_VALUE,
+                                                             Constants.RPD_CAPABILITY_SEND_VALUE);
+                unSupportedCapabilityTlv.add(tempTlv);
+            }
+        }
+
+        if (unSupportedCapabilityTlv.size() == MAX_UNSUPPORTED_CAPABILITY) {
             ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
             while (unSupportedCaplistIterator.hasNext()) {
                 BgpValueType tlv = unSupportedCaplistIterator.next();
diff --git a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpConfig.java b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpConfig.java
index 6073559..bbeea48 100755
--- a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpConfig.java
+++ b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpConfig.java
@@ -57,6 +57,7 @@
     private BgpConnectPeer connectPeer;
     private BgpPeerManagerImpl peerManager;
     private BgpController bgpController;
+    private boolean rpdCapability;
 
     /*
      * Constructor to initialize the values.
@@ -129,6 +130,16 @@
     }
 
     @Override
+    public boolean flowSpecRpdCapability() {
+        return this.rpdCapability;
+    }
+
+    @Override
+    public void setFlowSpecRpdCapability(boolean rpdCapability) {
+        this.rpdCapability = rpdCapability;
+    }
+
+    @Override
     public String getRouterId() {
         if (this.routerId != null) {
             return this.routerId.toString();
diff --git a/protocols/bgp/ctl/src/test/java/org/onosproject/bgp/BgpControllerImplTest.java b/protocols/bgp/ctl/src/test/java/org/onosproject/bgp/BgpControllerImplTest.java
index 72d5607..4795d35 100644
--- a/protocols/bgp/ctl/src/test/java/org/onosproject/bgp/BgpControllerImplTest.java
+++ b/protocols/bgp/ctl/src/test/java/org/onosproject/bgp/BgpControllerImplTest.java
@@ -72,6 +72,7 @@
 import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
 import org.onosproject.bgpio.types.IsIsPseudonode;
 import org.onosproject.bgpio.types.RouteDistinguisher;
+import org.onosproject.bgpio.util.Constants;
 
 /**
  * Test case for BGPControllerImpl.
@@ -299,6 +300,29 @@
         assertThat(result, is(true));
     }
 
+    @Test
+    public void bgpOpenMessageTest8() throws InterruptedException {
+        // Open message with route policy distribution capability
+        short afi = Constants.AFI_FLOWSPEC_RPD_VALUE;
+        byte res = 0;
+        byte safi = Constants.SAFI_FLOWSPEC_RPD_VALUE;
+        peer1.peerChannelHandler.asNumber = 200;
+        peer1.peerChannelHandler.version = 4;
+        peer1.peerChannelHandler.holdTime = 120;
+
+        bgpControllerImpl.getConfig().setFlowSpecRpdCapability(true);
+        BgpValueType tempTlv1 = new MultiProtocolExtnCapabilityTlv(afi, res, safi);
+        peer1.peerChannelHandler.capabilityTlv.add(tempTlv1);
+
+        peer1.connect(connectToSocket);
+
+        boolean result;
+        result = peer1.peerFrameDecoder.receivedOpenMessageLatch.await(
+            MESSAGE_TIMEOUT_MS,
+            TimeUnit.MILLISECONDS);
+        assertThat(result, is(true));
+    }
+
     /**
      * Peer1 has Node NLRI (MpReach).
      */