EVPN RT2 : Receive RT2 BGPManager changes 48/55848/14
authorVyshakh Krishnan CH <vyshakh.krishnan.c.h@ericsson.com>
Tue, 9 May 2017 05:36:09 +0000 (11:06 +0530)
committerSam Hague <shague@redhat.com>
Tue, 9 May 2017 12:28:21 +0000 (12:28 +0000)
On receiving RT2, bgpmanager has to updated the macVrfEntry in fib.yang.
Also when the RT2 is from a new TEP, same has to be updated in elan
external tep DS.
A sample cli is added to simulate the RT2 from QBGP as well.

Change-Id: If193af109a3a08d08d6c6f32e715c71f045e5af8
Signed-off-by: Vyshakh Krishnan CH <vyshakh.krishnan.c.h@ericsson.com>
vpnservice/bgpmanager/bgpmanager-impl/pom.xml
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/BgpConfigurationManager.java
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/BgpManager.java
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/BgpUtil.java
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/ConfigureBgpCli.java
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/FibDSWriter.java
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/thrift/client/BgpRouter.java
vpnservice/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/netvirt/bgpmanager/thrift/server/BgpThriftService.java

index d817dfc0954aa1587b597bd85f02075d51781934..4b849f1e9536f08f3a87d007f17b66f4a8492639 100644 (file)
@@ -26,6 +26,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <artifactId>bgpmanager-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>elanmanager-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.genius</groupId>
             <artifactId>mdsalutil-api</artifactId>
index 4fd52f9134e1401e0a4bcd47e48fa554be9f8ae7..09358cb1e1709241e38f872e2ad74b1dd63689b2 100755 (executable)
@@ -40,7 +40,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import javax.annotation.Nullable;
 
