Adding BGP provider code to support EVPN

Change-Id: Ic5508749b64a47a70f1aabd9324e9f89e85fa39f
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 e2f83d4..036d8e6 100644
--- 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
@@ -677,6 +677,8 @@
 
         bgpId = Ip4Address.valueOf(bgpconfig.getRouterId()).toInt();
 
+        boolean evpnCapability = bgpconfig.getEvpnCapability();
+
         if (flowSpec == BgpCfg.FlowSpec.IPV4) {
             flowSpecStatus = true;
         } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
@@ -692,6 +694,7 @@
                 .setLargeAsCapabilityTlv(bgpconfig.getLargeASCapability())
                 .setFlowSpecCapabilityTlv(flowSpecStatus)
                 .setVpnFlowSpecCapabilityTlv(vpnFlowSpecStatus)
+                .setEvpnCapabilityTlv(evpnCapability)
                 .setFlowSpecRpdCapabilityTlv(bgpconfig.flowSpecRpdCapability()).build();
         log.debug("Sending open message to {}", channel.getRemoteAddress());
         channel.write(Collections.singletonList(msg));
@@ -808,6 +811,9 @@
         boolean isMultiProtocolFlowSpecCapability = false;
         boolean isMultiProtocolVpnFlowSpecCapability = false;
         BgpCfg.FlowSpec flowSpec = h.bgpconfig.flowSpecCapability();
+        boolean isEvpnCapability = false;
+        boolean isEvpnCapabilityCfg = h.bgpconfig
+                .getEvpnCapability();
 
         if (flowSpec == BgpCfg.FlowSpec.IPV4) {
             isFlowSpecIpv4CapabilityCfg = true;
@@ -826,6 +832,10 @@
                     isMultiProtocolFlowSpecCapability = true;
                 }
 
+                if (Constants.SAFI_EVPN_VALUE == tempCapability.getSafi()) {
+                    isEvpnCapability = true;
+                }
+
                 if (Constants.VPN_SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
                     isMultiProtocolVpnFlowSpecCapability = true;
                 }
@@ -878,6 +888,15 @@
             }
         }
 
