2 * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.unimgr.mef.netvirt;
11 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.concurrent.ExecutorService;
13 import java.util.concurrent.Executors;
14 import java.util.concurrent.TimeUnit;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.unimgr.api.UnimgrDataTreeChangeListener;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
24 import org.opendaylight.yangtools.concepts.ListenerRegistration;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 public class GwMacListener extends UnimgrDataTreeChangeListener<VpnPortipToPort> implements IGwMacListener {
29 private static final Logger Log = LoggerFactory.getLogger(GwMacListener.class);
30 private ListenerRegistration<GwMacListener> gwMacListenerRegistration;
31 private final OdlArputilService arpUtilService;
32 private final ExecutorService retriesHandler;
33 private final Short sleepInterval;
35 private final ConcurrentHashMap<GwMacKey, GwMacValue> gwMacResolver;
37 public GwMacListener(final DataBroker dataBroker, final OdlArputilService arputilService, Short sleepInterval) {
39 this.arpUtilService = arputilService;
40 this.gwMacResolver = new ConcurrentHashMap<>();
41 this.sleepInterval = sleepInterval;
42 retriesHandler = Executors.newSingleThreadExecutor();
46 public void registerListener() {
48 final DataTreeIdentifier<VpnPortipToPort> dataTreeIid = new DataTreeIdentifier<>(
49 LogicalDatastoreType.OPERATIONAL, NetvirtVpnUtils.getVpnPortipToPortIdentifier());
50 gwMacListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
52 Log.info("GwMacListener created and registered");
53 } catch (final Exception e) {
54 Log.error("GwMacListener listener registration failed !", e);
55 throw new IllegalStateException("GwMacListener Listener failed.", e);
60 public void close() throws Exception {
61 gwMacListenerRegistration.close();
62 retriesHandler.shutdown();
63 if (!retriesHandler.awaitTermination(10, TimeUnit.SECONDS)) {
64 retriesHandler.shutdownNow();
69 public void add(DataTreeModification<VpnPortipToPort> newDataObject) {
70 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
71 VpnPortipToPort portIpToPort = newDataObject.getRootNode().getDataAfter();
72 updateMac(portIpToPort);
77 public void remove(DataTreeModification<VpnPortipToPort> removedDataObject) {
81 public void update(DataTreeModification<VpnPortipToPort> modifiedDataObject) {
82 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
83 VpnPortipToPort portIpToPort = modifiedDataObject.getRootNode().getDataAfter();
84 updateMac(portIpToPort);
88 private void updateMac(VpnPortipToPort portIpToPort) {
89 String portName = portIpToPort.getPortName();
90 String macAddress = portIpToPort.getMacAddress();
91 String vpnName = portIpToPort.getVpnName();
92 String ipAddress = portIpToPort.getPortFixedip();
93 GwMacKey gwMacKey = new GwMacKey(vpnName, portName, ipAddress);
95 if (!gwMacResolver.containsKey(gwMacKey)) {
96 Log.debug("Ignoring MAC update for vpn {} port {} ip {}", vpnName, portName, ipAddress);
100 if (macAddress != null && vpnName != null) {
101 Log.trace("Updating vpn {} port {} with IP {} MAC {}", vpnName, portName, ipAddress, macAddress);
104 if (gwMacResolver.get(gwMacKey).getGwMac() == null || !gwMacResolver.get(gwMacKey).getGwMac().equals(macAddress)) {
105 Log.info("Creating GW for vpn {} port {} ip {} MAC {}", vpnName, portName, ipAddress, macAddress);
106 NetvirtVpnUtils.createUpdateVpnInterface(dataBroker, vpnName, portName, gwMacResolver.get(gwMacKey).getSubnet(), macAddress,
107 false, gwMacResolver.get(gwMacKey).getPortIp());
109 gwMacResolver.get(gwMacKey).setGwMac(macAddress);
114 public void resolveGwMac(String vpnName, String portName, IpAddress srcIpAddress, IpAddress dstIpAddress, String subnet) {
115 String dstIpAddressStr = NetvirtVpnUtils.ipAddressToString(dstIpAddress);
116 GwMacKey gwMacKey = new GwMacKey(vpnName, portName, dstIpAddressStr);
118 if (!gwMacResolver.containsKey(gwMacKey)) {
119 // check if IP was resolved already
120 gwMacResolver.putIfAbsent(gwMacKey, new GwMacValue(NetvirtVpnUtils.ipAddressToString(srcIpAddress), subnet));
121 VpnPortipToPort portIpToPort = NetvirtVpnUtils.getVpnPortFixedIp(dataBroker, vpnName, dstIpAddressStr);
122 if (portIpToPort != null) {
123 updateMac(portIpToPort);
126 Log.info("Starting GW mac resolution for vpn {} port {} GW ip {}", vpnName, portName, dstIpAddress);
127 NetvirtVpnUtils.sendArpRequest(arpUtilService, srcIpAddress, dstIpAddress, portName);
132 public void unResolveGwMac(String vpnName, String portName, IpAddress srcIpAddress, IpAddress dstIpAddress) {
133 String dstIpAddressStr = NetvirtVpnUtils.ipAddressToString(dstIpAddress);
134 GwMacKey gwMacKey = new GwMacKey(vpnName, portName, dstIpAddressStr);
135 if (gwMacResolver.containsKey(gwMacKey)) {
136 Log.info("Stopping GW mac resolution for vpn {} port {} GW ip {}", vpnName, portName, dstIpAddress);
137 gwMacResolver.remove(gwMacKey);
141 private void resolveRetry() {
142 gwMacResolver.forEach((k, v) -> {
143 if (v.getGwMac() == null) {
144 IpAddress dstIpAddress = new IpAddress(k.gwIp.toCharArray());
145 IpAddress srcIpAddress = new IpAddress(v.portIp.toCharArray());
146 Log.debug("Resending ARP for IP {} port {}", dstIpAddress, k.getGwIp());
148 NetvirtVpnUtils.sendArpRequest(arpUtilService, srcIpAddress, dstIpAddress, k.portId);
153 void startRetriesThread() {
154 retriesHandler.submit(() -> {
155 Thread t = Thread.currentThread();
156 t.setName("ResolveSubnetGW");
157 Log.info("ResolveSubnetGW: started {}", t.getName());
159 NetvirtUtils.safeSleep(sleepInterval);
163 Log.debug("Subnet GW Arp Retries");
166 public static class GwMacKey {
167 private final String vpId;
168 private final String portId;
169 private final String gwIp;
171 public GwMacKey(String vpId, String portId, String gwIp) {
173 this.portId = portId;
177 public String getGwIp() {
181 public String getVpId() {
185 public String getPortId() {
190 public int hashCode() {
191 final int prime = 31;
193 result = prime * result + (gwIp == null ? 0 : gwIp.hashCode());
194 result = prime * result + (portId == null ? 0 : portId.hashCode());
195 result = prime * result + (vpId == null ? 0 : vpId.hashCode());
200 public boolean equals(Object obj) {
207 if (getClass() != obj.getClass()) {
210 GwMacKey other = (GwMacKey) obj;
212 if (other.gwIp != null) {
215 } else if (!gwIp.equals(other.gwIp)) {
218 if (portId == null) {
219 if (other.portId != null) {
222 } else if (!portId.equals(other.portId)) {
226 if (other.vpId != null) {
229 } else if (!vpId.equals(other.vpId)) {
238 public static class GwMacValue {
243 public GwMacValue(String portIp, String subnet) {
244 this.portIp = portIp;
245 this.subnet = subnet;
248 public String getGwMac() {
252 public void setGwMac(String gwMac) {
256 public String getPortIp() {
260 public String getSubnet() {