-
 import org.apache.thrift.TException;
 import org.opendaylight.controller.config.api.osgi.WaitingServiceTracker;
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
@@ -115,6 +114,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -221,6 +221,11 @@ public class BgpConfigurationManager {
     //static IITMProvider itmProvider;
     //map<rd, map<prefix/len:nexthop, label>>
     private static Map<String, Map<String, Long>> staledFibEntriesMap = new ConcurrentHashMap<>();
+    //map<rd, map<mac, l2vni>>
+    private static Map<String, Map<String, Long>> staledMacEntriesMap = new ConcurrentHashMap<>();
+
+    //map<rd, map<tep-ip, list<mac, l2vni>>>
+    private static Map<String, Map<String, Map<String, Long>>> rt2TepMap = new ConcurrentHashMap<>();
 
     static final String BGP_ENTITY_TYPE_FOR_OWNERSHIP = "bgp";
     static final String BGP_ENTITY_NAME = "bgp";
@@ -228,6 +233,7 @@ public class BgpConfigurationManager {
     static int totalStaledCount = 0;
     static int totalCleared = 0;
     static int totalExternalRoutes = 0;
+    static int totalExternalMacRoutes = 0;
 
     private static final Class[] REACTORS = {
         ConfigServerReactor.class, AsIdReactor.class,
@@ -1064,6 +1070,8 @@ public class BgpConfigurationManager {
                         : label.intValue();
                 int l3vni = (val.getL3vni() == null) ? qbgpConstants.LBL_NO_LABEL
                         : val.getL3vni().intValue();
+                int l2vni = (val.getL2vni() == null) ? qbgpConstants.LBL_NO_LABEL
+                        : val.getL2vni().intValue();
 
                 BgpControlPlaneType protocolType = val.getBgpControlPlaneType();
                 int ethernetTag = val.getEthtag().intValue();
@@ -1074,9 +1082,8 @@ public class BgpConfigurationManager {
                 int afiInt = testValueAFI(pfxlen);
 
                 try {
-                    br.addPrefix(rd, pfxlen, nh, lbl, l3vni, BgpUtil.convertToThriftProtocolType(protocolType),
-                            ethernetTag, esi, macaddress, BgpUtil.convertToThriftEncapType(encapType),
-                            routerMac);
+                    br.addPrefix(rd, pfxlen, nh, lbl, l3vni, l2vni, BgpUtil.convertToThriftProtocolType(protocolType),
+                            ethernetTag, esi, macaddress, BgpUtil.convertToThriftEncapType(encapType), routerMac);
                 } catch (TException | BgpRouterException e) {
                     LOG.error("{} Add received exception; {}", YANG_OBJ, ADD_WARN, e);
                 }
@@ -1636,6 +1643,7 @@ public class BgpConfigurationManager {
 
                     // TODO: decide correct label here
                     int label = update.getL3label();
+                    int l2label = update.getL2label();
 
                     String prefix = update.getPrefix();
                     int plen = update.getPrefixlen();
@@ -1645,18 +1653,18 @@ public class BgpConfigurationManager {
                     // use "rd" to query vrf table and obtain the protocol_type.
                     // Currently using PROTOCOL_EVPN as default.
                     onUpdatePushRoute(
-                            protocol_type.PROTOCOL_EVPN,
-                            rd,
-                            prefix,
-                            plen,
-                            nexthop,
-                            update.getEthtag(),
-                            update.getEsi(),
-                            update.getMacaddress(),
-                            label,
-                            update.getRoutermac(),
-                            afi
-                    );
+                           protocol_type.PROTOCOL_EVPN,
+                           rd,
+                           prefix,
+                           plen,
+                           nexthop,
+                           update.getEthtag(),
+                           update.getEsi(),
+                           update.getMacaddress(),
+                           label,
+                           l2label,
+                           update.getRoutermac(),
+                           afi);
                 }
             }
         }
@@ -1668,6 +1676,26 @@ public class BgpConfigurationManager {
         }
     }
 
+    public static void addTepToElanDS(String rd, String tepIp, String mac, Long l2vni) {
+        boolean needUpdate = addToRt2TepMap(rd, tepIp, mac, l2vni);
+        if (needUpdate) {
+            LOG.info("Adding tepIp {} with RD {} to ELan DS", tepIp, rd);
+            BgpUtil.addTepToElanInstance(dataBroker, rd, tepIp);
+        } else {
+            LOG.debug("Skipping the Elan update for RT2 from tep {} rd {}", tepIp, rd);
+        }
+    }
+
+    public static void deleteTepfromElanDS(String rd, String tepIp, String mac) {
+        boolean needUpdate = deleteFromRt2TepMap(rd, tepIp, mac);
+        if (needUpdate) {
+            LOG.info("Deleting tepIp {} with RD {} to ELan DS", tepIp, rd);
+            BgpUtil.deleteTepFromElanInstance(dataBroker, rd, tepIp);
+        } else {
+            LOG.debug("Skipping the Elan update for RT2 withdraw from tep {} rd {}", tepIp, rd);
+        }
+    }
+
     /* onUpdatePushRoute
      * Get Stale fibDSWriter map, and compare current route/fibDSWriter entry.
      *  - Entry compare shall include NextHop, Label.
@@ -1687,22 +1715,32 @@ public class BgpConfigurationManager {
                                          String esi,
                                          String macaddress,
                                          int label,
+                                         int l2label,
                                          String routermac,
                                          af_afi afi)
             throws InterruptedException, ExecutionException, TimeoutException {
         boolean addroute = false;
+        boolean macupdate = false;
         long l3vni = 0L;
         VrfEntry.EncapType encapType = VrfEntry.EncapType.Mplsgre;
         if (protocolType.equals(protocol_type.PROTOCOL_EVPN)) {
             encapType = VrfEntry.EncapType.Vxlan;
             VpnInstanceOpDataEntry vpnInstanceOpDataEntry = BgpUtil.getVpnInstanceOpData(dataBroker, rd);
             if (vpnInstanceOpDataEntry != null) {
-                l3vni = vpnInstanceOpDataEntry.getL3vni();
+                if (vpnInstanceOpDataEntry.getType() == VpnInstanceOpDataEntry.Type.L2) {
+                    LOG.info("Got RT2 route for RD {} l3label {} l2label {} from tep {} with mac {} remote RD {}",
+                            vpnInstanceOpDataEntry.getVpnInstanceName(), label, l2label, nextHop, macaddress, rd);
+                    addTepToElanDS(rd, nextHop, macaddress, (long)l2label);
+                    macupdate = true;
+                } else {
+                    l3vni = vpnInstanceOpDataEntry.getL3vni();
+                }
             } else {
                 LOG.error("No corresponding vpn instance found for rd {}. Aborting.", rd);
                 return;
             }
         }
+
         if (!staledFibEntriesMap.isEmpty()) {
             // restart Scenario, as MAP is not empty.
             Map<String, Long> map = staledFibEntriesMap.get(rd);
@@ -1725,7 +1763,12 @@ public class BgpConfigurationManager {
             LOG.debug("Route add ** {} ** {}/{} ** {} ** {} ", rd, prefix, plen, nextHop, label);
             addroute = true;
         }
-        if (addroute) {
+        if (macupdate) {
+            LOG.info("ADD: Adding Mac Fib entry rd {} mac{} nexthop {} l2vni {}", rd, macaddress, nextHop, l2label);
+            fibDSWriter.addMacEntryToDS(rd, macaddress, prefix, Collections.singletonList(nextHop),
+                    encapType, l2label, routermac, RouteOrigin.BGP);
+            LOG.info("ADD: Added Mac Fib entry rd {} prefix {} nexthop {} label {}", rd, macaddress, nextHop, l2label);
+        } else if (addroute) {
             LOG.info("ADD: Adding Fib entry rd {} prefix {} nexthop {} label {} afi {}",
                     rd, prefix, nextHop, label, afi);
             // TODO: modify addFibEntryToDS signature
@@ -1741,6 +1784,53 @@ public class BgpConfigurationManager {
         }
     }
 
+    public static void onUpdateWithdrawRoute(protocol_type protocolType,
+                                             String rd,
+                                             String prefix,
+                                             int plen,
+                                             String nextHop,
+                                             String macaddress)
+            throws InterruptedException, ExecutionException, TimeoutException {
+        long vni = 0L;
+        boolean macupdate = false;
+        if (protocolType.equals(protocol_type.PROTOCOL_EVPN)) {
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = BgpUtil.getVpnInstanceOpData(dataBroker, rd);
+            if (vpnInstanceOpDataEntry != null) {
+                vni = vpnInstanceOpDataEntry.getL3vni();
+                if (vpnInstanceOpDataEntry.getType() == VpnInstanceOpDataEntry.Type.L2) {
+                    LOG.debug("Got RT2 withdraw for RD %s from tep %s with mac %s remote RD %s",
+                            vpnInstanceOpDataEntry.getVpnInstanceName(), vni, nextHop, macaddress, rd);
+                    deleteTepfromElanDS(rd, nextHop, macaddress);
+                    LOG.debug("For rd %s. skipping fib update", rd);
+                    macupdate = true;
+                }
+            } else {
+                LOG.error("No corresponding vpn instance found for rd {}. Aborting.", rd);
+                return;
+            }
+        }
+        if (macupdate) {
+            LOG.info("Removing Mac Fib entry rd {} mac{} nexthop {} ", rd, macaddress, nextHop);
+            fibDSWriter.removeMacEntryFromDS(rd, macaddress);
+            LOG.info("Removed Mac Fib entry rd {} prefix {} nexthop {} ", rd, macaddress, nextHop);
+        } else {
+            LOG.info("REMOVE: Removing Fib entry rd {} prefix {}", rd, prefix);
+            fibDSWriter.removeOrUpdateFibEntryFromDS(rd, prefix + "/" + plen, nextHop);
+            LOG.info("REMOVE: Removed Fib entry rd {} prefix {}", rd, prefix);
+        }
+    }
+
+    //TODO: below function is for testing purpose with cli
+    public static void onUpdateWithdrawRoute(String rd, String prefix, int plen, String nexthop) {
+        LOG.debug("Route del ** {} ** {}/{} ", rd, prefix, plen);
+        fibDSWriter.removeOrUpdateFibEntryFromDS(rd, prefix + "/" + plen, nexthop);
+        String vpnName = BgpUtil.getVpnNameFromRd(dataBroker, rd);
+        if (vpnName != null) {
+            vpnLinkService.leakRouteIfNeeded(vpnName, prefix, null /*nextHopList*/, 0 /*INVALID_LABEL*/,
+                                             RouteOrigin.BGP, NwConstants.DEL_FLOW);
+        }
+    }
+
     private static boolean isRouteModified(int label, Long labelInStaleMap) {
         return labelInStaleMap != null && !labelInStaleMap.equals(Long.valueOf(label));
     }
