[ONOS-3845] BGP FlowSpec capability handling.

Change-Id: I5368dea5a0d959399550737ccf6eb6742a7510b9
diff --git a/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpCfg.java b/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpCfg.java
index 6f64d2b..70a5c9e 100755
--- a/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpCfg.java
+++ b/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpCfg.java
@@ -61,7 +61,7 @@
     /**
      * Get the status of the link state support for this BGP speaker.
      *
-     * @return  true if the link state is supported else false
+     * @return true if the link state is supported else false
      */
     boolean getLsCapability();
 
@@ -73,6 +73,20 @@
     void setLsCapability(boolean lscapability);
 
     /**
+     * Get the status of the flow specification support for this BGP speaker.
+     *
+     * @return true if the flow specification is supported otherwise false
+     */
+    boolean flowSpecCapability();
+
+    /**
+     * Set the flow specification support to this BGP speaker.
+     *
+     * @param flowSpecCapability BGP flow specification capability support
+     */
+    void setFlowSpecCapability(boolean flowSpecCapability);
+
+    /**
      * Get the status of the 32 bit AS support for this BGP speaker.
      *
      * @return true if the 32 bit AS number is supported else false
@@ -82,7 +96,7 @@
     /**
      * Set the 32 bit AS support capability to this BGP speaker.
      *
-     * @param largeAs  true value if the 32 bit AS is supported else false
+     * @param largeAs true value if the 32 bit AS is supported else false
      */
     void setLargeASCapability(boolean largeAs);
 
@@ -166,7 +180,7 @@
     /**
      * Set the Router ID of this BGP speaker.
      *
-     * @param routerid  IP address in string format
+     * @param routerid IP address in string format
      */
     void setRouterId(String routerid);
 
@@ -174,7 +188,7 @@
      * Add the BGP peer IP address and the AS number to which it belongs.
      *
      * @param routerid IP address in string format
-     * @param remoteAs  AS number to which it belongs
+     * @param remoteAs AS number to which it belongs
      *
      * @return true if added successfully else false
      */
@@ -197,7 +211,7 @@
      * @param remoteAs AS number to which it belongs
      * @param holdTime keep alive time for the connection
      *
-     * @return  true if added successfully else false
+     * @return true if added successfully else false
      */
     boolean addPeer(String routerid, int remoteAs, short holdTime);
 
@@ -215,14 +229,14 @@
      *
      * @param routerid router IP address
      *
-     * @return  true of the configuration is found and able to connect else false
+     * @return true of the configuration is found and able to connect else false
      */
     boolean connectPeer(String routerid);
 
     /**
      * Disconnect this BGP peer with this IP address.
      *
-     * @param routerid  router IP address in string format
+     * @param routerid router IP address in string format
      *
      * @return true if the configuration is found and able to disconnect else false
      */
@@ -247,9 +261,9 @@
     /**
      * Check if this BGP peer is configured.
      *
-     * @param routerid  router IP address in string format
+     * @param routerid router IP address in string format
      *
-     * @return  true if configured exists else false
+     * @return true if configured exists else false
      */
     boolean isPeerConfigured(String routerid);
 
@@ -272,7 +286,7 @@
     /**
      * Set the current connection state information.
      *
-     * @param routerid  router IP address in string format
+     * @param routerid router IP address in string format
      * @param state state information
      */
     void setPeerConnState(String routerid, BgpPeerCfg.State state);
@@ -280,9 +294,9 @@
     /**
      * Check if the peer can be connected or not.
      *
-     * @param routerid  router IP address in string format
+     * @param routerid router IP address in string format
      *
-     * @return  true if the peer can be connected else false
+     * @return true if the peer can be connected else false
      */
     boolean isPeerConnectable(String routerid);
 
diff --git a/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpSessionInfo.java b/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpSessionInfo.java
index a21a23d..eedde14 100755
--- a/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpSessionInfo.java
+++ b/protocols/bgp/api/src/main/java/org/onosproject/bgp/controller/BgpSessionInfo.java
@@ -13,7 +13,10 @@
 
 package org.onosproject.bgp.controller;
 
+import java.util.List;
+
 import org.onosproject.bgpio.protocol.BgpVersion;
+import org.onosproject.bgpio.types.BgpValueType;
 
 /**
  * Abstraction of an BGP session info. Maintian session parameters obtained during session creation.
@@ -67,4 +70,11 @@
      * @return bgp identifier.
      */
     int remoteBgpIdentifier();
+
+    /**
+     * Gets the BGP capabilities for this BGP peer.
+     *
+     * @return BGP peer capabilities.
+     */
+    List<BgpValueType> remoteBgpCapability();
 }
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 ff660a7..4c8c7df 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
@@ -34,6 +34,11 @@
     public static final short AFI_VALUE = 16388;
     public static final byte VPN_SAFI_VALUE = (byte) 0x80;
     public static final byte SAFI_VALUE = 71;
