2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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
8 package org.opendaylight.netvirt.vpnmanager.iplearn;
10 import com.google.common.base.Optional;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.Future;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.arputil.api.ArpConstants;
20 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
23 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
24 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
25 import org.opendaylight.netvirt.vpnmanager.iplearn.model.MacEntry;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.InterfaceMonitorMap;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProtocolType;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitoringMode;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411._interface.monitor.map.InterfaceMonitorEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411._interface.monitor.map.InterfaceMonitorEntryKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.InterfaceBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.params.DestinationBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.params.SourceBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.Profile;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.ProfileBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.start.input.ConfigBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.common.RpcResult;
56 import org.opendaylight.yangtools.yang.common.Uint32;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
61 public final class AlivenessMonitorUtils {
63 private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorUtils.class);
64 private static Map<Long, MacEntry> alivenessCache = new ConcurrentHashMap<>();
66 private final DataBroker dataBroker;
67 private final INeutronVpnManager neutronvpnService;
68 private final AlivenessMonitorService alivenessManager;
69 private final IInterfaceManager interfaceManager;
70 private final VpnUtil vpnUtil;
71 private final VpnConfig vpnConfig;
74 public AlivenessMonitorUtils(DataBroker dataBroker, VpnUtil vpnUtil, INeutronVpnManager neutronvpnService,
75 AlivenessMonitorService alivenessManager, IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
76 this.dataBroker = dataBroker;
77 this.vpnUtil = vpnUtil;
78 this.neutronvpnService = neutronvpnService;
79 this.alivenessManager = alivenessManager;
80 this.interfaceManager = interfaceManager;
81 this.vpnConfig = vpnConfig;
84 void startIpMonitoring(MacEntry macEntry, Long ipMonitorProfileId) {
85 if (interfaceManager.isExternalInterface(macEntry.getInterfaceName())) {
86 LOG.debug("IP monitoring is currently not supported through external interfaces,"
87 + "skipping IP monitoring from interface {} for IP {} (last known MAC {})",
88 macEntry.getInterfaceName(), macEntry.getIpAddress().getHostAddress(), macEntry.getMacAddress());
91 Optional<IpAddress> gatewayIpOptional =
92 vpnUtil.getGatewayIpAddressFromInterface(macEntry);
93 if (!gatewayIpOptional.isPresent()) {
94 LOG.info("Interface{} does not have an GatewayIp", macEntry.getInterfaceName());
97 final IpAddress gatewayIp = gatewayIpOptional.get();
98 Optional<String> gatewayMacOptional = vpnUtil.getGWMacAddressFromInterface(macEntry, gatewayIp);
99 if (!gatewayMacOptional.isPresent()) {
100 LOG.error("Error while retrieving GatewayMac for interface{}", macEntry.getInterfaceName());
104 final IpAddress targetIp = IetfInetUtil.INSTANCE.ipAddressFor(macEntry.getIpAddress());
105 if (ipMonitorProfileId == null || ipMonitorProfileId.equals(0L)) {
106 Optional<Uint32> profileIdOptional = allocateIpMonitorProfile(targetIp);
107 if (!profileIdOptional.isPresent()) {
108 LOG.error("startIpMonitoring: Error while allocating Profile Id for IP={}", targetIp);
111 ipMonitorProfileId = profileIdOptional.get().toJava();
114 final PhysAddress gatewayMac = new PhysAddress(gatewayMacOptional.get());
115 MonitorStartInput ipMonitorInput = new MonitorStartInputBuilder().setConfig(new ConfigBuilder()
116 .setSource(new SourceBuilder().setEndpointType(getSourceEndPointType(macEntry.getInterfaceName(),
117 gatewayIp, gatewayMac)).build())
118 .setDestination(new DestinationBuilder().setEndpointType(getEndPointIpAddress(targetIp)).build())
119 .setMode(MonitoringMode.OneOne)
120 .setProfileId(ipMonitorProfileId).build()).build();
122 Future<RpcResult<MonitorStartOutput>> result = alivenessManager.monitorStart(ipMonitorInput);
123 RpcResult<MonitorStartOutput> rpcResult = result.get();
125 if (rpcResult.isSuccessful()) {
126 monitorId = rpcResult.getResult().getMonitorId().toJava();
127 createOrUpdateInterfaceMonitorIdMap(monitorId, macEntry);
128 LOG.trace("Started IP monitoring with id {}", monitorId);
130 LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
132 } catch (InterruptedException | ExecutionException e) {
133 LOG.warn("Exception when starting monitoring", e);
137 void stopIpMonitoring(Uint32 monitorId) {
138 MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
140 JdkFutures.addErrorLogging(alivenessManager.monitorStop(input), LOG, "Stop monitoring");
142 alivenessCache.remove(monitorId.toJava());
146 private void createOrUpdateInterfaceMonitorIdMap(long monitorId, MacEntry macEntry) {
147 alivenessCache.put(monitorId, macEntry);
150 private Interface getSourceEndPointType(String interfaceName, IpAddress ipAddress, PhysAddress gwMac) {
151 return new InterfaceBuilder()
152 .setInterfaceIp(ipAddress)
153 .setInterfaceName(interfaceName)
154 .setMacAddress(gwMac)
158 private Optional<Uint32> allocateIpMonitorProfile(IpAddress targetIp) {
159 Optional<Uint32> profileIdOptional = Optional.absent();
160 if (targetIp.getIpv4Address() != null) {
161 profileIdOptional = allocateArpMonitorProfile();
162 } else if (targetIp.getIpv6Address() != null) {
163 profileIdOptional = allocateIpv6NaMonitorProfile();
165 return profileIdOptional;
168 public Optional<Uint32> allocateArpMonitorProfile() {
169 return allocateProfile(ArpConstants.FAILURE_THRESHOLD, ArpConstants.ARP_CACHE_TIMEOUT_MILLIS,
170 ArpConstants.MONITORING_WINDOW, MonitorProtocolType.Arp);
173 public Optional<Uint32> allocateIpv6NaMonitorProfile() {
174 Long monitorInterval = vpnConfig.getIpv6NdMonitorInterval().toJava() * 1000; // converting to milliseconds
175 return allocateProfile(vpnConfig.getIpv6NdMonitorFailureThreshold().toJava(), monitorInterval,
176 vpnConfig.getIpv6NdMonitorWindow().toJava(), MonitorProtocolType.Ipv6Nd);
179 public Optional<Uint32> allocateProfile(long failureThreshold, long monitoringInterval, long monitoringWindow,
180 MonitorProtocolType protocolType) {
181 MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder()
182 .setProfile(new ProfileBuilder().setFailureThreshold(failureThreshold)
183 .setMonitorInterval(monitoringInterval).setMonitorWindow(monitoringWindow)
184 .setProtocolType(protocolType).build()).build();
185 return createMonitorProfile(input);
188 // TODO Clean up the exception handling
189 @SuppressWarnings("checkstyle:IllegalCatch")
190 public Optional<Uint32> createMonitorProfile(MonitorProfileCreateInput monitorProfileCreateInput) {
192 Future<RpcResult<MonitorProfileCreateOutput>> result =
193 alivenessManager.monitorProfileCreate(monitorProfileCreateInput);
194 RpcResult<MonitorProfileCreateOutput> rpcResult = result.get();
195 if (rpcResult.isSuccessful()) {
196 return Optional.of(rpcResult.getResult().getProfileId());
198 LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID",
199 rpcResult.getErrors());
201 Profile createProfile = monitorProfileCreateInput.getProfile();
202 Future<RpcResult<MonitorProfileGetOutput>> existingProfile =
203 alivenessManager.monitorProfileGet(buildMonitorGetProfile(
204 createProfile.getMonitorInterval().toJava(),
205 createProfile.getMonitorWindow().toJava(), createProfile.getFailureThreshold().toJava(),
206 createProfile.getProtocolType()));
207 RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
208 if (rpcGetResult.isSuccessful()) {
209 return Optional.of(rpcGetResult.getResult().getProfileId());
211 LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}",
212 rpcGetResult.getErrors());
214 } catch (Exception e) {
215 LOG.warn("Exception when getting existing profile", e);
218 } catch (InterruptedException | ExecutionException e) {
219 LOG.warn("Exception when allocating profile Id", e);
221 return Optional.absent();
224 private MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval, long monitorWindow,
225 long failureThreshold, MonitorProtocolType protocolType) {
226 MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
227 org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.get.input
230 new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.get
231 .input.ProfileBuilder();
232 profileBuilder.setFailureThreshold(failureThreshold)
233 .setMonitorInterval(monitorInterval)
234 .setMonitorWindow(monitorWindow)
235 .setProtocolType(protocolType);
236 buildGetProfile.setProfile(profileBuilder.build());
237 return buildGetProfile.build();
240 public static MacEntry getMacEntryFromMonitorId(Long monitorId) {
241 return alivenessCache.get(monitorId);
244 private static org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411
245 .endpoint.endpoint.type.IpAddress getEndPointIpAddress(IpAddress ip) {
246 return new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411
247 .endpoint.endpoint.type.IpAddressBuilder().setIpAddress(ip).build();
250 public java.util.Optional<Uint32> getMonitorIdFromInterface(MacEntry macEntry) {
251 String interfaceName = macEntry.getInterfaceName();
252 java.util.Optional<Uint32> monitorId = java.util.Optional.empty();
253 Optional<InterfaceMonitorEntry> interfaceMonitorEntryOptional = MDSALUtil.read(dataBroker,
254 LogicalDatastoreType.OPERATIONAL, getInterfaceMonitorMapId(interfaceName));
255 if (interfaceMonitorEntryOptional.isPresent()) {
256 return java.util.Optional.of(interfaceMonitorEntryOptional.get().getMonitorIds().get(0));
261 private InstanceIdentifier<InterfaceMonitorEntry> getInterfaceMonitorMapId(String interfaceName) {
262 return InstanceIdentifier.builder(InterfaceMonitorMap.class)
263 .child(InterfaceMonitorEntry.class, new InterfaceMonitorEntryKey(interfaceName)).build();