/* * Copyright (c) 2014 Cisco Systems, Inc. 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, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.destination; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; import org.opendaylight.groupbasedpolicy.dto.EgKey; import org.opendaylight.groupbasedpolicy.dto.EpKey; import org.opendaylight.groupbasedpolicy.dto.IndexedTenant; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtl; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3Gateways; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; /** * <h1>Manage the table that maps the destination address to the next hop for the * path as well as applies any relevant routing transformations (table=3)</h1> * * Sync Ep flows, every endpoint pair creates L2 and L3 flow<br> * <ul><li>Flow is external, when any {@link Endpoint} is external</li> * <li>Flow is local, when src and dst endpoint {@link EndpointFwdCtxOrdinals} are the same</li> * <li>Flow is local, when src and dst endpoint ordinals are not the same and {@link OfOverlayContext} is missing</li></ul> * Also applies to L3 * <p> * L2 Flows: * <p> * <i>External, local and remote L2 flows</i><br> * Priority = 50<br> * Matches:<br> * - dl_dst mac address {@link MacAddress}<br> * - loadReg4 {@link NxmNxReg4}<br> * Actions:<br> * - load tunnel Ipv4 (local and remote only)<br> * - loadReg2 {@link NxmNxReg2}<br> * - loadReg3 {@link NxmNxReg3}<br> * - loadReg7 (next hop) {@link NxmNxReg7}<br> * - {@link GoToTable} POLICY ENFORCER table<br> * <p> * L3 flows: * <p> * <i>External, local and remote L3 routed flows:</i><br> * Priority = 132<br> * Matches:<br> * - ip (ethertype) * - dl_dst mac address {@link MacAddress}<br> * - nw_dst ip address {@link IpAddress}<br> * - setReg6 {@link NxmNxReg6}<br> * Actions:<br> * - loadReg2 {@link NxmNxReg2}<br> * - loadReg3 {@link NxmNxReg3}<br> * - loadReg4 (tunnel destination) {@link NxmNxReg4} (remote only)<br> * - loadReg7 (next hop) {@link NxmNxReg7}<br> * - set dst mac to eth_dst {@link MacAddress}<br> * - dec_ttl {@link DecNwTtl} (local only)<br> * - {@link GoToTable} POLICY ENFORCER table * <p> * If virtual router ip is present in subnet, and subnet contains L3 context, arp flow is created<br> * <p> * <i>Router Arp flow</i><br> * Priority = 150<br> * Matches:<br> * - arp (ethertype)<br> * - arp target transport address<br> * - setReg6 {@link NxmNxReg6}<br> * Actions:<br> * - move eth_src = eth_dst<br> * - set dl_src {@link MacAddress}<br> * - load arp_op<br> * - move arp_sha = arp_tha<br> * - load arp_sha<br> * - move arp_spa = arp_tpa<br> * - load arp_spa<br> * - output:port {@link NodeConnectorId}<br> * <p> * <i>Broadcast flow (per flood domain)</i> * Priority = 140<br> * Matches:<br> * - ethernet destination {@link MacAddress} * - setReg5 {@link NxmNxReg5}<br> * Actions:<br> * - load tunnel ID<br> * - group action<br> * <p> * <i>L3 Prefix flow</i><br> * Priority = 140<br> * Matches:<br> * - ethernet destination {@link MacAddress} * - setReg5 {@link NxmNxReg5}<br> * Actions:<br> * - dl_dst {@link MacAddress}<br> * - dec_ttl<br> * - loadReg2 {@link NxmNxReg2}<br> * - loadReg3 {@link NxmNxReg3}<br> * - loadReg4 (next hop) {@link NxmNxReg4}<br> * - loadReg7 (if internal, port_num == {@link NodeConnectorId of L2 EP} ) {@link NxmNxReg7}<br> * - loadReg7 (if external, port_num = external port) {@link NxmNxReg7}<br> * - {@link GoToTable} POLICY ENFORCER table */ public class DestinationMapper extends FlowTable { private static final Logger LOG = LoggerFactory.getLogger(DestinationMapper.class); private final DestinationMapperUtils utils; private final short tableId; final Map<TenantId, HashSet<Subnet>> subnetsByTenant = new HashMap<>(); // This is the MAC address of the magical router in the sky public static final MacAddress ROUTER_MAC = new MacAddress("88:f0:31:b5:12:b5"); private static final MacAddress MULTICAST_MAC = new MacAddress("01:00:00:00:00:00"); private static final int EXTERNAL_L2 = 50; private static final int LOCAL_L2 = 50; private static final int L3_PREFIX = 100; private static final int L3_LOCAL = 132; private static final int L3_EXTERNAL = 132; private static final int ROUTER_ARP = 150; private static final int REMOTE_L2 = 50; private static final int REMOTE_L3 = 132; // Priorities private static final int DROP_FLOW = 1; private static final int BROADCAST = 140; public DestinationMapper(OfContext ctx, short tableId) { super(ctx); this.tableId = tableId; utils = new DestinationMapperUtils(ctx); } @Override public short getTableId() { return tableId; } @Override public void sync(Endpoint endpoint, OfWriter ofWriter) throws Exception { NodeId endpointNodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint); if (endpointNodeId == null) { LOG.warn("Endpoint {} has no location specified, skipped", endpoint); return; } DestinationMapperFlows flows = new DestinationMapperFlows(utils, endpointNodeId, tableId); // Do sync syncFlows(flows, endpoint, endpointNodeId, ofWriter); } @VisibleForTesting void syncFlows(DestinationMapperFlows flows, Endpoint endpoint, NodeId nodeId, OfWriter ofWriter) { // Create basic drop flow flows.dropFlow(DROP_FLOW, null, ofWriter); // Sync flows related to endpoints List<Subnet> localSubnets = utils.getLocalSubnets(nodeId); if (localSubnets != null) { // Local syncLocalFlows(flows, endpoint, localSubnets, ofWriter); // Remote & external syncEndpointFlows(flows, nodeId, endpoint, ofWriter); } // Sync router ARP flow TenantId tenantId = endpoint.getTenant(); syncArpFlow(flows, tenantId, ofWriter); // Create broadcast flow EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint); if (ordinals != null) { flows.createBroadcastFlow(BROADCAST, ordinals, MULTICAST_MAC, ofWriter); } // L3 Prefix Endpoint handling Collection<EndpointL3Prefix> prefixes = ctx.getEndpointManager().getEndpointsL3PrefixForTenant(tenantId); if (prefixes != null) { LOG.trace("DestinationMapper - Processing L3PrefixEndpoint"); syncL3PrefixFlow(flows, prefixes, tenantId, nodeId, ofWriter); } } @VisibleForTesting void syncEndpointFlows(DestinationMapperFlows flows, NodeId nodeId, Endpoint endpoint, OfWriter ofWriter) { SetMultimap<EpKey, EpKey> visited = HashMultimap.create(); Set<EndpointGroupId> groupIds = utils.getAllEndpointGroups(endpoint); for (EndpointGroupId groupId : groupIds) { EgKey groupKey = new EgKey(endpoint.getTenant(), groupId); Set<EgKey> peers = Sets.union(Collections.singleton(groupKey), ctx.getCurrentPolicy().getPeers(groupKey)); for (EgKey peer : peers) { Collection<Endpoint> endpointsForGroup = new HashSet<>(); endpointsForGroup.addAll(ctx.getEndpointManager().getEndpointsForGroup(peer)); endpointsForGroup.addAll(ctx.getEndpointManager().getExtEpsNoLocForGroup(peer)); for (Endpoint peerEndpoint : endpointsForGroup) { subnetsByTenant.put(peerEndpoint.getTenant(), utils.getSubnets(endpoint.getTenant())); EpKey epKey = new EpKey(endpoint.getL2Context(), endpoint.getMacAddress()); EpKey peerEpKey = new EpKey(peerEndpoint.getL2Context(), peerEndpoint.getMacAddress()); if (visited.get(epKey) != null && visited.get(epKey).contains(peerEpKey)) { continue; } // Basic checks IndexedTenant endpointTenant = utils.getIndexedTenant(endpoint.getTenant()); IndexedTenant peerTenant = utils.getIndexedTenant(peerEndpoint.getTenant()); if (endpointTenant == null || peerTenant == null) { LOG.debug("Source or destination endpoint references empty tenant. SrcEp: {} DestEp: {}", endpointTenant, peerTenant); continue; } EndpointFwdCtxOrdinals endpointOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint); EndpointFwdCtxOrdinals peerOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, peerEndpoint); if (endpointOrdinals == null || peerOrdinals == null) { LOG.debug("Source od destination endpoint ordinals are null. SrcOrdinals: {} DestOrdinals: {}", endpointOrdinals, peerOrdinals); continue; } if (peerEndpoint.getEndpointGroup() == null && peerEndpoint.getEndpointGroups() == null) { LOG.debug("Didn't process endpoint {} due to EPG(s) being null", peerEndpoint.getKey()); continue; } List<Subnet> localSubnets = utils.getLocalSubnets(nodeId); if (localSubnets == null) { LOG.error("No subnets could be found locally for node: {}", nodeId); continue; } OfOverlayContext peerContext = peerEndpoint.getAugmentation(OfOverlayContext.class); Subnet epSubnet = endpointTenant.resolveSubnet(new SubnetId(endpoint.getNetworkContainment())); Endpoint l2GatewayEp = utils.getL2EpOfSubnetGateway(endpoint.getTenant(), epSubnet); boolean peerEpIsExternal = peerEndpoint.getNetworkContainment() != null && EndpointManager.isExternal(peerEndpoint, peerTenant.getExternalImplicitGroups()); boolean subnetGwIsExternal = l2GatewayEp != null && EndpointManager.isExternal(l2GatewayEp, utils.getIndexedTenant(endpoint.getTenant()).getExternalImplicitGroups()); // Sync external if (peerEpIsExternal || subnetGwIsExternal) { Set<NodeConnectorId> externalPorts = ctx.getSwitchManager().getExternalPorts(nodeId); syncExternalFlows(flows, endpoint, peerEndpoint, l2GatewayEp, externalPorts, ofWriter); // Sync remote } else if (peerContext != null && !Objects.equals(peerContext.getNodeId(), nodeId)) { syncRemoteFlows(flows, endpoint, peerEndpoint, peerContext, nodeId, endpointOrdinals, peerOrdinals, localSubnets, ofWriter); } visited.put(epKey, peerEpKey); } } } } @VisibleForTesting void syncArpFlow(DestinationMapperFlows flows, TenantId tenantId, OfWriter ofWriter) { for (Entry<TenantId, HashSet<Subnet>> subnetEntry : subnetsByTenant.entrySet()) { for (Subnet subnet : subnetEntry.getValue()) { IndexedTenant tenant = ctx.getTenant(tenantId); L3Context l3Context = utils.getL3ContextForSubnet(tenant, subnet); if (subnet == null || subnet.getVirtualRouterIp() == null) { LOG.trace("Arp flow not created, subnet or its virtual router is null. Subnet Id: {}", subnet); continue; } try { if (l3Context != null && l3Context.getId() != null && tenant != null) { flows.createRouterArpFlow(ROUTER_ARP, tenant, subnet, ofWriter); } } catch (Exception e) { LOG.error("Failed to get context ordinal from tenant Id {} and L3 Context Id {}", tenantId, l3Context.getId()); } } } } @VisibleForTesting void syncL3PrefixFlow(DestinationMapperFlows flows, Collection<EndpointL3Prefix> l3Prefixes, TenantId tenantId, NodeId nodeId, OfWriter ofWriter) { short policyEnforcerTableId = ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(); for (EndpointL3Prefix l3Prefix : l3Prefixes) { List<Subnet> localSubnets = utils.getLocalSubnets(nodeId); if (localSubnets != null) { for (Subnet localSubnet : localSubnets) { for (EndpointL3Gateways l3Gateway : l3Prefix.getEndpointL3Gateways()) { if (l3Gateway != null && l3Gateway.getL3Context() != null && l3Gateway.getIpAddress() != null) { EndpointL3 endpointL3 = ctx.getEndpointManager().getL3Endpoint(l3Gateway.getL3Context(), l3Gateway.getIpAddress(), tenantId); Endpoint endpointL2 = ctx.getEndpointManager().getL2EndpointFromL3(endpointL3); IndexedTenant tenant = ctx.getTenant(l3Prefix.getTenant()); Set<NodeConnectorId> externalPorts = ctx.getSwitchManager().getExternalPorts(nodeId); if (endpointL3 != null && endpointL2 != null && tenant != null && externalPorts != null) { L3Context l3Context = utils.getL3ContextForSubnet(tenant, localSubnet); if (l3Context == null || l3Context.getId() == null) { LOG.error("No L3 Context found associated with subnet {}", localSubnet.getId()); continue; } EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpointL2); if (ordinals == null) { LOG.error("No Fwd Ctx ordinals found in endpoint ", endpointL2); continue; } flows.createL3PrefixFlow(policyEnforcerTableId, L3_PREFIX, endpointL2, l3Prefix, tenant, localSubnet, externalPorts, ofWriter); } } } } } } } private void syncExternalFlows(DestinationMapperFlows flows, Endpoint endpoint, Endpoint peerEndpoint, Endpoint gatewayEndpoint, Set<NodeConnectorId> externalPorts, OfWriter ofWriter) { EndpointFwdCtxOrdinals peerOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, peerEndpoint); if (peerOrdinals == null) { return; } short goToTable = ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(); if (endpoint.getNetworkContainment().equals(peerEndpoint.getNetworkContainment())) { if (externalPorts.iterator().hasNext()) { // L2 flow flows.createExternalL2Flow(goToTable, EXTERNAL_L2, peerEndpoint, externalPorts, ofWriter); } } else if (gatewayEndpoint != null) { HashSet<Subnet> subnets = utils.getSubnets(peerEndpoint.getTenant()); if (subnets == null) { LOG.trace("No subnets in tenant {}", peerEndpoint.getTenant()); return; } for (L3Address l3Address : endpoint.getL3Address()) { if (l3Address.getIpAddress() == null || l3Address.getL3Context() == null) { LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}", endpoint.getL3Address()); continue; } // L3 flow flows.createExternalL3RoutedFlow(goToTable, L3_EXTERNAL, peerEndpoint, gatewayEndpoint, l3Address, externalPorts, ofWriter); } } } private void syncLocalFlows(DestinationMapperFlows flows, Endpoint endpoint, List<Subnet> localSubnets, OfWriter ofWriter) { short goToTable = ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(); // L2 Flow flows.createLocalL2Flow(goToTable, LOCAL_L2, endpoint, ofWriter); if (endpoint.getL3Address() == null) { LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", endpoint.getKey()); return; } for (L3Address l3Address : endpoint.getL3Address()) { if (l3Address.getIpAddress() == null || l3Address.getL3Context() == null) { LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}", endpoint.getL3Address()); } else { for (Subnet localSubnet : localSubnets) { HashSet<Subnet> subnets = utils.getSubnets(endpoint.getTenant()); if (subnets == null) { LOG.trace("No subnets in tenant {}", utils.getIndexedTenant(endpoint.getTenant())); continue; } Subnet remoteSubnet = ctx.getTenant(endpoint.getTenant()) .resolveSubnet(new SubnetId(endpoint.getNetworkContainment())); // Do check if(checked(localSubnet, remoteSubnet, l3Address, endpoint)) { // L3 flow flows.createLocalL3RoutedFlow(goToTable, L3_LOCAL, endpoint, l3Address, localSubnet, remoteSubnet, ofWriter); } } } } } private void syncRemoteFlows(DestinationMapperFlows flows, Endpoint endpoint, Endpoint peerEndpoint, OfOverlayContext ofc, NodeId nodeId, EndpointFwdCtxOrdinals endpointOrdinals, EndpointFwdCtxOrdinals peerOrdinals, List<Subnet> localSubnets, OfWriter ofWriter) { short goToTable = ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(); if (endpointOrdinals.getBdId() == peerOrdinals.getBdId()) { IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class); NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class); // L2 flow if (tunDst != null && tunPort != null) { flows.createRemoteL2Flow(goToTable, REMOTE_L2, endpoint, peerEndpoint, tunDst, tunPort, ofWriter); } } else { LOG.trace("DestinationMapper: RemoteL2Flow: not created, in different BDs src: {} dst: {}", endpointOrdinals.getBdId(), peerOrdinals.getBdId()); } if (peerEndpoint.getL3Address() == null) { LOG.trace("Endpoint {} didn't have L3 Address so was not processed for L3 flows.", peerEndpoint.getKey()); return; } for (L3Address l3Address : peerEndpoint.getL3Address()) { if (l3Address.getIpAddress() == null || l3Address.getL3Context() == null) { LOG.error("Endpoint with L3Address but either IPAddress or L3Context is null. {}", peerEndpoint.getL3Address()); } else { for (Subnet localSubnet : localSubnets) { HashSet<Subnet> subnets = utils.getSubnets(peerEndpoint.getTenant()); if (subnets == null) { LOG.trace("No subnets in tenant {}", peerEndpoint.getTenant()); return; } Subnet remoteSubnet = ctx.getTenant(peerEndpoint.getTenant()) .resolveSubnet(new SubnetId(peerEndpoint.getNetworkContainment())); // Do check if(checked(localSubnet, remoteSubnet, l3Address, peerEndpoint)) { IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(ofc.getNodeId(), TunnelTypeVxlan.class); NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class); // L3 flow if (tunDst != null && tunPort != null) { flows.createRemoteL3RoutedFlow(goToTable, REMOTE_L3, peerEndpoint, l3Address, remoteSubnet, tunDst, tunPort, localSubnet, ofWriter); } } } } } } private boolean checked(Subnet localSubnet, Subnet remoteSubnet, L3Address l3Address, Endpoint peerEndpoint) { if(peerEndpoint.getTenant() == null) { LOG.trace("Endpoint {} does not contain info about tenant", peerEndpoint.getKey()); return false; } if (remoteSubnet == null) { LOG.trace("Destination IP address does not match any subnet in tenant {}", l3Address.getIpAddress()); return false; } if (remoteSubnet.getVirtualRouterIp() == null) { LOG.trace("Destination subnet {} for Endpoint {}.{} has no gateway IP", remoteSubnet.getIpPrefix(), peerEndpoint, l3Address.getKey()); return false; } if (localSubnet.getVirtualRouterIp() == null) { LOG.trace("Local subnet {} has no gateway IP", localSubnet.getIpPrefix()); return false; } L3Context destL3c = utils.getL3ContextForSubnet(ctx.getTenant(peerEndpoint.getTenant()), remoteSubnet); if (destL3c == null || destL3c.getId() == null) { LOG.error("No L3 Context found associated with subnet {}", remoteSubnet.getId()); return false; } L3Context srcL3c = utils.getL3ContextForSubnet(ctx.getTenant(peerEndpoint.getTenant()), localSubnet); if (srcL3c == null || srcL3c.getId() == null) { LOG.error("No L3 Context found associated with subnet {}", localSubnet.getId()); return false; } if (!(srcL3c.getId().getValue().equals(destL3c.getId().getValue()))) { LOG.trace("Trying to route between two L3Contexts {} and {}. Not currently supported.", srcL3c.getId() .getValue(), destL3c.getId().getValue()); return false; } return true; } }