+
+    public static final short AFI_FLOWSPEC_VALUE = 1;
+    public static final byte SAFI_FLOWSPEC_VALUE = (byte) 133;
+    public static final byte VPN_SAFI_FLOWSPEC_VALUE = (byte) 134;
+
     public static final int EXTRA_TRAFFIC = 0x01;
     public static final int UNPROTECTED = 0x02;
     public static final int SHARED = 0x04;
@@ -41,4 +46,23 @@
     public static final int DEDICATED_ONE_PLUS_ONE = 0x10;
     public static final int ENHANCED = 0x20;
     public static final int RESERVED = 0x40;
+
+    public static final byte BGP_FLOWSPEC_DST_PREFIX = 0x01;
+    public static final byte BGP_FLOWSPEC_SRC_PREFIX = 0x02;
+    public static final byte BGP_FLOWSPEC_IP_PROTO = 0x03;
+    public static final byte BGP_FLOWSPEC_PORT = 0x04;
+    public static final byte BGP_FLOWSPEC_DST_PORT = 0x05;
+    public static final byte BGP_FLOWSPEC_SRC_PORT = 0x06;
+    public static final byte BGP_FLOWSPEC_ICMP_TP = 0x07;
+    public static final byte BGP_FLOWSPEC_ICMP_CD = 0x08;
+    public static final byte BGP_FLOWSPEC_TCP_FLAGS = 0x09;
+    public static final byte BGP_FLOWSPEC_PCK_LEN = 0x10;
+    public static final byte BGP_FLOWSPEC_DSCP = 0x11;
+    public static final byte BGP_FLOWSPEC_FRAGMENT = 0x12;
+
+    public static final short BGP_FLOWSPEC_ACTION_TRAFFIC_RATE = (short) 0x8006;
+    public static final short BGP_FLOWSPEC_ACTION_TRAFFIC_ACTION = (short) 0x8007;
+    public static final short BGP_FLOWSPEC_ACTION_TRAFFIC_REDIRECT = (short) 0x8008;
+    public static final short BGP_FLOWSPEC_ACTION_TRAFFIC_MARKING = (short) 0x8009;
+
 }
\ No newline at end of file
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 8ffbaa7..cbdb553 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.util.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -108,6 +109,7 @@
     private SocketAddress address;
     private String peerAddr;
     private BgpCfg bgpconfig;