@@ -1921,6 +2011,7 @@ public class BgpConfigurationManager {
                     Long label = net.getLabel();
                     int lbl = (label == null) ? 0 : label.intValue();
                     int l3vni = (net.getL3vni() == null) ? 0 : net.getL3vni().intValue();
+                    int l2vni = (net.getL2vni() == null) ? 0 : net.getL2vni().intValue();
                     Long afi = net.getAfi();
                     int afint = (afi == null) ? (int) af_afi.AFI_IP.getValue() : afi.intValue();
                     if (rd == null && lbl > 0) {
@@ -1936,9 +2027,9 @@ public class BgpConfigurationManager {
                     String routerMac = net.getRoutermac();
 
                     try {
-                        br.addPrefix(rd, pfxlen, nh, lbl, l3vni, BgpUtil.convertToThriftProtocolType(protocolType),
-                                ethernetTag, esi, macaddress, BgpUtil.convertToThriftEncapType(encapType),
-                                routerMac);
+                        br.addPrefix(rd, pfxlen, nh, lbl, l3vni, l2vni,
+                                BgpUtil.convertToThriftProtocolType(protocolType),
+                                ethernetTag, esi, macaddress, BgpUtil.convertToThriftEncapType(encapType), routerMac);
                     } catch (Exception e) {
                         LOG.error("Replay:addPfx() received exception", e);
                     }
@@ -2348,6 +2439,7 @@ public class BgpConfigurationManager {
      */
     public static void deleteExternalFibRoutes() {
         totalExternalRoutes = 0;
+        totalExternalMacRoutes = 0;
         try {
             /*
             * at the time FIB route deletion, Wait till all PENDING write transaction
@@ -2379,17 +2471,24 @@ public class BgpConfigurationManager {
                 List<VrfTables> staleVrfTables = fibEntries.get().getVrfTables();
                 for (VrfTables vrfTable : staleVrfTables) {
                     rd = vrfTable.getRouteDistinguisher();
-                    if (vrfTable.getVrfEntry() == null) {
-                        LOG.error("deleteExternalFibRoutes::getVrfEntry is null");
-                        continue;
-                    }
-                    for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
-                        if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
-                            //route cleanup is only meant for the routes learned through BGP.
-                            continue;
+                    if (vrfTable.getVrfEntry() != null) {
+                        for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
+                            if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
+                                //route cleanup is only meant for the routes learned through BGP.
+                                continue;
+                            }
+                            totalExternalRoutes++;
+                            fibDSWriter.removeFibEntryFromDS(rd, vrfEntry.getDestPrefix());
+                        }
+                    } else if (vrfTable.getMacVrfEntry() != null) {
+                        for (MacVrfEntry macEntry : vrfTable.getMacVrfEntry()) {
+                            if (RouteOrigin.value(macEntry.getOrigin()) != RouteOrigin.BGP) {
+                                //route cleanup is only meant for the routes learned through BGP.
+                                continue;
+                            }
+                            totalExternalMacRoutes++;
+                            fibDSWriter.removeMacEntryFromDS(rd, macEntry.getMac());
                         }
-                        totalExternalRoutes++;
-                        fibDSWriter.removeFibEntryFromDS(rd, vrfEntry.getDestPrefix());
                     }
                 }
             } else {
@@ -2398,7 +2497,7 @@ public class BgpConfigurationManager {
         } catch (InterruptedException | ReadFailedException e) {
             LOG.error("deleteExternalFibRoutes:: error ", e);
         }
-        LOG.debug("deleted {} fib entries ", totalExternalRoutes);
+        LOG.debug("deleted {} fib entries {} mac entries", totalExternalRoutes, totalExternalMacRoutes);
     }
 
     //map<rd, map<prefix/len:nexthop, label>>
@@ -2406,15 +2505,63 @@ public class BgpConfigurationManager {
         return staledFibEntriesMap;
     }
 
-    //TODO: below function is for testing purpose with cli
-    public static void onUpdateWithdrawRoute(String rd, String prefix, int plen, String nexthop) {
-        LOG.debug("Route del ** {} ** {}/{} ", rd, prefix, plen);
-        fibDSWriter.removeOrUpdateFibEntryFromDS(rd, prefix + "/" + plen, nexthop);
-        String vpnName = BgpUtil.getVpnNameFromRd(dataBroker, rd);
-        if (vpnName != null) {
-            vpnLinkService.leakRouteIfNeeded(vpnName, prefix, null /*nextHopList*/, 0 /*INVALID_LABEL*/,
-                                             RouteOrigin.BGP, NwConstants.DEL_FLOW);
+    public static Map<String, Map<String, Long>> getStaledMacEntriesMap() {
+        return staledMacEntriesMap;
+    }
+
+    public static Map<String, Map<String, Map<String, Long>>> getRt2TepMap() {
+        return rt2TepMap;
+    }
+
+    public static boolean addToRt2TepMap(String rd, String tepIp, String mac, Long l2vni) {
+        boolean isFirstMacUpdateFromTep = false;
+        if (getRt2TepMap().containsKey(rd)) {
+            if (getRt2TepMap().get(rd).containsKey(tepIp)) {
+                LOG.debug("RT2 with mac {} l2vni {} from existing rd {} and tep-ip {}. No Elan DS write required",
+                        mac, l2vni, rd, tepIp);
+                getRt2TepMap().get(rd).get(tepIp).put(mac, l2vni);
+            } else {
+                LOG.debug("RT2 with mac {} l2vni {} from existing rd {} and new tep-ip {}",
+                        mac, rd, tepIp);
+                isFirstMacUpdateFromTep = true;
+                Map<String, Long> macList = new HashMap<>();
+                macList.put(mac, l2vni);
+                getRt2TepMap().get(rd).put(tepIp, macList);
+            }
+        } else {
+            LOG.debug("RT2 with mac {} l2vni {} from new rd {} and tep ip {}",
+                    mac, l2vni, rd, tepIp);
+            isFirstMacUpdateFromTep = true;
+            Map<String, Long> macList = new HashMap<>();
+            macList.put(mac, l2vni);
+            Map<String, Map<String, Long>> tepIpMacMap = new HashMap<>();
+            tepIpMacMap.put(tepIp, macList);
+            getRt2TepMap().put(rd, tepIpMacMap);
+        }
+        return isFirstMacUpdateFromTep;
+    }
+
+    public static boolean deleteFromRt2TepMap(String rd, String tepIp, String mac) {
+        boolean isLastMacUpdateFromTep = false;
+        LOG.debug("RT2 withdraw with rd {} mac {} tep-ip {} ", rd, mac, tepIp);
+        if (getRt2TepMap().containsKey(rd)) {
+            if (getRt2TepMap().get(rd).containsKey(tepIp)) {
+                if (getRt2TepMap().get(rd).get(tepIp).containsKey(mac)) {
+                    LOG.debug("RT2 Withdraw : Removing the mac {} from Map", mac);
+                    getRt2TepMap().get(rd).get(tepIp).remove(mac);
+                    if (getRt2TepMap().get(rd).get(tepIp).isEmpty()) {
+                        isLastMacUpdateFromTep = true;
+                        LOG.debug("RT2 Withdraw : Removing the tep-ip {} from Map", tepIp);
+                        getRt2TepMap().get(rd).remove(tepIp);
+                        if (getRt2TepMap().get(rd).isEmpty()) {
+                            LOG.debug("RT2 Withdraw : Removing the rd {} from Map", rd);
+                            getRt2TepMap().remove(rd);
+                        }
+                    }
+                }
+            }
         }
+        return isLastMacUpdateFromTep;
     }
 
     public boolean isBgpConnected() {
index 970fc23af9064c333b7cf29f690bdb9df5d8fc43..b2cef00d8e775df926d624c8c476512ee51e7169 100644 (file)
@@ -136,20 +136,24 @@ public class BgpManager implements AutoCloseable, IBgpManager {
     public void advertisePrefix(String rd, String macAddress, String prefix, List<String> nextHopList,
                                 VrfEntry.EncapType encapType, long vpnLabel, long l3vni, long l2vni,
                                 String gatewayMac) throws Exception {
+        LOG.info("Advertise Prefix: Adding Prefix rd {} prefix {} label {} l3vni {} l2vni {}",
+                rd, prefix, vpnLabel, l3vni, l2vni);
         bcm.addPrefix(rd, macAddress, prefix, nextHopList,
                 encapType, vpnLabel, l3vni, l2vni, gatewayMac);
+        LOG.info("Advertise Prefix: Added Prefix rd {} prefix {} label {} l3vni {} l2vni {}",
+                rd, prefix, vpnLabel, l3vni, l2vni);
     }
 
     @Override
     public void advertisePrefix(String rd, String macAddress, String prefix, String nextHop,
                                 VrfEntry.EncapType encapType, long vpnLabel, long l3vni, long l2vni,
                                 String gatewayMac) throws Exception {
-        LOG.info("ADVERTISE: Adding Prefix rd {} prefix {} nexthop {} label {} afi {}",
-                rd, prefix, nextHop, vpnLabel);
+        LOG.info("ADVERTISE: Adding Prefix rd {} prefix {} nexthop {} label {} l3vni {} l2vni {}",
+                rd, prefix, nextHop, vpnLabel, l3vni, l2vni);
         bcm.addPrefix(rd, macAddress, prefix, Collections.singletonList(nextHop), encapType,
                 vpnLabel, l3vni, l2vni, gatewayMac);
-        LOG.info("ADVERTISE: Added Prefix rd {} prefix {} nexthop {} label {} afi {}",
-                rd, prefix, nextHop, vpnLabel);
+        LOG.info("ADVERTISE: Added Prefix rd {} prefix {} nexthop {} label {} l3vni {} l2vni {}",
+                rd, prefix, nextHop, vpnLabel, l3vni, l2vni);
     }
 
     @Override
index 721e017d621225a11c56b2ce34b77280f8755b92..901e6f50c8a85d5258770b62b910793280373794 100755 (executable)
@@ -36,7 +36,17 @@ import org.opendaylight.netvirt.bgpmanager.thrift.gen.encap_type;
 import org.opendaylight.netvirt.bgpmanager.thrift.gen.protocol_type;
 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.BgpControlPlaneType;
 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.EncapType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.EvpnRdToNetworks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.evpn.rd.to.networks.EvpnRdToNetworkKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -176,7 +186,7 @@ public class BgpUtil {
             ExecutionException, TimeoutException {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = MDSALUtil.read(broker,
-                LogicalDatastoreType.OPERATIONAL, id);
+                LogicalDatastoreType.CONFIGURATION, id);
         if (vpnInstanceOpData.isPresent()) {
             return vpnInstanceOpData.get();
         }
@@ -188,6 +198,62 @@ public class BgpUtil {
                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
     }
 
+    static String getElanNamefromRd(DataBroker broker, String rd)  {
+        InstanceIdentifier<EvpnRdToNetwork> id = getEvpnRdToNetworkIdentifier(rd);
+        Optional<EvpnRdToNetwork> evpnRdToNetworkOpData = MDSALUtil.read(broker,
+                LogicalDatastoreType.OPERATIONAL, id);
+        if (evpnRdToNetworkOpData.isPresent()) {
+            return evpnRdToNetworkOpData.get().getNetworkId();
+        }
+        return null;
+    }
+
+    public static InstanceIdentifier<EvpnRdToNetwork> getEvpnRdToNetworkIdentifier(String rd) {
+        return InstanceIdentifier.builder(EvpnRdToNetworks.class)
+                .child(EvpnRdToNetwork.class, new EvpnRdToNetworkKey(rd)).build();
+    }
+
+    public static void addTepToElanInstance(DataBroker broker, String rd, String tepIp) {
+        if (rd == null || tepIp == null) {
+            LOG.error("addTepToElanInstance : Null parameters returning");
+            return;
+        }
+        String elanName = getElanNamefromRd(broker, rd);
+        if (elanName == null) {
+            LOG.error("Elan null while processing RT2 for RD {}", rd);
+            return;
+        }
+        LOG.debug("Adding tepIp {} to elan {}", tepIp, elanName);
+        InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
+        ExternalTepsBuilder externalTepsBuilder = new ExternalTepsBuilder();
+        ExternalTepsKey externalTepsKey = externalTepsId.firstKeyOf(ExternalTeps.class);
+        externalTepsBuilder.setKey(externalTepsKey);
+        externalTepsBuilder.setTepIp(externalTepsKey.getTepIp());
+        BgpUtil.update(dataBroker, LogicalDatastoreType.CONFIGURATION, externalTepsId, externalTepsBuilder.build());
+    }
+
+    public static void deleteTepFromElanInstance(DataBroker broker, String rd, String tepIp) {
+        if (rd == null || tepIp == null) {
+            LOG.error("deleteTepFromElanInstance : Null parameters returning");
+            return;
+        }
+        String elanName = getElanNamefromRd(broker, rd);
+        if (elanName == null) {
+            LOG.error("Elan null while processing RT2 withdraw for RD {}", rd);
+            return;
+        }
+        LOG.debug("Deleting tepIp {} from elan {}", tepIp, elanName);
+        InstanceIdentifier<ExternalTeps> externalTepsId = getExternalTepsIdentifier(elanName, tepIp);
+        BgpUtil.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, externalTepsId);
+    }
+
+    public static InstanceIdentifier<ExternalTeps> getExternalTepsIdentifier(String elanInstanceName, String tepIp) {
+        IpAddress tepAdress = (tepIp == null) ? null : new IpAddress(tepIp.toCharArray());
+        return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class,
+                new ElanInstanceKey(elanInstanceName)).child(ExternalTeps.class,
+                new ExternalTepsKey(tepAdress)).build();
+    }
+
     public static String getVpnNameFromRd(DataBroker dataBroker2, String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class)
                                                                           .child(VpnInstanceOpDataEntry.class,
index 93370de43f81b5e2ed209f2e7075064a9273ada7..cb0462fca0c1dda51a186be7e773bed5926eab3a 100644 (file)
@@ -18,7 +18,7 @@ import org.apache.karaf.shell.console.OsgiCommandSupport;
 import org.apache.thrift.TException;
 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_afi;
 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_safi;
-
+import org.opendaylight.netvirt.bgpmanager.thrift.gen.protocol_type;
 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.Bgp;
 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.TcpMd5SignaturePasswordType;
 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.Neighbors;
@@ -31,6 +31,8 @@ public class ConfigureBgpCli extends OsgiCommandSupport {
     private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureBgpCli.class);
 
     private static BgpManager bgpManager;
+    private static BgpConfigurationManager bgpConfigurationManager;
+
 
     private static final long AS_MIN = 0;
     private static final long AS_MAX = 4294967295L;//2^32-1
@@ -40,12 +42,14 @@ public class ConfigureBgpCli extends OsgiCommandSupport {
     }
 
     @Option(name = "-op", aliases = {"--operation", "--op"}, description = "[start-bgp-server, stop-bgp-server, "
-            + "add-neighbor, delete-neighbor, graceful-restart, enable-log ]",
+            + "add-neighbor, delete-neighbor, add-route, delete-route,graceful-restart, enable-log ]",
             required = false, multiValued = false)
     String op;
 
     //exec configure-bgp  add-neighbor --ip <neighbor-ip> --as-num <as-num> --address-family <af> --use-source-ip
     // <sip> --ebgp-multihops <em> --next-hop <nh>
+    //exec configure-bgp --op add-route/delete-route --rd <rd> --prefix <prefix> --nexthop <nexthop>
+    // --mac <mac> --l2vni <l2vni> --l3vni <l3vni>
 
     @Option(name = "--as-num", description = "as number of the bgp neighbor", required = false, multiValued = false)
     String asNumber = null;
@@ -74,6 +78,30 @@ public class ConfigureBgpCli extends OsgiCommandSupport {
             required = false, multiValued = false)
     String routerId = null;
 
+    @Option(name = "--rd", description = "rd of the route",
+            required = false, multiValued = false)
+    String rd = null;
+
+    @Option(name = "--prefix", description = "prefix of the route",
+            required = false, multiValued = false)
+    String prefix = null;
+
+    @Option(name = "--nexthop", description = "nexthop of the route",
+            required = false, multiValued = false)
+    String nexthop = null;
+
+    @Option(name = "--mac", description = "mac of the route",
+            required = false, multiValued = false)
+    String mac = null;
+
+    @Option(name = "--l2vni", description = "l2vni of the route",
+            required = false, multiValued = false)
+    int l2vni = 0;
+
+    @Option(name = "--l3vni", description = "l3vni",
+            required = false, multiValued = false)
+    int l3vni = 0;
+
     @Option(name = "--stalepath-time", description = "the time delay after bgp restart stalepaths are cleaned",
             required = false, multiValued = false)
     String stalePathTime = null;
@@ -99,7 +127,7 @@ public class ConfigureBgpCli extends OsgiCommandSupport {
                 usage();
                 session.getConsole().println(
                         "exec configure-bgp -op [start-bgp-server | stop-bgp-server | add-neighbor | delete-neighbor|"
-                                + " graceful-restart| enable-log ]");
+                                + " add-route | delete-route | graceful-restart| enable-log ]");
             }
             switch (op) {
                 case "start-bgp-server":
@@ -114,6 +142,12 @@ public class ConfigureBgpCli extends OsgiCommandSupport {
                 case "delete-neighbor":
                     deleteNeighbor();
                     break;
+                case "add-route":
+                    addRoute();
+                    break;
+                case "delete-route":
+                    deleteRoute();
+                    break;
                 case "graceful-restart":
                     configureGR();
                     break;
@@ -342,6 +376,16 @@ public class ConfigureBgpCli extends OsgiCommandSupport {
         }
     }
 
+    protected void addRoute() throws Exception {
+        bgpConfigurationManager.onUpdatePushRoute(protocol_type.PROTOCOL_EVPN, rd, prefix,
+                0, nexthop, 0, null, mac, l3vni, l2vni, null, null);
+    }
+
+    protected void deleteRoute() throws Exception {
+        bgpConfigurationManager.onUpdateWithdrawRoute(protocol_type.PROTOCOL_EVPN, rd, prefix,
+                0, nexthop, mac);
+    }
+
     private boolean validateIp(String inputIp) {
         boolean validIp = false;
         try {
index 506a1b566779698fe31624a8f44c3daef639e686..00784f6cb65302c455005ffff676653163df1978 100644 (file)
@@ -13,7 +13,7 @@ import com.google.common.base.Preconditions;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
-
+import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
@@ -23,6 +23,9 @@ import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.macvrfentries.MacVrfEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
@@ -71,6 +74,34 @@ public class FibDSWriter {
         BgpUtil.update(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
     }
 
+    public void addMacEntryToDS(String rd, String macAddress, String prefix,
+                                List<String> nextHopList, VrfEntry.EncapType encapType,
+                                long l2vni, String gatewayMacAddress, RouteOrigin origin) {
+        if (StringUtils.isEmpty(rd)) {
+            LOG.error("Mac {} not associated with vpn", macAddress);
+            return;
+        }
+
+        Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
+        for (String nextHop : nextHopList) {
+            if (StringUtils.isEmpty(nextHop)) {
+                LOG.error("nextHop list contains null element for macVrf");
+                return;
+            }
+        }
+
+        MacVrfEntryBuilder macEntryBuilder = new MacVrfEntryBuilder().setOrigin(origin.getValue());
+        buildVpnEncapSpecificInfo(macEntryBuilder, encapType, l2vni, macAddress,
+                gatewayMacAddress, nextHopList);
+        macEntryBuilder.setMac(macAddress);
+        macEntryBuilder.setDestPrefix(prefix);
+        InstanceIdentifier<MacVrfEntry> macEntryId =
+                InstanceIdentifier.builder(FibEntries.class)
+                        .child(VrfTables.class, new VrfTablesKey(rd))
+                        .child(MacVrfEntry.class, new MacVrfEntryKey(macAddress)).build();
+        BgpUtil.update(dataBroker, LogicalDatastoreType.CONFIGURATION, macEntryId, macEntryBuilder.build());
+    }
+
     private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder,
             VrfEntry.EncapType encapType, long label, long l3vni, String macAddress,
             String gatewayMac, List<String> nextHopList) {
@@ -88,6 +119,20 @@ public class FibDSWriter {
         builder.setRoutePaths(routePaths);
     }
 
+    private static void buildVpnEncapSpecificInfo(MacVrfEntryBuilder builder,
+                                                  VrfEntry.EncapType encapType, long l2vni, String macAddress,
+                                                  String gatewayMac, List<String> nextHopList) {
+        builder.setEncapType(encapType);
+        builder.setGatewayMacAddress(gatewayMac);
+        builder.setL2vni(l2vni);
+        List<RoutePaths> routePaths = nextHopList.stream()
+                .filter(nextHop -> StringUtils.isEmpty(nextHop))
+                .map(nextHop -> {
+                    return FibHelper.buildRoutePath(nextHop, null);
+                }).collect(Collectors.toList());
+        builder.setRoutePaths(routePaths);
+    }
+
     public synchronized void removeFibEntryFromDS(String rd, String prefix) {
 
         if (rd == null || rd.isEmpty()) {
@@ -104,6 +149,22 @@ public class FibDSWriter {
 
     }
 
+    public void removeMacEntryFromDS(String rd, String macAddress) {
+
+        if (StringUtils.isEmpty(rd)) {
+            LOG.error("Mac {} not associated with vpn", macAddress);
+            return;
+        }
+        LOG.debug("Removing Mac fib entry with Mac {} from vrf table for rd {}", macAddress, rd);
+
+        InstanceIdentifierBuilder<MacVrfEntry> idBuilder =
+                InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(
+                        MacVrfEntry.class, new MacVrfEntryKey(macAddress));
+        InstanceIdentifier<MacVrfEntry> macEntryId = idBuilder.build();
+        BgpUtil.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, macEntryId);
+
+    }
+
     public synchronized void removeOrUpdateFibEntryFromDS(String rd, String prefix, String nextHop) {
 
         if (rd == null || rd.isEmpty()) {
index 7d47d0150ba5e7d248cadd25d417ae53077cadb4..0c9ac9b9fe873d9ba4302f124b6a02803b770fc8 100644 (file)
@@ -338,6 +338,7 @@ public class BgpRouter {
                                        String nexthop,
                                        int label,
                                        int l3vni,
+                                       int l2vni,
                                        protocol_type protocolType,
                                        int ethtag,
                                        String esi,
@@ -354,6 +355,7 @@ public class BgpRouter {
         bop.ints[0] = label;
         if (protocolType.equals(protocol_type.PROTOCOL_EVPN) && encapType.equals(encap_type.VXLAN)) {
             bop.l3label = l3vni; //L3VPN Over VxLan
+            bop.l2label = l2vni;
         } else {
             bop.l3label = label; // L3VPN Over MPLSGRE
         }
index bc7c32cf7b6e4f820917a34b8ebc87d6ef07f238..9e74d39a9228e1079889cc81793903f31b62091e 100644 (file)
@@ -9,6 +9,9 @@
 package org.opendaylight.netvirt.bgpmanager.thrift.server;
 
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
 import org.apache.thrift.protocol.TBinaryProtocol;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.server.ServerContext;
@@ -149,6 +152,7 @@ public class BgpThriftService {
                         esi,
                         macaddress,
                         l3label,
+                        l2label,
                         routermac,
                         afi);
 
@@ -168,10 +172,22 @@ public class BgpThriftService {
                                           int l3label,
                                           int l2label,
                                           af_afi afi) {
-            LOGGER.debug("Route del ** {} ** {}/{} ", rd, prefix, plen);
-            LOGGER.info("REMOVE: Removing Fib entry rd {} prefix {} nexthop {}", rd, prefix, nexthop);
-            fibDSWriter.removeOrUpdateFibEntryFromDS(rd, prefix + "/" + plen, nexthop);
-            LOGGER.info("REMOVE: Removed Fib entry rd {} prefix {} nexthop {}", rd, prefix, nexthop);
+            try {
+                LOGGER.debug("Route del ** {} ** {}/{} ", rd, prefix, plen);
+                BgpConfigurationManager.onUpdateWithdrawRoute(
+                        protocolType,
+                        rd,
+                        prefix,
+                        plen,
+                        nexthop,
+                        macaddress);
+            } catch (InterruptedException e1) {
+                LOGGER.error("Interrupted exception for withdraw route", e1);
+            } catch (ExecutionException e2) {
+                LOGGER.error("Execution exception for withdraw route", e2);
+            } catch (TimeoutException e3) {
+                LOGGER.error("Timeout exception for withdraw route", e3);
+            }
         }
 
         public void onStartConfigResyncNotification() {