X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=fibmanager%2Ffibmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fvpnservice%2Ffibmanager%2FFibManager.java;h=f1ce228a05c3924b77f89cde09fc648981c1357a;hb=7fd91ca847eaebfa14b0da26e986641be438fdae;hp=2ff2bd8233d5ab8b43a46edfdd8e6dcd573186e5;hpb=2ccb70accdd075712be8a38e812c2aefa3e2fdfc;p=vpnservice.git diff --git a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java index 2ff2bd82..f1ce228a 100644 --- a/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java +++ b/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/vpnservice/fibmanager/FibManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -7,15 +7,29 @@ */ package org.opendaylight.vpnservice.fibmanager; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.Futures; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; -import org.opendaylight.vpnmanager.api.IVpnManager; -import org.opendaylight.vpnservice.AbstractDataChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnmanager.api.IVpnManager; +import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener; +import org.opendaylight.vpnservice.itm.globals.ITMConstants; import org.opendaylight.vpnservice.mdsalutil.ActionInfo; import org.opendaylight.vpnservice.mdsalutil.ActionType; import org.opendaylight.vpnservice.mdsalutil.FlowEntity; @@ -27,54 +41,60 @@ import org.opendaylight.vpnservice.mdsalutil.MatchInfo; import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil; import org.opendaylight.vpnservice.mdsalutil.NwConstants; import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.GetEgressPointerInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.GetEgressPointerOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.L3nexthopService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.RemoveLocalNextHopInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; -import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; - -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; public class FibManager extends AbstractDataChangeListener implements AutoCloseable{ private static final Logger LOG = LoggerFactory.getLogger(FibManager.class); private static final String FLOWID_PREFIX = "L3."; private ListenerRegistration listenerRegistration; private final DataBroker broker; - private final L3nexthopService l3nexthopService; private IMdsalApiManager mdsalManager; private IVpnManager vpnmanager; + private NexthopManager nextHopManager; + private ItmRpcService itmManager; + private OdlInterfaceRpcService interfaceManager; private static final short L3_FIB_TABLE = 21; private static final short L3_LFIB_TABLE = 20; + public static final short INTERNAL_TUNNEL_TABLE = 23; + private static final short L3_PROTOCOL_TABLE = 36; + private static final short L3_INTERFACE_TABLE = 80; + public static final short LPORT_DISPATCHER_TABLE = 30; private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16); private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16); private static final int DEFAULT_FIB_FLOW_PRIORITY = 10; + private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16); + private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0); + public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16); private static final FutureCallback DEFAULT_CALLBACK = @@ -88,10 +108,9 @@ public class FibManager extends AbstractDataChangeListener implements }; }; - public FibManager(final DataBroker db, final RpcService nextHopService) { + public FibManager(final DataBroker db) { super(VrfEntry.class); broker = db; - l3nexthopService = (L3nexthopService)nextHopService; registerListener(db); } @@ -108,6 +127,9 @@ public class FibManager extends AbstractDataChangeListener implements LOG.info("Fib Manager Closed"); } + public void setNextHopManager(NexthopManager nextHopManager) { + this.nextHopManager = nextHopManager; + } public void setMdsalManager(IMdsalApiManager mdsalManager) { this.mdsalManager = mdsalManager; @@ -117,9 +139,17 @@ public class FibManager extends AbstractDataChangeListener implements this.vpnmanager = vpnmanager; } + public void setITMRpcService(ItmRpcService itmManager) { + this.itmManager = itmManager; + } + + public void setInterfaceManager(OdlInterfaceRpcService ifManager) { + this.interfaceManager = ifManager; + } + private void registerListener(final DataBroker db) { try { - listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE); } catch (final Exception e) { LOG.error("FibManager DataChange listener registration fail!", e); @@ -169,6 +199,7 @@ public class FibManager extends AbstractDataChangeListener implements @Override protected void update(InstanceIdentifier identifier, VrfEntry original, VrfEntry update) { LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update ); + createFibEntries(identifier, update); } private void createFibEntries(final InstanceIdentifier identifier, @@ -177,40 +208,217 @@ public class FibManager extends AbstractDataChangeListener implements Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!"); Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); - Long vpnId = getVpnId(vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnId, "Vpn Instance not available!"); - Collection dpns = vpnmanager.getDpnsForVpn(vpnId); - for (Long dpId : dpns) { - addRouteInternal(dpId, vpnId, vrfTableKey, vrfEntry); + VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!"); + Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!"); + + Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); + BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(), + vrfTableKey.getRouteDistinguisher(), vrfEntry); + if (vpnToDpnList != null) { + for (VpnToDpnList curDpn : vpnToDpnList) { + if (!curDpn.getDpnId().equals(localDpnId)) { + createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), + vrfTableKey, vrfEntry); + } + } } } - private void addRouteInternal(final long dpId, final long vpnId, final VrfTablesKey vrfTableKey, - final VrfEntry vrfEntry) { + public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { + BigInteger localDpnId = BigInteger.ZERO; + Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix()); + boolean staticRoute = false; + + //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn + if(localNextHopInfo == null) { + localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32"); + staticRoute = true; + } + + if(localNextHopInfo != null) { + localDpnId = localNextHopInfo.getDpnId(); + long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), + (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()); + List actionInfos = new ArrayList(); + + actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); + + makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW); + makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW); + + LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", + localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel()); + makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId); + + } + return localDpnId; + } + + private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) { + List actionsInfos = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); + + + createTerminatingServiceActions(dpId, (int)label, actionsInfos); + + LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}", + dpId, label, groupId); + } + + public void createTerminatingServiceActions( BigInteger destDpId, int label, List actionsInfos) { + List mkMatches = new ArrayList(); + + LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos); + + // Matching metadata + // FIXME vxlan vni bit set is not working properly with OVS.need to revisit + mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)})); + + List mkInstructions = new ArrayList(); + mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + + FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, INTERNAL_TUNNEL_TABLE, + getFlowRef(destDpId, INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label), + 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions); + + mdsalManager.installFlow(terminatingServiceTableFlowEntity); + } + + private void removeTunnelTableEntry(BigInteger dpId, long label) { + FlowEntity flowEntity; + LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label); + List mkMatches = new ArrayList(); + // Matching metadata + mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { + MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet((int)label), + MetaDataUtil.METADA_MASK_TUNNEL_ID })); + flowEntity = MDSALUtil.buildFlowEntity(dpId, + INTERNAL_TUNNEL_TABLE, + getFlowRef(dpId, INTERNAL_TUNNEL_TABLE, (int)label), + 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0, + COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null); + mdsalManager.removeFlow(flowEntity); + LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label); + } + + public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) { + BigInteger localDpnId = BigInteger.ZERO; + VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix()); + boolean staticRoute = false; + + //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn + if(localNextHopInfo == null) { + localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getNextHopAddress() + "/32"); + staticRoute = true; + } + + if(localNextHopInfo != null) { + localDpnId = localNextHopInfo.getDpnId(); + if (getPrefixToInterface(vpnId, (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()) == null) { + makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */, + NwConstants.DEL_FLOW); + makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */, + vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); + removeTunnelTableEntry(localDpnId, vrfEntry.getLabel()); + deleteLocalAdjacency(localDpnId, vpnId, (staticRoute == true) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()); + } + } + return localDpnId; + } + + private InstanceIdentifier getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) { + return InstanceIdentifier.builder(PrefixToInterface.class) + .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build(); + } + + private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) { + Optional localNextHopInfoData = + read(LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix)); + return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null; + } + + + private Class getTunnelType(String ifName) { + try { + Future> result = interfaceManager.getTunnelType( + new GetTunnelTypeInputBuilder().setIntfName(ifName).build()); + RpcResult rpcResult = result.get(); + if(!rpcResult.isSuccessful()) { + LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors()); + } else { + return rpcResult.getResult().getTunnelType(); + } + + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e); + } + + return null; + + } + private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfTablesKey vrfTableKey, + final VrfEntry vrfEntry) { String rd = vrfTableKey.getRouteDistinguisher(); LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd); - - GetEgressPointerOutput adjacency = resolveAdjacency(dpId, vpnId, vrfEntry); - long groupId = -1; - boolean isLocalRoute = false; - if(adjacency != null) { - groupId = adjacency.getEgressPointer(); - isLocalRoute = adjacency.isLocalDestination(); + /********************************************/ + String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); + if(tunnelInterface == null) { + LOG.error("Could not get interface for nexthop: {} in vpn {}", + vrfEntry.getNextHopAddress(), rd); + LOG.warn("Failed to add Route: {} in vpn: {}", + vrfEntry.getDestPrefix(), rd); + return; } - if(groupId == -1) { + List actionInfos = new ArrayList<>(); + Class tunnel_type = getTunnelType(tunnelInterface); + if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) { + LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); + actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); + actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); + } else { + int label = vrfEntry.getLabel().intValue(); + BigInteger tunnelId; + // FIXME vxlan vni bit set is not working properly with OVS.need to revisit + if(tunnel_type.equals(TunnelTypeVxlan.class)) { + tunnelId = BigInteger.valueOf(label); + } else { + tunnelId = BigInteger.valueOf(label); + } + LOG.debug("adding set tunnel id action for label {}", label); + actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{ + tunnelId})); + } + actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface)); +/* + List actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); + if(actionInfos == null) { LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}", vrfEntry.getNextHopAddress(), rd); LOG.warn("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd); return; } - - makeConnectedRoute(dpId, vpnId, vrfEntry, rd, groupId, NwConstants.ADD_FLOW); - - if (isLocalRoute) { - makeLFibTableEntry(dpId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW); + BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix()); + if(dpnId == null) { + //This route may be extra route... try to query with nexthop Ip + LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix()); + dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32"); } - + if(dpnId == null) { + LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix()); + actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); + actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); + } else { + int label = vrfEntry.getLabel().intValue(); + LOG.debug("adding set tunnel id action for label {}", label); + actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { + MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label), + MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID })); + } +**/ + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW); LOG.debug( "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId); } @@ -221,40 +429,36 @@ public class FibManager extends AbstractDataChangeListener implements Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!"); Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!"); - Long vpnId = getVpnId(vrfTableKey.getRouteDistinguisher()); - Preconditions.checkNotNull(vpnId, "Vpn Instance not available!"); - Collection dpns = vpnmanager.getDpnsForVpn(vpnId); - for (Long dpId : dpns) { - deleteRoute(dpId, vpnId, vrfTableKey, vrfEntry); + VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher()); + Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!"); + Collection vpnToDpnList = vpnInstance.getVpnToDpnList(); + BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(), + vrfTableKey.getRouteDistinguisher(), vrfEntry); + if (vpnToDpnList != null) { + for (VpnToDpnList curDpn : vpnToDpnList) { + if (!curDpn.getDpnId().equals(localDpnId)) { + deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry); + } + } + } } - public void deleteRoute(final long dpId, final long vpnId, final VrfTablesKey vrfTableKey, - final VrfEntry vrfEntry) { + public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfTablesKey vrfTableKey, + final VrfEntry vrfEntry) { LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId); String rd = vrfTableKey.getRouteDistinguisher(); - GetEgressPointerOutput adjacency = resolveAdjacency(dpId, vpnId, vrfEntry); - long groupId = -1; - boolean isLocalRoute = false; - if(adjacency != null) { - groupId = adjacency.getEgressPointer(); - isLocalRoute = adjacency.isLocalDestination(); - } - if(groupId == -1) { + String egressInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry); + if(egressInterface == null) { LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}", - vrfEntry.getNextHopAddress(), rd); - LOG.warn("Failed to add Route: {} in vpn: {}", - vrfEntry.getDestPrefix(), rd); + vrfEntry.getNextHopAddress(), rd); + LOG.warn("Failed to delete Route: {} in vpn: {}", + vrfEntry.getDestPrefix(), rd); return; } - makeConnectedRoute(dpId, vpnId, vrfEntry, rd, groupId, NwConstants.DEL_FLOW); - - if (isLocalRoute) { - makeLFibTableEntry(dpId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW); - deleteLocalAdjacency(dpId, vpnId, vrfEntry); - } - + makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW); LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId); } @@ -263,18 +467,18 @@ public class FibManager extends AbstractDataChangeListener implements + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL; } - private void makeConnectedRoute(long dpId, long vpnId, VrfEntry vrfEntry, String rd, - long groupId, int addOrRemove) { + private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd, + List actionInfos, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry); String values[] = vrfEntry.getDestPrefix().split("/"); String ipAddress = values[0]; - int prefixLength = (values.length == 1) ? 32 : Integer.parseInt(values[1]); + int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]); LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength); InetAddress destPrefix = null; try { destPrefix = InetAddress.getByName(ipAddress); } catch (UnknownHostException e) { - LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix()); + LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix()); return; } @@ -292,13 +496,8 @@ public class FibManager extends AbstractDataChangeListener implements } List instructions = new ArrayList(); - List actionsInfos = new ArrayList(); - if(addOrRemove == NwConstants.ADD_FLOW) { - actionsInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null })); - actionsInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())})); - actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)})); - instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos)); } String flowRef = getFlowRef(dpId, L3_FIB_TABLE, rd, destPrefix); @@ -311,13 +510,22 @@ public class FibManager extends AbstractDataChangeListener implements COOKIE_VM_FIB_TABLE, matches, instructions); if (addOrRemove == NwConstants.ADD_FLOW) { + /* We need to call sync API to install flow so that 2 DS operations on the same object do not + * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait + * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows, + * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means + * wait indefinitely. */ + // FIXME: sync calls. + //mdsalManager.syncInstallFlow(flowEntity, 1); mdsalManager.installFlow(flowEntity); } else { + // FIXME: sync calls. + // mdsalManager.syncRemoveFlow(flowEntity, 1); mdsalManager.removeFlow(flowEntity); } } - private void makeLFibTableEntry(long dpId, long label, long groupId, + private void makeLFibTableEntry(BigInteger dpId, long label, long groupId, String nextHop, int addOrRemove) { List matches = new ArrayList(); matches.add(new MatchInfo(MatchFieldType.eth_type, @@ -326,6 +534,7 @@ public class FibManager extends AbstractDataChangeListener implements List instructions = new ArrayList(); List actionsInfos = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{})); actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) })); instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); @@ -338,51 +547,54 @@ public class FibManager extends AbstractDataChangeListener implements COOKIE_VM_LFIB_TABLE, matches, instructions); if (addOrRemove == NwConstants.ADD_FLOW) { + /* We need to call sync API to install flow so that 2 DS operations on the same object do not + * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait + * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows, + * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means + * wait indefinitely. */ + + // FIXME: + // mdsalManager.syncInstallFlow(flowEntity, 1); mdsalManager.installFlow(flowEntity); } else { + // FIXME: + // mdsalManager.syncRemoveFlow(flowEntity, 1); mdsalManager.removeFlow(flowEntity); } LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId ); } - private void deleteLocalAdjacency(final long dpId, final long vpnId, final VrfEntry vrfEntry) { - LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, VrfEntry {}",dpId, vpnId, vrfEntry);; + private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) { + LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress); try { - Future> result = - l3nexthopService.removeLocalNextHop(new RemoveLocalNextHopInputBuilder().setDpnId(dpId) - .setIpPrefix(vrfEntry.getDestPrefix()) - .setNexthopIp(vrfEntry.getNextHopAddress()) - .setVpnId(vpnId) - .build()); - RpcResult rpcResult = result.get(); - if (rpcResult.isSuccessful()) { - LOG.debug("Local Next hop for {} on dpn {} successfully deleted", vrfEntry.getDestPrefix(), dpId); - } else { - LOG.error("Local Next hop for {} on dpn {} not deleted", vrfEntry.getDestPrefix(), dpId); - } - } catch (NullPointerException | InterruptedException | ExecutionException e) { + nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress); + } catch (NullPointerException e) { LOG.trace("", e); } } - public void populateFibOnNewDpn(long dpnId, long vpnId, String rd) { + public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) { LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd); InstanceIdentifier id = buildVrfId(rd); - Optional vrfTable = read(LogicalDatastoreType.CONFIGURATION, id); + Optional vrfTable = read(LogicalDatastoreType.OPERATIONAL, id); if(vrfTable.isPresent()) { for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { - addRouteInternal(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); + // Passing null as we don't know the dpn + // to which prefix is attached at this point + createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); } } } - public void cleanUpDpnForVpn(long dpnId, long vpnId, String rd) { + public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) { LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd); InstanceIdentifier id = buildVrfId(rd); - Optional vrfTable = read(LogicalDatastoreType.CONFIGURATION, id); + Optional vrfTable = read(LogicalDatastoreType.OPERATIONAL, id); if(vrfTable.isPresent()) { for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { - deleteRoute(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); + // Passing null as we don't know the dpn + // to which prefix is attached at this point + deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry); } } } @@ -394,74 +606,57 @@ public class FibManager extends AbstractDataChangeListener implements return id; } - private String getFlowRef(long dpnId, short tableId, long label, String nextHop) { + private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) { return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) .append(tableId).append(NwConstants.FLOWID_SEPARATOR) .append(label).append(NwConstants.FLOWID_SEPARATOR) .append(nextHop).toString(); } - private String getFlowRef(long dpnId, short tableId, String rd, InetAddress destPrefix) { + private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) { return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) .append(tableId).append(NwConstants.FLOWID_SEPARATOR) .append(rd).append(NwConstants.FLOWID_SEPARATOR) .append(destPrefix.getHostAddress()).toString(); } - private GetEgressPointerOutput resolveAdjacency(final long dpId, final long vpnId, - final VrfEntry vrfEntry) { - GetEgressPointerOutput adjacency = null; - LOG.trace("resolveAdjacency called with dpid {}, vpnId{}, VrfEntry {}",dpId, vpnId, vrfEntry);; + protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId, + final long vpnId, final VrfEntry vrfEntry) { + String adjacency = null; + LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);; try { - Future> result = - l3nexthopService.getEgressPointer(new GetEgressPointerInputBuilder().setDpnId(dpId) - .setIpPrefix(vrfEntry.getDestPrefix()) - .setNexthopIp(vrfEntry.getNextHopAddress()) - .setVpnId(vpnId) - .build()); - RpcResult rpcResult = result.get(); - if (rpcResult.isSuccessful()) { - adjacency = rpcResult.getResult(); - } else { - LOG.error("Next hop information not available"); - } - } catch (NullPointerException | InterruptedException | ExecutionException e) { + adjacency = + nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId, + vrfEntry.getDestPrefix(), + vrfEntry.getNextHopAddress()); + } catch (NullPointerException e) { LOG.trace("", e); } return adjacency; } - private Long getVpnId(String rd) { - Long vpnId = null; - InstanceIdentifier id = InstanceIdentifier.create(VpnInstances.class); - Optional vpnInstances = read(LogicalDatastoreType.OPERATIONAL, id); - if(vpnInstances.isPresent()) { - List vpns = vpnInstances.get().getVpnInstance(); - for(VpnInstance vpn : vpns) { - if(vpn.getIpv4Family().getRouteDistinguisher().equals(rd)) { - VpnInstance1 vpnInstanceId = vpn.getAugmentation(VpnInstance1.class); - if (vpnInstanceId != null) { - vpnId = vpnInstanceId.getVpnId(); - break; - } - } - } + protected VpnInstanceOpDataEntry getVpnInstance(String rd) { + InstanceIdentifier id = InstanceIdentifier.create(VpnInstanceOpData.class).child( + VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)); + Optional vpnInstanceOpData = read(LogicalDatastoreType.OPERATIONAL, id); + if(vpnInstanceOpData.isPresent()) { + return vpnInstanceOpData.get(); } - return vpnId; + return null; } - public void processNodeAdd(long dpnId) { + public void processNodeAdd(BigInteger dpnId) { LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId); makeTableMissFlow(dpnId, NwConstants.ADD_FLOW); + makeProtocolTableFlow(dpnId, NwConstants.ADD_FLOW); + makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW); } - private void makeTableMissFlow(long dpnId, int addOrRemove) { + private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) { final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); - // Instruction to punt to controller + // Instruction to goto L3 InterfaceTable List instructions = new ArrayList(); - List actionsInfos = new ArrayList(); - actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {})); - instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { L3_INTERFACE_TABLE })); List matches = new ArrayList(); FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, L3_LFIB_TABLE, getFlowRef(dpnId, L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW), @@ -482,9 +677,81 @@ public class FibManager extends AbstractDataChangeListener implements } } - private String getFlowRef(long dpnId, short tableId, int tableMiss) { + private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) { return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR) .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss) .append(FLOWID_PREFIX).toString(); } + + /* + * Install flow entry in protocol table to forward mpls + * coming through gre tunnel to LFIB table. + */ + private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) { + final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16); + // Instruction to goto L3 InterfaceTable + List instructions = new ArrayList<>(); + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {L3_LFIB_TABLE})); + List matches = new ArrayList(); + matches.add(new MatchInfo(MatchFieldType.eth_type, + new long[] { 0x8847L })); + FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, L3_PROTOCOL_TABLE, + getFlowRef(dpnId, L3_PROTOCOL_TABLE, + L3_LFIB_TABLE), + DEFAULT_FIB_FLOW_PRIORITY, + "Protocol Table For LFIB", + 0, 0, + COOKIE_PROTOCOL_TABLE, + matches, instructions); + + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId); + mdsalManager.installFlow(flowEntityToLfib); + } else { + mdsalManager.removeFlow(flowEntityToLfib); + } + } + + public List printFibEntries() { + List result = new ArrayList(); + result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label")); + result.add("-------------------------------------------------------------------"); + InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); + Optional fibEntries = read(LogicalDatastoreType.OPERATIONAL, id); + if (fibEntries.isPresent()) { + List vrfTables = fibEntries.get().getVrfTables(); + for (VrfTables vrfTable : vrfTables) { + for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) { + result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(), + vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel())); + } + } + } + return result; + } + + private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) { + List instructions = new ArrayList(); + List matches = new ArrayList(); + final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16); + // Instruction to clear metadata except SI and LportTag bits + instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { + CLEAR_METADATA, METADATA_MASK_CLEAR })); + // Instruction to clear action + instructions.add(new InstructionInfo(InstructionType.clear_actions)); + // Instruction to goto L3 InterfaceTable + + instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { LPORT_DISPATCHER_TABLE })); + + FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, L3_INTERFACE_TABLE, + getFlowRef(dpnId, L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW), + NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions); + if (addOrRemove == NwConstants.ADD_FLOW) { + LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries"); + mdsalManager.installFlow(flowEntityL3Intf); + } else { + mdsalManager.removeFlow(flowEntityL3Intf); + } + } + }