[ONOS-3857] BGP Update message builder.

Change-Id: I02d750f662602fc51b090e6beb89d73d5eb36436
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpFactory.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpFactory.java
index 11a85ff..d4e83fa 100755
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpFactory.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpFactory.java
@@ -45,6 +45,13 @@
     BgpNotificationMsg.Builder notificationMessageBuilder();
 
     /**
+     * Gets the builder object for a update message.
+     *
+     * @return builder object for update message
+     */
+    BgpUpdateMsg.Builder updateMessageBuilder();
+
+    /**
      * Gets the BGP message reader.
      *
      * @return BGP message reader
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 94ec223..dfd4419 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
@@ -121,6 +121,24 @@
          */
         Builder setLsCapabilityTlv(boolean isLsCapabilitySet);
 
+        /**
+         * Sets flow specification capability and return its builder.
+         *
+         * @param isFlowSpecCapabilitySet boolean value to know whether flow specification capability is set or not
+         *
+         * @return builder by setting capabilities
+         */
+        Builder setFlowSpecCapabilityTlv(boolean isFlowSpecCapabilitySet);
+
+        /**
+         * Sets VPN flow specification capability and return its builder.
+         *
+         * @param isVpnFlowSpecCapabilitySet boolean value to know whether flow spec capability is set or not
+         *
+         * @return builder by setting capabilities
+         */
+        Builder setVpnFlowSpecCapabilityTlv(boolean isVpnFlowSpecCapabilitySet);
+
         @Override
         Builder setHeader(BgpHeader bgpMsgHeader);
     }
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpUpdateMsg.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpUpdateMsg.java
index d79a423..23dd7d5 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpUpdateMsg.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BgpUpdateMsg.java
@@ -18,13 +18,47 @@
 
 import java.util.List;
 
