public final class ArpResolverMetadata {
+ private final Ipv4Address gatewayIpAddress;
+ private final Long externalNetworkBridgeDpid;
+ private final Ipv4Address arpRequestSourceIp;
+ private final MacAddress arpRequestSourceMacAddress;
+ private final boolean periodicRefresh;
private RemoveFlowInput flowToRemove;
- private Ipv4Address gatewayIpAddress;
private MacAddress gatewayMacAddress;
- private boolean periodicRefresh;
- public ArpResolverMetadata(){
-
- }
- public ArpResolverMetadata(RemoveFlowInput flowToRemove, Ipv4Address gatewayIpAddress, boolean periodicRefresh){
- this.flowToRemove = flowToRemove;
+ public ArpResolverMetadata(final Long externalNetworkBridgeDpid,
+ final Ipv4Address gatewayIpAddress, final Ipv4Address arpRequestSourceIp,
+ final MacAddress arpRequestMacAddress, final boolean periodicRefresh){
+ this.externalNetworkBridgeDpid = externalNetworkBridgeDpid;
this.gatewayIpAddress = gatewayIpAddress;
- this.periodicRefresh = periodicRefresh;
- }
-
- public ArpResolverMetadata(RemoveFlowInput flowToRemove, Ipv4Address gatewayIpAddress, MacAddress gatewayMacAddress, boolean periodicRefresh){
- this.flowToRemove = flowToRemove;
- this.gatewayIpAddress = gatewayIpAddress;
- this.gatewayMacAddress = gatewayMacAddress;
+ this.arpRequestSourceIp = arpRequestSourceIp;
+ this.arpRequestSourceMacAddress = arpRequestMacAddress;
this.periodicRefresh = periodicRefresh;
}
public boolean isPeriodicRefresh() {
return periodicRefresh;
}
- public void setPeriodicRefresh(boolean periodicRefresh) {
- this.periodicRefresh = periodicRefresh;
- }
public void setFlowToRemove(RemoveFlowInput flowToRemove) {
this.flowToRemove = flowToRemove;
}
public Ipv4Address getGatewayIpAddress() {
return gatewayIpAddress;
}
- public void setGatewayIpAddress(Ipv4Address gatewayIpAddress) {
- this.gatewayIpAddress = gatewayIpAddress;
- }
public MacAddress getGatewayMacAddress() {
return gatewayMacAddress;
}
this.gatewayMacAddress = gatewayMacAddress;
}
+ public Long getExternalNetworkBridgeDpid() {
+ return externalNetworkBridgeDpid;
+ }
+ public Ipv4Address getArpRequestSourceIp() {
+ return arpRequestSourceIp;
+ }
+ public MacAddress getArpRequestMacAddress() {
+ return arpRequestSourceMacAddress;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime
+ * result
+ + ((arpRequestSourceMacAddress == null) ? 0 : arpRequestSourceMacAddress
+ .hashCode());
+ result = prime
+ * result
+ + ((arpRequestSourceIp == null) ? 0 : arpRequestSourceIp
+ .hashCode());
+ result = prime
+ * result
+ + ((externalNetworkBridgeDpid == null) ? 0
+ : externalNetworkBridgeDpid.hashCode());
+ result = prime
+ * result
+ + ((gatewayIpAddress == null) ? 0 : gatewayIpAddress.hashCode());
+ result = prime * result + (periodicRefresh ? 1231 : 1237);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ArpResolverMetadata other = (ArpResolverMetadata) obj;
+ if (arpRequestSourceMacAddress == null) {
+ if (other.arpRequestSourceMacAddress != null)
+ return false;
+ } else if (!arpRequestSourceMacAddress.equals(other.arpRequestSourceMacAddress))
+ return false;
+ if (arpRequestSourceIp == null) {
+ if (other.arpRequestSourceIp != null)
+ return false;
+ } else if (!arpRequestSourceIp.equals(other.arpRequestSourceIp))
+ return false;
+ if (externalNetworkBridgeDpid == null) {
+ if (other.externalNetworkBridgeDpid != null)
+ return false;
+ } else if (!externalNetworkBridgeDpid
+ .equals(other.externalNetworkBridgeDpid))
+ return false;
+ if (gatewayIpAddress == null) {
+ if (other.gatewayIpAddress != null)
+ return false;
+ } else if (!gatewayIpAddress.equals(other.gatewayIpAddress))
+ return false;
+ if (periodicRefresh != other.periodicRefresh)
+ return false;
+ return true;
+ }
+
}
import static com.google.common.base.Preconditions.checkNotNull;
import java.math.BigInteger;
-import java.util.Map;
+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;
private ArpSender arpSender;
private SalFlowService flowService;
private final AtomicLong flowCookie = new AtomicLong();
- private final Map<Ipv4Address, ArpResolverMetadata> arpRemoveFlowInputAndL3EpKeyById =
+ private final ConcurrentMap<Ipv4Address, ArpResolverMetadata> gatewayToArpMetadataMap =
new ConcurrentHashMap<Ipv4Address, ArpResolverMetadata>();
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;
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);
static {
this.arpSender = null;
}
flowService = providerContext.getRpcService(SalFlowService.class);
+ refreshRequester.scheduleWithFixedDelay(new Runnable(){
+
+ @Override
+ public void run() {
+ if (!gatewayToArpMetadataMap.isEmpty()){
+ for(final Entry<Ipv4Address, ArpResolverMetadata> gatewayToArpMetadataEntry : gatewayToArpMetadataMap.entrySet()){
+ final Ipv4Address gatewayIp = gatewayToArpMetadataEntry.getKey();
+ final ArpResolverMetadata gatewayMetaData = gatewayToArpMetadataEntry.getValue();
+ gatewayMacRefresherPool.schedule(new Runnable(){
+
+ @Override
+ public void run() {
+
+ 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() );
+ }
+
+ 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);
+ }
+ }
+ }
+ }, REFRESH_INTERVAL, REFRESH_INTERVAL, TimeUnit.SECONDS);
}
}
/**
gatewayIp.getValue(),sourceIpAddress.getValue(),sourceMacAddress.getValue());
init();
- if(arpRemoveFlowInputAndL3EpKeyById.containsKey(gatewayIp)){
- if(arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp).getGatewayMacAddress() != null){
+ if(gatewayToArpMetadataMap.containsKey(gatewayIp)){
+ if(gatewayToArpMetadataMap.get(gatewayIp).getGatewayMacAddress() != null){
return arpWatcherWall.submit(new Callable<MacAddress>(){
@Override
public MacAddress call() throws Exception {
- return arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp).getGatewayMacAddress();
+ return gatewayToArpMetadataMap.get(gatewayIp).getGatewayMacAddress();
}
});
}
}else{
- arpRemoveFlowInputAndL3EpKeyById.put(gatewayIp,
- new ArpResolverMetadata(null, gatewayIp,periodicRefresh));
+ gatewayToArpMetadataMap.put(gatewayIp,new ArpResolverMetadata(
+ externalNetworkBridgeDpid, gatewayIp,sourceIpAddress,sourceMacAddress,periodicRefresh));
}
- final ArpMessageAddress senderAddress = new ArpMessageAddress(sourceMacAddress,sourceIpAddress);
-
- final String nodeName = OPENFLOW + externalNetworkBridgeDpid;
- final Node externalNetworkBridge = getOpenFlowNode(nodeName);
+ 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 );
return null;
}
+
+ sendGatewayArpRequest(externalNetworkBridge,gatewayIp,sourceIpAddress, sourceMacAddress);
+
+ //Wait for MacAddress population in cache
+ return waitForMacAddress(gatewayIp);
+ }
+
+ private Node getExternalBridge(final Long externalNetworkBridgeDpid){
+ final String nodeName = OPENFLOW + externalNetworkBridgeDpid;
+
+ return getOpenFlowNode(nodeName);
+ }
+
+ private void sendGatewayArpRequest(final Node externalNetworkBridge,final Ipv4Address gatewayIp,
+ final Ipv4Address sourceIpAddress, final MacAddress sourceMacAddress){
+ final ArpMessageAddress senderAddress = new ArpMessageAddress(sourceMacAddress,sourceIpAddress);
+
//Build arp reply router flow
final Flow arpReplyToControllerFlow = createArpReplyToControllerFlow(senderAddress, gatewayIp);
-
final InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(Nodes.class)
.child(Node.class, externalNetworkBridge.getKey())
.build();
LOG.debug("Flow to route ARP Reply to Controller installed successfully : {}", flowIid);
//cache metadata
- arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp).setFlowToRemove(
+ gatewayToArpMetadataMap.get(gatewayIp).setFlowToRemove(
new RemoveFlowInputBuilder(arpReplyToControllerFlow).setNode(nodeRef).build());
//Broadcast ARP request packets
}
}
);
- //Wait for MacAddress population in cache
- return waitForMacAddress(gatewayIp);
}
private ListenableFuture<MacAddress> waitForMacAddress(final Ipv4Address gatewayIp){
//Sleep before checking mac address, so meanwhile ARP request packets
// will be broadcasted on the bridge.
Thread.sleep(PER_CYCLE_WAIT_DURATION);
- ArpResolverMetadata arpResolverMetadata = arpRemoveFlowInputAndL3EpKeyById.get(gatewayIp);
+ ArpResolverMetadata arpResolverMetadata = gatewayToArpMetadataMap.get(gatewayIp);
if(arpResolverMetadata != null && arpResolverMetadata.getGatewayMacAddress() != null){
if(!arpResolverMetadata.isPeriodicRefresh()){
- return arpRemoveFlowInputAndL3EpKeyById.remove(gatewayIp).getGatewayMacAddress();
+ return gatewayToArpMetadataMap.remove(gatewayIp).getGatewayMacAddress();
}
return arpResolverMetadata.getGatewayMacAddress();
}
}
});
}
+
private static @Nullable Ipv4Address getIPv4Addresses(IpAddress ipAddress) {
if (ipAddress.getIpv4Address() == null) {
return null;
@Override
public void onPacketReceived(PacketReceived potentialArp) {
- Arp arp = null;
- try {
- arp = ArpResolverUtils.getArpFrom(potentialArp);
- } catch (Exception e) {
- LOG.trace(
- "Failed to decode potential ARP packet. This could occur when other than ARP packet was received.",
- e);
- return;
- }
- if (arp.getOperation() != ArpOperation.REPLY.intValue()) {
- LOG.trace("Packet is not ARP REPLY packet.");
- return;
- }
- if (LOG.isTraceEnabled()) {
- LOG.trace("ARP REPLY received - {}", ArpUtils.getArpToStringFormat(arp));
- }
- NodeKey nodeKey = potentialArp.getIngress().getValue().firstKeyOf(Node.class, NodeKey.class);
- if (nodeKey == null) {
- LOG.info("Unknown source node of ARP packet: {}", potentialArp);
- return;
- }
- Ipv4Address gatewayIpAddress = ArpUtils.bytesToIp(arp.getSenderProtocolAddress());
- MacAddress gatewayMacAddress = ArpUtils.bytesToMac(arp.getSenderHardwareAddress());
- ArpResolverMetadata removeFlowInputAndL3EpKey = arpRemoveFlowInputAndL3EpKeyById.get(gatewayIpAddress);
- if(removeFlowInputAndL3EpKey != null){
- removeFlowInputAndL3EpKey.setGatewayMacAddress(gatewayMacAddress);
- flowService.removeFlow(removeFlowInputAndL3EpKey.getFlowToRemove());
+ Arp arp = ArpResolverUtils.getArpFrom(potentialArp);
+ if(arp != null){
+ if (arp.getOperation() != ArpOperation.REPLY.intValue()) {
+ LOG.trace("Packet is not ARP REPLY packet.");
+ return;
+ }
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("ARP REPLY received - {}", ArpUtils.getArpToStringFormat(arp));
+ }
+ NodeKey nodeKey = potentialArp.getIngress().getValue().firstKeyOf(Node.class, NodeKey.class);
+ if (nodeKey == null) {
+ LOG.info("Unknown source node of ARP packet: {}", potentialArp);
+ return;
+ }
+ Ipv4Address gatewayIpAddress = ArpUtils.bytesToIp(arp.getSenderProtocolAddress());
+ MacAddress gatewayMacAddress = ArpUtils.bytesToMac(arp.getSenderHardwareAddress());
+ ArpResolverMetadata candidateGatewayIp = gatewayToArpMetadataMap.get(gatewayIpAddress);
+ if(candidateGatewayIp != null){
+ LOG.debug("Resolved MAC for Gateway Ip {} is {}",gatewayIpAddress.getValue(),gatewayMacAddress.getValue());
+ candidateGatewayIp.setGatewayMacAddress(gatewayMacAddress);
+ flowService.removeFlow(candidateGatewayIp.getFlowToRemove());
+ }
}
}
public void setDependencies(Object impl) {}
@Override
- public void stopPeriodicReferesh(Ipv4Address gatewayIp) {
+ public void stopPeriodicRefresh(Ipv4Address gatewayIp) {
init();
- arpRemoveFlowInputAndL3EpKeyById.remove(gatewayIp);
+ gatewayToArpMetadataMap.remove(gatewayIp);
}
}