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.Collections;
12 import java.util.HashSet;
13 import java.util.List;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.concurrent.ExecutorService;
17 import java.util.concurrent.Executors;
18 import java.util.concurrent.TimeUnit;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.unimgr.api.UnimgrDataTreeChangeListener;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
28 import org.opendaylight.yangtools.concepts.ListenerRegistration;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 public class GwMacListener extends UnimgrDataTreeChangeListener<VpnPortipToPort> implements IGwMacListener {
33 private static final Logger Log = LoggerFactory.getLogger(GwMacListener.class);
34 private ListenerRegistration<GwMacListener> gwMacListenerRegistration;
35 private final OdlArputilService arpUtilService;
36 private final ExecutorService retriesHandler;
37 private final Short sleepInterval;
39 private final ConcurrentHashMap<GwMacKey, GwMacValue> gwMacResolver;
41 public GwMacListener(final DataBroker dataBroker, final OdlArputilService arputilService, Short sleepInterval) {
43 this.arpUtilService = arputilService;
44 this.gwMacResolver = new ConcurrentHashMap<>();
45 this.sleepInterval = sleepInterval;
46 retriesHandler = Executors.newSingleThreadExecutor();
50 public void registerListener() {
52 final DataTreeIdentifier<VpnPortipToPort> dataTreeIid = new DataTreeIdentifier<>(
53 LogicalDatastoreType.OPERATIONAL, NetvirtVpnUtils.getVpnPortipToPortIdentifier());
54 gwMacListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
56 Log.info("GwMacListener created and registered");
57 } catch (final Exception e) {
58 Log.error("GwMacListener listener registration failed !", e);
59 throw new IllegalStateException("GwMacListener Listener failed.", e);
64 public void close() throws Exception {
65 gwMacListenerRegistration.close();
66 retriesHandler.shutdown();
67 if (!retriesHandler.awaitTermination(10, TimeUnit.SECONDS)) {
68 retriesHandler.shutdownNow();
73 public void add(DataTreeModification<VpnPortipToPort> newDataObject) {
74 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
75 VpnPortipToPort portIpToPort = newDataObject.getRootNode().getDataAfter();
76 updateMac(portIpToPort);
81 public void remove(DataTreeModification<VpnPortipToPort> removedDataObject) {
85 public void update(DataTreeModification<VpnPortipToPort> modifiedDataObject) {
86 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
87 VpnPortipToPort portIpToPort = modifiedDataObject.getRootNode().getDataAfter();
88 updateMac(portIpToPort);
92 private synchronized void updateMac(VpnPortipToPort portIpToPort) {
93 String portName = portIpToPort.getPortName();
94 String macAddress = portIpToPort.getMacAddress();
95 String vpnName = portIpToPort.getVpnName();
96 String ipAddress = portIpToPort.getPortFixedip();
97 GwMacKey gwMacKey = new GwMacKey(vpnName, portName, ipAddress);
99 if (!gwMacResolver.containsKey(gwMacKey)) {
100 Log.debug("Ignoring MAC update for vpn {} port {} ip {}", vpnName, portName, ipAddress);
104 if (macAddress != null && vpnName != null) {
105 Log.trace("Updating vpn {} port {} with IP {} MAC {}", vpnName, portName, ipAddress, macAddress);
108 if (gwMacResolver.get(gwMacKey).getGwMac() == null
109 || !gwMacResolver.get(gwMacKey).getGwMac().equals(macAddress)) {
110 String portIp = gwMacResolver.get(gwMacKey).getPortIp();
111 for (String subnet : gwMacResolver.get(gwMacKey).getSubnets()) {
112 Log.info("Creating GW for vpn {} port {} ip {} subnet {} MAC {}", vpnName, portName, ipAddress, subnet,
115 NetvirtVpnUtils.createUpdateVpnInterface(dataBroker, vpnName, portName, subnet, macAddress, false,
119 gwMacResolver.get(gwMacKey).setGwMac(macAddress);
123 private void forceUpdateSubnet(GwMacKey gwMacKey, String subnet) {
124 if (!gwMacResolver.containsKey(gwMacKey)) {
127 String portIp = gwMacResolver.get(gwMacKey).getPortIp();
128 String macAddress = gwMacResolver.get(gwMacKey).getGwMac();
129 if (macAddress == null) {
132 Log.info("Creating GW for vpn {} port {} ip {} subnet {} MAC {}", gwMacKey.vpnId, gwMacKey.portId,
133 gwMacKey.gwIp, subnet, macAddress);
134 NetvirtVpnUtils.createUpdateVpnInterface(dataBroker, gwMacKey.vpnId, gwMacKey.portId, subnet, macAddress, false,
140 public synchronized void resolveGwMac(String vpnName, String portName, IpAddress srcIpAddress,
141 IpAddress dstIpAddress, String subnet) {
142 String dstIpAddressStr = NetvirtVpnUtils.ipAddressToString(dstIpAddress);
143 GwMacKey gwMacKey = new GwMacKey(vpnName, portName, dstIpAddressStr);
145 if (!gwMacResolver.containsKey(gwMacKey)) {
146 gwMacResolver.putIfAbsent(gwMacKey,
147 new GwMacValue(NetvirtVpnUtils.ipAddressToString(srcIpAddress), subnet));
148 Log.info("Starting GW mac resolution for vpn {} port {} GW ip {}", vpnName, portName, dstIpAddress);
149 NetvirtVpnUtils.sendArpRequest(arpUtilService, srcIpAddress, dstIpAddress, portName);
151 forceUpdateSubnet(gwMacKey, subnet);
152 gwMacResolver.get(gwMacKey).getSubnets().add(subnet);
155 VpnPortipToPort portIpToPort = NetvirtVpnUtils.getVpnPortFixedIp(dataBroker, vpnName, dstIpAddressStr);
156 if (portIpToPort != null) {
157 updateMac(portIpToPort);
163 public synchronized void unResolveGwMac(String vpnName, String portName, IpAddress srcIpAddress,
164 IpAddress dstIpAddress, String subnet) {
165 String dstIpAddressStr = NetvirtVpnUtils.ipAddressToString(dstIpAddress);
166 GwMacKey gwMacKey = new GwMacKey(vpnName, portName, dstIpAddressStr);
167 if (gwMacResolver.containsKey(gwMacKey)) {
168 Log.info("Stopping GW mac resolution for vpn {} port {} GW ip {} Subnet {}", vpnName, portName,
169 dstIpAddress, subnet);
170 gwMacResolver.get(gwMacKey).getSubnets().remove(subnet);
172 if (gwMacResolver.get(gwMacKey).getSubnets().isEmpty()) {
173 gwMacResolver.remove(gwMacKey);
178 private void resolveRetry() {
179 gwMacResolver.forEach((k, v) -> {
180 if (v.getGwMac() == null) {
181 IpAddress dstIpAddress = new IpAddress(k.gwIp.toCharArray());
182 IpAddress srcIpAddress = new IpAddress(v.portIp.toCharArray());
183 Log.debug("Resending ARP for IP {} port {}", dstIpAddress, k.getGwIp());
185 NetvirtVpnUtils.sendArpRequest(arpUtilService, srcIpAddress, dstIpAddress, k.portId);
190 void startRetriesThread() {
191 retriesHandler.submit(() -> {
192 Thread t = Thread.currentThread();
193 t.setName("ResolveSubnetGW");
194 Log.info("ResolveSubnetGW: started {}", t.getName());
196 NetvirtUtils.safeSleep(sleepInterval);
200 Log.debug("Subnet GW Arp Retries");
203 private static class GwMacKey {
204 private final String vpnId;
205 private final String portId;
206 private final String gwIp;
208 public GwMacKey(String vpId, String portId, String gwIp) {
210 this.portId = portId;
214 public String getGwIp() {
219 public int hashCode() {
220 final int prime = 31;
222 result = prime * result + (gwIp == null ? 0 : gwIp.hashCode());
223 result = prime * result + (portId == null ? 0 : portId.hashCode());
224 result = prime * result + (vpnId == null ? 0 : vpnId.hashCode());
229 public boolean equals(Object obj) {
236 if (getClass() != obj.getClass()) {
239 GwMacKey other = (GwMacKey) obj;
241 if (other.gwIp != null) {
244 } else if (!gwIp.equals(other.gwIp)) {
247 if (portId == null) {
248 if (other.portId != null) {
251 } else if (!portId.equals(other.portId)) {
255 if (other.vpnId != null) {
258 } else if (!vpnId.equals(other.vpnId)) {
266 private static class GwMacValue {
267 private String portIp;
268 private Set<String> subnets;
269 private String gwMac;
271 public GwMacValue(String portIp, String subnet) {
272 this.portIp = portIp;
273 this.subnets = new HashSet<String>();
274 this.subnets.add(subnet);
277 public String getGwMac() {
281 public void setGwMac(String gwMac) {
285 public String getPortIp() {
289 public Set<String> getSubnets() {