X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=openstack%2Fnet-virt-providers%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fovsdb%2Fopenstack%2Fnetvirt%2Fproviders%2Fopenflow13%2Fservices%2Farp%2FGatewayMacResolverService.java;h=af75afb5da777d40349a261cf96cfdf94d9314a1;hb=9b4ce3667cd845b5454c8ec897cd659568775054;hp=70ff81a4fcb66a9f19d64f3a946dad5e081801a6;hpb=0417f7f353cbfc114e17d8263a18bbd7254f31bc;p=netvirt.git diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java index 70ff81a4fc..af75afb5da 100644 --- a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java +++ b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/arp/GatewayMacResolverService.java @@ -7,30 +7,24 @@ */ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.math.BigInteger; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -import javax.annotation.Nullable; - +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.JdkFutureAdapters; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.openflowplugin.api.OFConstants; +import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService; import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolver; +import org.opendaylight.ovsdb.openstack.netvirt.api.GatewayMacResolverListener; +import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager; import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface; import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider; import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance; import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; @@ -74,14 +68,21 @@ import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.JdkFutureAdapters; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import static com.google.common.base.Preconditions.checkNotNull; /** * @@ -92,7 +93,6 @@ public class GatewayMacResolverService extends AbstractServiceInstance implements ConfigInterface, GatewayMacResolver,PacketProcessingListener { private static final Logger LOG = LoggerFactory.getLogger(GatewayMacResolverService.class); - private static final short TABEL_FOR_ARP_FLOW = 0; private static final String ARP_REPLY_TO_CONTROLLER_FLOW_NAME = "GatewayArpReplyRouter"; private static final int ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY = 10000; private static final Instruction SEND_TO_CONTROLLER_INSTRUCTION; @@ -100,15 +100,17 @@ public class GatewayMacResolverService extends AbstractServiceInstance private SalFlowService flowService; private final AtomicLong flowCookie = new AtomicLong(); private final ConcurrentMap gatewayToArpMetadataMap = - new ConcurrentHashMap(); - private final int ARP_WATCH_BROTHERS = 10; - private final int WAIT_CYCLES = 3; - private final int PER_CYCLE_WAIT_DURATION = 1000; - private final int REFRESH_INTERVAL = 10; + new ConcurrentHashMap<>(); + private static final int ARP_WATCH_BROTHERS = 10; + private static final int WAIT_CYCLES = 3; + private static final int PER_CYCLE_WAIT_DURATION = 1000; + private static final int REFRESH_INTERVAL = 10; private final ListeningExecutorService arpWatcherWall = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(ARP_WATCH_BROTHERS)); private final ScheduledExecutorService gatewayMacRefresherPool = Executors.newScheduledThreadPool(1); private final ScheduledExecutorService refreshRequester = Executors.newSingleThreadScheduledExecutor(); private AtomicBoolean initializationDone = new AtomicBoolean(false); + private volatile ConfigurationService configurationService; + private volatile NodeCacheManager nodeCacheManager; static { ApplyActions applyActions = new ApplyActionsBuilder().setAction( @@ -147,7 +149,9 @@ public class GatewayMacResolverService extends AbstractServiceInstance if (!gatewayToArpMetadataMap.isEmpty()){ for(final Entry gatewayToArpMetadataEntry : gatewayToArpMetadataMap.entrySet()){ final Ipv4Address gatewayIp = gatewayToArpMetadataEntry.getKey(); - final ArpResolverMetadata gatewayMetaData = gatewayToArpMetadataEntry.getValue(); + final ArpResolverMetadata gatewayMetaData = + checkAndGetExternalBridgeDpid( + resetFlowToRemove(gatewayIp, gatewayToArpMetadataEntry.getValue())); gatewayMacRefresherPool.schedule(new Runnable(){ @Override @@ -156,13 +160,15 @@ public class GatewayMacResolverService extends AbstractServiceInstance final Node externalNetworkBridge = getExternalBridge(gatewayMetaData.getExternalNetworkBridgeDpid()); if(externalNetworkBridge == null){ LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} " - + "is not connected to controller.",gatewayIp.getValue(),gatewayMetaData.getExternalNetworkBridgeDpid() ); + + "is not connected to controller.", + gatewayIp.getValue(), + gatewayMetaData.getExternalNetworkBridgeDpid() ); + } else { + LOG.debug("Refresh Gateway Mac for gateway {} using source ip {} and mac {} for ARP request", + gatewayIp.getValue(),gatewayMetaData.getArpRequestSourceIp().getValue(),gatewayMetaData.getArpRequestSourceMacAddress().getValue()); + + sendGatewayArpRequest(externalNetworkBridge,gatewayIp,gatewayMetaData.getArpRequestSourceIp(), gatewayMetaData.getArpRequestSourceMacAddress()); } - - LOG.debug("Refresh Gateway Mac for gateway {} using source ip {} and mac {} for ARP request", - gatewayIp.getValue(),gatewayMetaData.getArpRequestSourceIp().getValue(),gatewayMetaData.getArpRequestMacAddress().getValue()); - - sendGatewayArpRequest(externalNetworkBridge,gatewayIp,gatewayMetaData.getArpRequestSourceIp(), gatewayMetaData.getArpRequestMacAddress()); } }, 1, TimeUnit.SECONDS); } @@ -182,13 +188,15 @@ public class GatewayMacResolverService extends AbstractServiceInstance * @param sourceIpAddress Source Ip address for the ARP request packet * @param sourceMacAddress Source Mac address for the ARP request packet * @param periodicRefresh Enable/Disable periodic refresh of the Gateway Mac address - * NOTE:Periodic refresh is not supported yet. - * @param gatewayIp Resolve MAC address of this Gateway Ip * @return Future object */ @Override - public ListenableFuture resolveMacAddress( final Long externalNetworkBridgeDpid, final Ipv4Address gatewayIp, - final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, final Boolean periodicRefresh){ + public ListenableFuture resolveMacAddress( + final GatewayMacResolverListener gatewayMacResolverListener, final Long externalNetworkBridgeDpid, + final Boolean refreshExternalNetworkBridgeDpidIfNeeded, + final Ipv4Address gatewayIp, final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress, + final Boolean periodicRefresh){ + Preconditions.checkNotNull(refreshExternalNetworkBridgeDpidIfNeeded); Preconditions.checkNotNull(sourceIpAddress); Preconditions.checkNotNull(sourceMacAddress); Preconditions.checkNotNull(gatewayIp); @@ -208,15 +216,21 @@ public class GatewayMacResolverService extends AbstractServiceInstance }); } }else{ - gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata( - externalNetworkBridgeDpid, gatewayIp,sourceIpAddress,sourceMacAddress,periodicRefresh)); + gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata(gatewayMacResolverListener, + externalNetworkBridgeDpid, refreshExternalNetworkBridgeDpidIfNeeded, + gatewayIp, sourceIpAddress, sourceMacAddress, periodicRefresh)); } final Node externalNetworkBridge = getExternalBridge(externalNetworkBridgeDpid); - if(externalNetworkBridge == null){ - LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} " - + "is not connected to controller.",gatewayIp.getValue(),externalNetworkBridgeDpid ); + if (externalNetworkBridge == null) { + if (!refreshExternalNetworkBridgeDpidIfNeeded) { + LOG.error("MAC address for gateway {} can not be resolved, because external bridge {} " + + "is not connected to controller.", gatewayIp.getValue(), externalNetworkBridgeDpid); + } else { + LOG.debug("MAC address for gateway {} can not be resolved, since dpid was not refreshed yet", + gatewayIp.getValue()); + } return null; } @@ -227,9 +241,62 @@ public class GatewayMacResolverService extends AbstractServiceInstance } private Node getExternalBridge(final Long externalNetworkBridgeDpid){ - final String nodeName = OPENFLOW + externalNetworkBridgeDpid; + if (externalNetworkBridgeDpid != null) { + final String nodeName = OPENFLOW + externalNetworkBridgeDpid; + return getOpenFlowNode(nodeName); + } + return null; + } + + private ArpResolverMetadata checkAndGetExternalBridgeDpid(ArpResolverMetadata gatewayMetaData) { + final Long origDpid = gatewayMetaData.getExternalNetworkBridgeDpid(); + + // If we are not allowing dpid to change, there is nothing further to do here + if (!gatewayMetaData.isRefreshExternalNetworkBridgeDpidIfNeeded()) { + return gatewayMetaData; + } + + // If current dpid is null, or if mac is not getting resolved, make an attempt to + // grab a different dpid, so a different (or updated) external bridge gets used + if (origDpid == null || !gatewayMetaData.isGatewayMacAddressResolved()) { + Long newDpid = getAnotherExternalBridgeDpid(origDpid); + gatewayMetaData.setExternalNetworkBridgeDpid(newDpid); + } + + return gatewayMetaData; + } + + private Long getAnotherExternalBridgeDpid(final Long unwantedDpid) { + LOG.trace("Being asked to find a new dpid. unwantedDpid:{} cachemanager:{} configurationService:{}", + unwantedDpid, nodeCacheManager, configurationService); + + if (nodeCacheManager == null) { + LOG.error("Unable to find external dpid to use for resolver: no nodeCacheManager"); + return unwantedDpid; + } + if (configurationService == null) { + LOG.error("Unable to find external dpid to use for resolver: no configurationService"); + return unwantedDpid; + } + + // Pickup another dpid in list that is different than the unwanted one provided and is in the + // operational tree. If none can be found, return the provided dpid as a last resort. + // NOTE: We are assuming that all the br-ex are serving one external network and gateway ip of + // the external network is reachable from every br-ex + // TODO: Consider other deployment scenario, and think of another solution. + List dpids = nodeCacheManager.getBridgeDpids(configurationService.getExternalBridgeName()); + Collections.shuffle(dpids); + for (Long dpid : dpids) { + if (dpid == null || dpid.equals(unwantedDpid) || getExternalBridge(dpid) == null) { + continue; + } + + LOG.debug("Gateway Mac Resolver Service will use dpid {}", dpid); + return dpid; + } - return getOpenFlowNode(nodeName); + LOG.warn("Unable to find usable external dpid for resolver. Best choice is still {}", unwantedDpid); + return unwantedDpid; } private void sendGatewayArpRequest(final Node externalNetworkBridge,final Ipv4Address gatewayIp, @@ -260,16 +327,24 @@ public class GatewayMacResolverService extends AbstractServiceInstance } LOG.debug("Flow to route ARP Reply to Controller installed successfully : {}", flowIid); + ArpResolverMetadata gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp); + if (gatewayArpMetadata == null) { + LOG.warn("No metadata found for gatewayIp: {}", gatewayIp); + return; + } + //cache metadata - gatewayToArpMetadataMap.get(gatewayIp).setFlowToRemove( - new RemoveFlowInputBuilder(arpReplyToControllerFlow).setNode(nodeRef).build()); + gatewayArpMetadata.setFlowToRemove(new RemoveFlowInputBuilder(arpReplyToControllerFlow).setNode(nodeRef).build()); - //Broadcast ARP request packets + //get MAC DA for ARP packets + MacAddress arpRequestDestMacAddress = gatewayArpMetadata.getArpRequestDestMacAddress(); + + //Send ARP request packets for (NodeConnector egressNc : externalNetworkBridge.getNodeConnector()) { KeyedInstanceIdentifier egressNcIid = nodeIid.child( NodeConnector.class, new NodeConnectorKey(egressNc.getId())); ListenableFuture> futureSendArpResult = arpSender.sendArp( - senderAddress, gatewayIp, egressNcIid); + senderAddress, gatewayIp, arpRequestDestMacAddress, egressNcIid); Futures.addCallback(futureSendArpResult, logResult(gatewayIp, egressNcIid)); } } @@ -295,6 +370,7 @@ public class GatewayMacResolverService extends AbstractServiceInstance ArpResolverMetadata arpResolverMetadata = gatewayToArpMetadataMap.get(gatewayIp); if(arpResolverMetadata != null && arpResolverMetadata.getGatewayMacAddress() != null){ if(!arpResolverMetadata.isPeriodicRefresh()){ + resetFlowToRemove(gatewayIp, arpResolverMetadata); return gatewayToArpMetadataMap.remove(gatewayIp).getGatewayMacAddress(); } return arpResolverMetadata.getGatewayMacAddress(); @@ -305,17 +381,10 @@ public class GatewayMacResolverService extends AbstractServiceInstance }); } - private static @Nullable Ipv4Address getIPv4Addresses(IpAddress ipAddress) { - if (ipAddress.getIpv4Address() == null) { - return null; - } - return ipAddress.getIpv4Address(); - } - private Flow createArpReplyToControllerFlow(final ArpMessageAddress senderAddress, final Ipv4Address ipForRequestedMac) { checkNotNull(senderAddress); checkNotNull(ipForRequestedMac); - FlowBuilder arpFlow = new FlowBuilder().setTableId(TABEL_FOR_ARP_FLOW) + FlowBuilder arpFlow = new FlowBuilder().setTableId(Service.CLASSIFIER.getTable()) .setFlowName(ARP_REPLY_TO_CONTROLLER_FLOW_NAME) .setPriority(ARP_REPLY_TO_CONTROLLER_FLOW_PRIORITY) .setBufferId(OFConstants.OFP_NO_BUFFER) @@ -330,15 +399,13 @@ public class GatewayMacResolverService extends AbstractServiceInstance arpFlow.setMatch(match); arpFlow.setInstructions(new InstructionsBuilder().setInstruction( ImmutableList.of(SEND_TO_CONTROLLER_INSTRUCTION)).build()); - arpFlow.setId(createFlowId(senderAddress, ipForRequestedMac)); + arpFlow.setId(createFlowId(ipForRequestedMac)); return arpFlow.build(); } - private FlowId createFlowId(ArpMessageAddress senderAddress, Ipv4Address ipForRequestedMac) { - StringBuilder sb = new StringBuilder(); - sb.append(ARP_REPLY_TO_CONTROLLER_FLOW_NAME); - sb.append("|").append(ipForRequestedMac.getValue()); - return new FlowId(sb.toString()); + private FlowId createFlowId(Ipv4Address ipForRequestedMac) { + String flowId = ARP_REPLY_TO_CONTROLLER_FLOW_NAME + "|" + ipForRequestedMac.getValue(); + return new FlowId(flowId); } private static InstanceIdentifier createFlowIid(Flow flow, InstanceIdentifier nodeIid) { @@ -387,7 +454,7 @@ public class GatewayMacResolverService extends AbstractServiceInstance if(candidateGatewayIp != null){ LOG.debug("Resolved MAC for Gateway Ip {} is {}",gatewayIpAddress.getValue(),gatewayMacAddress.getValue()); candidateGatewayIp.setGatewayMacAddress(gatewayMacAddress); - flowService.removeFlow(candidateGatewayIp.getFlowToRemove()); + resetFlowToRemove(gatewayIpAddress, candidateGatewayIp); } } } @@ -400,12 +467,36 @@ public class GatewayMacResolverService extends AbstractServiceInstance } @Override - public void setDependencies(Object impl) {} + public void setDependencies(Object impl) { + if (impl instanceof NodeCacheManager) { + nodeCacheManager = (NodeCacheManager) impl; + } else if (impl instanceof ConfigurationService) { + configurationService = (ConfigurationService) impl; + } + } @Override public void stopPeriodicRefresh(Ipv4Address gatewayIp) { init(); + resetFlowToRemove(gatewayIp, null); gatewayToArpMetadataMap.remove(gatewayIp); } + private ArpResolverMetadata resetFlowToRemove( + final Ipv4Address gatewayIp, ArpResolverMetadata gatewayArpMetadata) { + checkNotNull(gatewayIp); + + // If gatewayArpMetadata was not provided, look it up + if (gatewayArpMetadata == null) { + gatewayArpMetadata = gatewayToArpMetadataMap.get(gatewayIp); + } + if (gatewayArpMetadata != null && gatewayArpMetadata.getFlowToRemove() != null) { + LOG.debug("Flow to route ARP Reply to Controller from {} being removed from node {}", + gatewayIp, gatewayArpMetadata.getFlowToRemove().getNode()); + flowService.removeFlow(gatewayArpMetadata.getFlowToRemove()); + gatewayArpMetadata.setFlowToRemove(null); + } + return gatewayArpMetadata; + } + }