+        if (isEvpnCapabilityCfg) {
+            if (!isEvpnCapability) {
+                tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_EVPN_VALUE,
+                        RES,
+                        Constants.SAFI_EVPN_VALUE);
+                unSupportedCapabilityTlv.add(tempTlv);
+            }
+        }
+
         if (isFlowSpecVpnv4CapabilityCfg) {
             if (!isMultiProtocolVpnFlowSpecCapability) {
                 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
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 f98f4bb..b15cfb8 100644
--- 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
@@ -15,13 +15,6 @@
  */
 package org.onosproject.bgp.controller.impl;
 
-import java.util.Iterator;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.List;
-import java.util.ArrayList;
-
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
 import org.onosproject.bgp.controller.BgpCfg;
@@ -34,6 +27,13 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
 /**
  * Provides BGP configuration of this BGP speaker.
  */
@@ -60,6 +60,7 @@
     private BgpPeerManagerImpl peerManager;
     private BgpController bgpController;
     private boolean rpdCapability;
+    private boolean evpnCapability;
 
     /*
      * Constructor to initialize the values.
@@ -142,6 +143,16 @@
     }
 
     @Override
+    public boolean getEvpnCapability() {
+        return this.evpnCapability;
+    }
+
+    @Override
+    public void setEvpnCapability(boolean evpnCapability) {
+        this.evpnCapability = evpnCapability;
+    }
+
+    @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/BgpControllerImpl.java b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpControllerImpl.java
index d9e0c2f..92ca7a4 100644
--- a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpControllerImpl.java
+++ b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpControllerImpl.java
@@ -28,6 +28,7 @@
 import org.onosproject.bgp.controller.BgpNodeListener;
 import org.onosproject.bgp.controller.BgpPeer;
 import org.onosproject.bgp.controller.BgpPeerManager;
+import org.onosproject.bgp.controller.BgpRouteListener;
 import org.onosproject.bgpio.exceptions.BgpParseException;
 import org.onosproject.bgpio.protocol.BgpMessage;
 import org.onosproject.bgpio.protocol.BgpUpdateMsg;
@@ -69,6 +70,7 @@
     private LinkedList<String> closedExceptionList = new LinkedList<String>();
     private Map<String, List<String>> activeSessionExceptionMap = new TreeMap<>();
     private Map<String, List<String>> closedSessionExceptionMap = new TreeMap<>();
+    protected Set<BgpRouteListener> bgpRouteListener = new CopyOnWriteArraySet<>();
 
     @Override
     public void activeSessionExceptionAdd(String peerId, String exception) {
@@ -111,6 +113,21 @@
         return closedSessionExceptionMap;
     }
 
+    @Override
+    public void addRouteListener(BgpRouteListener listener) {
+        this.bgpRouteListener.add(listener);
+    }
+
+    @Override
+    public void removeRouteListener(BgpRouteListener listener) {
+        this.bgpRouteListener.remove(listener);
+    }
+
+    @Override
+    public Set<BgpRouteListener> routeListener() {
+        return bgpRouteListener;
+    }
+
     @Activate
     public void activate() {
         this.ctrl.start();
@@ -163,46 +180,60 @@
         BgpPeer peer = getPeer(bgpId);
 
         switch (msg.getType()) {
-        case OPEN:
-            // TODO: Process Open message
-            break;
-        case KEEP_ALIVE:
-            // TODO: Process keepalive message
-            break;
-        case NOTIFICATION:
-            // TODO: Process notificatoin message
-            break;
-        case UPDATE:
-            BgpUpdateMsg updateMsg = (BgpUpdateMsg) msg;
-            List<BgpValueType> pathAttr = updateMsg.bgpPathAttributes().pathAttributes();
-            if (pathAttr == null) {
-               log.debug("llPathAttr is null, cannot process update message");
-               break;
-            }
-            Iterator<BgpValueType> listIterator = pathAttr.iterator();
-            boolean isLinkstate = false;
+            case OPEN:
+                // TODO: Process Open message
+                break;
+            case KEEP_ALIVE:
+                // TODO: Process keepalive message
+                break;
+            case NOTIFICATION:
+                // TODO: Process notificatoin message
+                break;
+            case UPDATE:
+                BgpUpdateMsg updateMsg = (BgpUpdateMsg) msg;
+                List<BgpValueType> pathAttr = updateMsg.bgpPathAttributes().pathAttributes();
+                if (pathAttr == null) {
+                    log.debug("llPathAttr is null, cannot process update message");
+                    break;
+                }
+                Iterator<BgpValueType> listIterator = pathAttr.iterator();
+                boolean isLinkstate = false;
+                boolean isEvpn = false;
 
-            while (listIterator.hasNext()) {
-                BgpValueType attr = listIterator.next();
-                if (attr instanceof MpReachNlri) {
-                    MpReachNlri mpReach = (MpReachNlri) attr;
-                    if (mpReach.bgpFlowSpecNlri() == null) {
-                        isLinkstate = true;
-                    }
-                } else if (attr instanceof MpUnReachNlri) {
-                    MpUnReachNlri mpUnReach = (MpUnReachNlri) attr;
-                    if (mpUnReach.bgpFlowSpecNlri() == null) {
-                        isLinkstate = true;
+                while (listIterator.hasNext()) {
+                    BgpValueType attr = listIterator.next();
+                    if (attr instanceof MpReachNlri) {
+                        MpReachNlri mpReach = (MpReachNlri) attr;
+                        if (mpReach.bgpFlowSpecNlri() == null
+                                && mpReach.bgpEvpnNlri() == null) {
+                            isLinkstate = true;
+                        }
+                        if (mpReach.bgpEvpnNlri() != null) {
+                            isEvpn = true;
+                        }
+                    } else if (attr instanceof MpUnReachNlri) {
+                        MpUnReachNlri mpUnReach = (MpUnReachNlri) attr;
+                        if (mpUnReach.bgpFlowSpecNlri() == null
+                                && mpUnReach.bgpEvpnNlri() == null) {
+                            isLinkstate = true;
+                        }
+                        if (mpUnReach.bgpEvpnNlri() != null) {
+                            isEvpn = true;
+                        }
                     }
                 }
-            }
-            if (isLinkstate) {
-                peer.buildAdjRibIn(pathAttr);
-            }
-            break;
-        default:
-            // TODO: Process other message
-            break;
+                if (isLinkstate) {
+                    peer.buildAdjRibIn(pathAttr);
+                }
+                if (isEvpn) {
+                    for (BgpRouteListener listener : bgpRouteListener) {
+                        listener.processRoute(bgpId, updateMsg);
+                    }
+                }
+                break;
+            default:
+                // TODO: Process other message
+                break;
         }
     }
 
diff --git a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpPeerImpl.java b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpPeerImpl.java
index 34f4ec6..4dc8fee 100644
--- a/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpPeerImpl.java
+++ b/protocols/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BgpPeerImpl.java
@@ -26,6 +26,7 @@
 import org.onosproject.bgp.controller.BgpPeer;
 import org.onosproject.bgp.controller.BgpSessionInfo;
 import org.onosproject.bgpio.exceptions.BgpParseException;
+import org.onosproject.bgpio.protocol.BgpEvpnNlri;
 import org.onosproject.bgpio.protocol.BgpFactories;
 import org.onosproject.bgpio.protocol.BgpFactory;
 import org.onosproject.bgpio.protocol.BgpLSNlri;
@@ -36,8 +37,8 @@
 import org.onosproject.bgpio.protocol.linkstate.BgpNodeLSNlriVer4;
 import org.onosproject.bgpio.protocol.linkstate.BgpPrefixIPv4LSNlriVer4;
 import org.onosproject.bgpio.protocol.linkstate.PathAttrNlriDetails;
-import org.onosproject.bgpio.types.AsPath;
 import org.onosproject.bgpio.types.As4Path;
+import org.onosproject.bgpio.types.AsPath;
 import org.onosproject.bgpio.types.BgpExtendedCommunity;
 import org.onosproject.bgpio.types.BgpValueType;
 import org.onosproject.bgpio.types.LocalPref;
@@ -46,8 +47,8 @@
 import org.onosproject.bgpio.types.MpUnReachNlri;
 import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
 import org.onosproject.bgpio.types.Origin;
-import org.onosproject.bgpio.types.attr.WideCommunity;
 import org.onosproject.bgpio.types.RpdCapabilityTlv;
+import org.onosproject.bgpio.types.attr.WideCommunity;
 import org.onosproject.bgpio.util.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -256,6 +257,69 @@
     }
 
     @Override
+    public void updateEvpnNlri(FlowSpecOperation operType, IpAddress nextHop,
+                               List<BgpValueType> extcommunity,
+                               List<BgpEvpnNlri> evpnNlris) {
+        Preconditions.checkNotNull(operType, "Operation type cannot be null");
+        Preconditions.checkNotNull(evpnNlris, "Evpn nlri cannot be null");
+        sendEvpnUpdateMessageToPeer(operType, nextHop, extcommunity, evpnNlris);
+    }
+
+    private void sendEvpnUpdateMessageToPeer(FlowSpecOperation operType,
+                                             IpAddress nextHop,
+                                             List<BgpValueType> extcommunity,
+                                             List<BgpEvpnNlri> evpnNlris) {
+        List<BgpValueType> attributesList = new LinkedList<>();
+        byte sessionType = sessionInfo.isIbgpSession() ? (byte) 0 : (byte) 1;
+        short afi = Constants.AFI_EVPN_VALUE;
+        byte safi = Constants.SAFI_EVPN_VALUE;
+        boolean isEvpnCapabilitySet = isCapabilitySupported(MultiProtocolExtnCapabilityTlv.TYPE,
+                                                            afi, safi);
+        if (!isEvpnCapabilitySet) {
+            log.debug("Peer do not support BGP Evpn capability",
+                     channel.getRemoteAddress());
+            return;
+        }
+        attributesList.add(new Origin((byte) 0));
+
+        if (sessionType != 0) {
+            // EBGP
+            if (!bgpController.getConfig().getLargeASCapability()) {
+                List<Short> aspathSet = new ArrayList<>();
+                List<Short> aspathSeq = new ArrayList<>();
+                aspathSeq.add((short) bgpController.getConfig().getAsNumber());
+
+                AsPath asPath = new AsPath(aspathSet, aspathSeq);
+                attributesList.add(asPath);
+            } else {
+                List<Integer> aspathSet = new ArrayList<>();
+                List<Integer> aspathSeq = new ArrayList<>();
+                aspathSeq.add(bgpController.getConfig().getAsNumber());
+
+                As4Path as4Path = new As4Path(aspathSet, aspathSeq);
+                attributesList.add(as4Path);
+            }
+        } else {
+            attributesList.add(new AsPath());
+        }
+
+        if (!extcommunity.isEmpty()) {
+            attributesList.add(new BgpExtendedCommunity(extcommunity));
+        }
+        if (operType == FlowSpecOperation.ADD || operType == FlowSpecOperation.UPDATE) {
+            attributesList
+                    .add(new MpReachNlri(evpnNlris, afi, safi, nextHop.getIp4Address()));
+        } else if (operType == FlowSpecOperation.DELETE) {
+            attributesList.add(new MpUnReachNlri(evpnNlris, afi, safi));
+        }
+
+        BgpMessage msg = Controller.getBgpMessageFactory4()
+                .updateMessageBuilder().setBgpPathAttributes(attributesList)
+                .build();
+        channel.write(Collections.singletonList(msg));
+    }
+
+    @Override
     public void buildAdjRibIn(List<BgpValueType> pathAttr) throws BgpParseException {
         ListIterator<BgpValueType> iterator = pathAttr.listIterator();
         while (iterator.hasNext()) {