+import org.jboss.netty.buffer.ChannelBuffer;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.bgpio.protocol.ver4.BgpPathAttributes;
+import org.onosproject.bgpio.protocol.flowspec.BgpFlowSpecDetails;
+import org.onosproject.bgpio.types.BgpValueType;
+import org.onosproject.bgpio.types.BgpHeader;
 
 /**
  * Abstraction of an entity providing BGP Update Message.
  */
 public interface BgpUpdateMsg extends BgpMessage {
+
+    @Override
+    BgpVersion getVersion();
+
+    @Override
+    BgpType getType();
+
+    @Override
+    void writeTo(ChannelBuffer channelBuffer);
+
+    @Override
+    BgpHeader getHeader();
+
+    /**
+     * Builder interface with set functions to build update message.
+     */
+    interface Builder extends BgpMessage.Builder {
+        @Override
+        BgpUpdateMsg build();
+
+        Builder setBgpPathAttributes(List<BgpValueType> attributes);
+
+        Builder setNlriIdentifier(short afi, byte safi);
+
+        Builder setBgpFlowSpecComponents(BgpFlowSpecDetails flowSpecComponents);
+
+        @Override
+        Builder setHeader(BgpHeader bgpMsgHeader);
+    }
+
     /**
      * Returns path attributes in BGP Update Message.
      *
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpFactoryVer4.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpFactoryVer4.java
index c57832b..bf2ccdf 100755
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpFactoryVer4.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpFactoryVer4.java
@@ -22,6 +22,7 @@
 import org.onosproject.bgpio.protocol.BgpMessageReader;
 import org.onosproject.bgpio.protocol.BgpNotificationMsg;
 import org.onosproject.bgpio.protocol.BgpOpenMsg;
+import org.onosproject.bgpio.protocol.BgpUpdateMsg;
 import org.onosproject.bgpio.protocol.BgpVersion;
 
 /**
@@ -47,6 +48,11 @@
     }
 
     @Override
+    public BgpUpdateMsg.Builder updateMessageBuilder() {
+        return new BgpUpdateMsgVer4.Builder();
+    }
+
+    @Override
     public BgpMessageReader<BgpMessage> getReader() {
         return BgpMessageVer4.READER;
     }
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 359eec2..2cc9f7a 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
@@ -31,6 +31,7 @@
 import org.onosproject.bgpio.types.FourOctetAsNumCapabilityTlv;
 import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
 import org.onosproject.bgpio.util.Validation;
+import org.onosproject.bgpio.util.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -293,6 +294,8 @@
         private int bgpId;
         private boolean isLargeAsCapabilityTlvSet = false;
         private boolean isLsCapabilityTlvSet = false;
+        private boolean isFlowSpecCapabilityTlvSet = false;
+        private boolean isVpnFlowSpecCapabilityTlvSet = false;
 
         LinkedList<BgpValueType> capabilityTlv = new LinkedList<>();
 
@@ -322,6 +325,20 @@
                 this.capabilityTlv.add(tlv);
             }
 
+            if (this.isFlowSpecCapabilityTlvSet) {
+                BgpValueType tlv;
+                tlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
+                                                         RES, Constants.SAFI_FLOWSPEC_VALUE);
+                this.capabilityTlv.add(tlv);
+            }
+
+            if (this.isVpnFlowSpecCapabilityTlvSet) {
+                BgpValueType tlv;
+                tlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
+                                                         RES, Constants.VPN_SAFI_FLOWSPEC_VALUE);
+                this.capabilityTlv.add(tlv);
+            }
+
             return new BgpOpenMsgVer4(bgpMsgHeader, PACKET_VERSION, this.asNumber, holdTime, this.bgpId,
                        this.capabilityTlv);
         }
@@ -370,6 +387,18 @@
             this.isLsCapabilityTlvSet = isLsCapabilitySet;
             return this;
         }
+
+        @Override
+        public Builder setFlowSpecCapabilityTlv(boolean isFlowSpecCapabilitySet) {
+            this.isFlowSpecCapabilityTlvSet = isFlowSpecCapabilitySet;
+            return this;
+        }
+
+        @Override
+        public Builder setVpnFlowSpecCapabilityTlv(boolean isVpnFlowSpecCapabilitySet) {
+            this.isVpnFlowSpecCapabilityTlvSet = isVpnFlowSpecCapabilitySet;
+            return this;
+        }
     }
 
     @Override
diff --git a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpUpdateMsgVer4.java b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpUpdateMsgVer4.java
index 4d6af59..7b3264e 100644
--- a/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpUpdateMsgVer4.java
+++ b/protocols/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BgpUpdateMsgVer4.java
@@ -22,12 +22,17 @@
 import org.onlab.packet.IpPrefix;
 import org.onosproject.bgpio.exceptions.BgpParseException;
 import org.onosproject.bgpio.protocol.BgpMessageReader;
+import org.onosproject.bgpio.protocol.BgpMessageWriter;
 import org.onosproject.bgpio.protocol.BgpType;
 import org.onosproject.bgpio.protocol.BgpUpdateMsg;
+import org.onosproject.bgpio.protocol.BgpVersion;
+import org.onosproject.bgpio.protocol.flowspec.BgpFlowSpecDetails;
 import org.onosproject.bgpio.types.BgpErrorType;
 import org.onosproject.bgpio.types.BgpHeader;
+import org.onosproject.bgpio.util.Constants;
 import org.onosproject.bgpio.util.Validation;
-import org.onosproject.bgpio.protocol.BgpVersion;
+
+import org.onosproject.bgpio.types.BgpValueType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -72,16 +77,26 @@
     public static final byte PACKET_VERSION = 4;
     //Withdrawn Routes Length(2) + Total Path Attribute Length(2)
     public static final int PACKET_MINIMUM_LENGTH = 4;
+    public static final int MARKER_LENGTH = 16;
     public static final int BYTE_IN_BITS = 8;
     public static final int MIN_LEN_AFTER_WITHDRW_ROUTES = 2;
     public static final int MINIMUM_COMMON_HEADER_LENGTH = 19;
     public static final BgpType MSG_TYPE = BgpType.UPDATE;
+    public static byte[] marker = 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};
+    public static final BgpHeader DEFAULT_UPDATE_HEADER = new BgpHeader(marker,
+                                                                        (short) PACKET_MINIMUM_LENGTH, (byte) 0X02);
     public static final BgpUpdateMsgVer4.Reader READER = new Reader();
 
     private List<IpPrefix> withdrawnRoutes;
     private BgpPathAttributes bgpPathAttributes;
     private BgpHeader bgpHeader;
     private List<IpPrefix> nlri;
+    private BgpFlowSpecDetails bgpFlowSpecComponents;
+    private short afi;
+    private byte safi;
 
     /**
      * Constructor to initialize parameters for BGP Update message.
@@ -99,6 +114,15 @@
         this.nlri = nlri;
     }
 
+    public BgpUpdateMsgVer4(BgpHeader bgpHeader, short afi, byte safi, BgpPathAttributes bgpPathAttributes,
+                                    BgpFlowSpecDetails bgpFlowSpecComponents) {
+        this.bgpHeader = bgpHeader;
+        this.bgpFlowSpecComponents = bgpFlowSpecComponents;
+        this.bgpPathAttributes = bgpPathAttributes;
+        this.afi = afi;
+        this.safi = safi;
+    }
+
     /**
      * Reader reads BGP Update Message from the channel buffer.
      */
@@ -163,6 +187,82 @@
     }
 
     /**
+     * Builder class for BGP update message.
+     */
+    static class Builder implements BgpUpdateMsg.Builder {
+        BgpHeader bgpMsgHeader = null;
+        BgpFlowSpecDetails bgpFlowSpecComponents;
+        BgpPathAttributes bgpPathAttributes;
+        private short afi;
+        private byte safi;
+
+        @Override
+        public BgpUpdateMsg build() /* throws BgpParseException */ {
+            BgpHeader bgpMsgHeader = DEFAULT_UPDATE_HEADER;
+
+            return new BgpUpdateMsgVer4(bgpMsgHeader, afi, safi, bgpPathAttributes, bgpFlowSpecComponents);
+        }
+
+        @Override
+        public Builder setHeader(BgpHeader bgpMsgHeader) {
+            this.bgpMsgHeader = bgpMsgHeader;
+            return this;
+        }
+
+        @Override
+        public Builder setBgpFlowSpecComponents(BgpFlowSpecDetails bgpFlowSpecComponents) {
+            this.bgpFlowSpecComponents = bgpFlowSpecComponents;
+            return this;
+        }
+
+        @Override
+        public Builder setBgpPathAttributes(List<BgpValueType> attributes) {
+            this.bgpPathAttributes = new BgpPathAttributes(attributes);
+            return this;
+        }
+
+        @Override
+        public Builder setNlriIdentifier(short afi, byte safi) {
+            this.afi = afi;
+            this.safi = safi;
+            return this;
+        }
+    }
+
+    public static final Writer WRITER = new Writer();
+
+    /**
+     * Writer class for writing BGP update message to channel buffer.
+     */
+    public static class Writer implements BgpMessageWriter<BgpUpdateMsgVer4> {
+
+        @Override
+        public void write(ChannelBuffer cb, BgpUpdateMsgVer4 message) throws BgpParseException {
+
+            int startIndex = cb.writerIndex();
+
+            // write common header and get msg length index
+            int msgLenIndex = message.bgpHeader.write(cb);
+
+            if (msgLenIndex <= 0) {
+                throw new BgpParseException("Unable to write message header.");
+            }
+
+            if ((message.afi == Constants.AFI_FLOWSPEC_VALUE) && (message.safi == Constants.SAFI_FLOWSPEC_VALUE)) {
+                //unfeasible route length
+                cb.writeShort(0);
+            }
+
+            // TODO: write path attributes
+
+            // write UPDATE Object Length
+            int length = cb.writerIndex() - startIndex;
+            cb.setShort(msgLenIndex, (short) length);
+            message.bgpHeader.setLength((short) length);
+        }
+    }
+
+    /**
      * Parses NLRI from channel buffer.
      *
      * @param cb channelBuffer
@@ -248,8 +348,12 @@
     }
 
     @Override
-    public void writeTo(ChannelBuffer channelBuffer) throws BgpParseException {
-        //Not to be implemented as of now
+    public void writeTo(ChannelBuffer channelBuffer) {
+        try {
+            WRITER.write(channelBuffer, this);
+        } catch (BgpParseException e) {
+            log.debug("[writeTo] Error: " + e.toString());
+        }
     }
 
     @Override