+    List<BgpValueType> remoteBgpCapability;
 
     /**
      * Create a new unconnected BGPChannelHandler.
@@ -171,6 +173,7 @@
                             return;
                         }
                         log.debug("Sending handshake OPEN message");
+                        h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
 
                         /*
                          * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
@@ -225,6 +228,7 @@
                             return;
                         }
                         log.debug("Sending handshake OPEN message");
+                        h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
 
                         /*
                          * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
@@ -277,7 +281,8 @@
                     h.negotiatedHoldTime = (h.peerHoldTime < h.bgpconfig.getHoldTime()) ? h.peerHoldTime
                                                                                         : h.bgpconfig.getHoldTime();
                     h.sessionInfo = new BgpSessionInfoImpl(h.thisbgpId, h.bgpVersion, h.peerAsNum, h.peerHoldTime,
-                                                           h.peerIdentifier, h.negotiatedHoldTime, h.isIbgpSession);
+                                                           h.peerIdentifier, h.negotiatedHoldTime, h.isIbgpSession,
+                                                           h.remoteBgpCapability);
 
                     h.bgpPeer = h.peerManager.getBgpPeerInstance(h.bgpController, h.sessionInfo, h.bgpPacketStats);
                     // set the status of bgp as connected
@@ -760,7 +765,6 @@
     private boolean capabilityValidation(BgpChannelHandler h, BgpOpenMsg openmsg) throws BgpParseException {
         log.debug("capabilityValidation");
 
-        boolean isMultiProtocolcapabilityExists = false;
         boolean isFourOctetCapabilityExits = false;
         int capAsNum = 0;
 
@@ -771,11 +775,27 @@
         BgpValueType tempTlv;
         boolean isLargeAsCapabilityCfg = h.bgpconfig.getLargeASCapability();
         boolean isLsCapabilityCfg = h.bgpconfig.getLsCapability();
+        boolean isFlowSpecCapabilityCfg = h.bgpconfig.flowSpecCapability();
+        MultiProtocolExtnCapabilityTlv tempCapability;
+        boolean isMultiProtocolLsCapability = false;
+        boolean isMultiProtocolFlowSpecCapability = false;
+        boolean isMultiProtocolVpnFlowSpecCapability = false;
 
         while (listIterator.hasNext()) {
             BgpValueType tlv = listIterator.next();
             if (tlv.getType() == MULTI_PROTOCOL_EXTN_CAPA_TYPE) {
-                isMultiProtocolcapabilityExists = true;
+                tempCapability = (MultiProtocolExtnCapabilityTlv) tlv;
+                if (Constants.SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
+                    isMultiProtocolFlowSpecCapability = true;
+                }
+
+                if (Constants.VPN_SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
+                    isMultiProtocolVpnFlowSpecCapability = true;
+                }
+
+                if (SAFI == tempCapability.getSafi()) {
+                    isMultiProtocolLsCapability = true;
+                }
             }
             if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
                 isFourOctetCapabilityExits = true;
@@ -796,12 +816,26 @@
         }
 
         if ((isLsCapabilityCfg)) {
-            if (!isMultiProtocolcapabilityExists) {
+            if (!isMultiProtocolLsCapability) {
                 tempTlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
                 unSupportedCapabilityTlv.add(tempTlv);
             }
         }
 
+        if ((isFlowSpecCapabilityCfg)) {
+            if (!isMultiProtocolFlowSpecCapability) {
+                tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
+                                                             RES, Constants.SAFI_FLOWSPEC_VALUE);
+                unSupportedCapabilityTlv.add(tempTlv);
+            }
+
+            if (!isMultiProtocolVpnFlowSpecCapability) {
+                tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
+                                                             RES, Constants.VPN_SAFI_FLOWSPEC_VALUE);
+                unSupportedCapabilityTlv.add(tempTlv);
+            }
+        }
+
         if ((isLargeAsCapabilityCfg)) {
             if (!isFourOctetCapabilityExits) {
                 tempTlv = new FourOctetAsNumCapabilityTlv(h.bgpconfig.getAsNumber());
@@ -809,7 +843,7 @@
             }
         }
 
-        if (unSupportedCaplistIterator.hasNext()) {
+        if (unSupportedCapabilityTlv.size() == 3) {
             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 1c846eb..405241b 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
@@ -47,6 +47,7 @@
     private int localAs;
     private int maxSession;
     private boolean lsCapability;
+    private boolean flowSpecCapability;
     private short holdTime;
     private boolean largeAs = false;
     private int maxConnRetryTime;
@@ -119,6 +120,16 @@
     }
 
     @Override
+    public boolean flowSpecCapability() {
+        return this.flowSpecCapability;
+    }
+
+    @Override
+    public void setFlowSpecCapability(boolean vpnFlowSpecCapability) {
+        this.flowSpecCapability = flowSpecCapability;
+    }
+
+    @Override
     public String getRouterId() {
         if (this.routerId != null) {
             return this.routerId.toString();
diff --git a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpSessionInfoImpl.java b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpSessionInfoImpl.java
index 33623dc..81f4ad0 100755
--- a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpSessionInfoImpl.java
+++ b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpSessionInfoImpl.java
@@ -13,9 +13,12 @@
 
 package org.onosproject.bgp.controller.impl;
 
+import java.util.List;
+
 import org.onosproject.bgp.controller.BgpId;
 import org.onosproject.bgp.controller.BgpSessionInfo;
 import org.onosproject.bgpio.protocol.BgpVersion;
+import org.onosproject.bgpio.types.BgpValueType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,6 +35,7 @@
     private int remoteBgpIdentifier;
     private short negotiatedholdTime;
     private boolean isIbgpSession;
+    List<BgpValueType> remoteBgpCapability;
 
     /**
      * Initialize session info.
@@ -43,10 +47,11 @@
      *@param remoteBgpIdentifier remote peer identifier
      *@param negotiatedholdTime negotiated hold time
      *@param isIbgpSession session type ibgp/ebgp
+     *@param remoteBgpCapability remote peer capabilities
      */
     public BgpSessionInfoImpl(BgpId remoteBgpId, BgpVersion remoteBgpVersion, long remoteBgpASNum,
                               short remoteBgpholdTime, int remoteBgpIdentifier, short negotiatedholdTime,
-                              boolean isIbgpSession) {
+                              boolean isIbgpSession, List<BgpValueType> remoteBgpCapability) {
         this.remoteBgpId = remoteBgpId;
         this.remoteBgpVersion = remoteBgpVersion;
         this.remoteBgpASNum = remoteBgpASNum;
@@ -54,6 +59,12 @@
         this.remoteBgpIdentifier = remoteBgpIdentifier;
         this.negotiatedholdTime = negotiatedholdTime;
         this.isIbgpSession = isIbgpSession;
+        this.remoteBgpCapability = remoteBgpCapability;
+    }
+
+    @Override
+    public List<BgpValueType> remoteBgpCapability() {
+        return remoteBgpCapability;
     }
 
     @Override