e084f657c75d0f7b0dd101fc9eedbbf274fa51ff
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / iplearn / AlivenessMonitorUtils.java
1 /*
2  * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.vpnmanager.iplearn;
9
10 import com.google.common.base.Optional;
11 import java.util.Map;
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;
59
60 @Singleton
61 public final class AlivenessMonitorUtils {
62
63     private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorUtils.class);
64     private static Map<Long, MacEntry> alivenessCache = new ConcurrentHashMap<>();
65
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;
72
73     @Inject
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;
82     }
83
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());
89             return;
90         }
91         Optional<IpAddress> gatewayIpOptional =
92             vpnUtil.getGatewayIpAddressFromInterface(macEntry);
93         if (!gatewayIpOptional.isPresent()) {
94             LOG.info("Interface{} does not have an GatewayIp", macEntry.getInterfaceName());
95             return;
96         }
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());
101             return;
102         }
103
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);
109                 return;
110             }
111             ipMonitorProfileId = profileIdOptional.get().toJava();
112         }
113
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();
121         try {
122             Future<RpcResult<MonitorStartOutput>> result = alivenessManager.monitorStart(ipMonitorInput);
123             RpcResult<MonitorStartOutput> rpcResult = result.get();
124             long monitorId;
125             if (rpcResult.isSuccessful()) {
126                 monitorId = rpcResult.getResult().getMonitorId().toJava();
127                 createOrUpdateInterfaceMonitorIdMap(monitorId, macEntry);
128                 LOG.trace("Started IP monitoring with id {}", monitorId);
129             } else {
130                 LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
131             }
132         } catch (InterruptedException | ExecutionException e) {
133             LOG.warn("Exception when starting monitoring", e);
134         }
135     }
136
137     void stopIpMonitoring(Uint32 monitorId) {
138         MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
139
140         JdkFutures.addErrorLogging(alivenessManager.monitorStop(input), LOG, "Stop monitoring");
141
142         alivenessCache.remove(monitorId.toJava());
143         return;
144     }
145
146     private void createOrUpdateInterfaceMonitorIdMap(long monitorId, MacEntry macEntry) {
147         alivenessCache.put(monitorId, macEntry);
148     }
149
150     private Interface getSourceEndPointType(String interfaceName, IpAddress ipAddress, PhysAddress gwMac) {
151         return new InterfaceBuilder()
152             .setInterfaceIp(ipAddress)
153             .setInterfaceName(interfaceName)
154             .setMacAddress(gwMac)
155             .build();
156     }
157
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();
164         }
165         return profileIdOptional;
166     }
167
168     public Optional<Uint32> allocateArpMonitorProfile() {
169         return allocateProfile(ArpConstants.FAILURE_THRESHOLD, ArpConstants.ARP_CACHE_TIMEOUT_MILLIS,
170                 ArpConstants.MONITORING_WINDOW, MonitorProtocolType.Arp);
171     }
172
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);
177     }
178
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);
186     }
187
188     // TODO Clean up the exception handling
189     @SuppressWarnings("checkstyle:IllegalCatch")
190     public Optional<Uint32> createMonitorProfile(MonitorProfileCreateInput monitorProfileCreateInput) {
191         try {
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());
197             } else {
198                 LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID",
199                     rpcResult.getErrors());
200                 try {
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());
210                     } else {
211                         LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}",
212                             rpcGetResult.getErrors());
213                     }
214                 } catch (Exception e) {
215                     LOG.warn("Exception when getting existing profile", e);
216                 }
217             }
218         } catch (InterruptedException | ExecutionException e) {
219             LOG.warn("Exception when allocating profile Id", e);
220         }
221         return Optional.absent();
222     }
223
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
228             .ProfileBuilder
229             profileBuilder =
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();
238     }
239
240     public static MacEntry getMacEntryFromMonitorId(Long monitorId) {
241         return alivenessCache.get(monitorId);
242     }
243
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();
248     }
249
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));
257         }
258         return monitorId;
259     }
260
261     private InstanceIdentifier<InterfaceMonitorEntry> getInterfaceMonitorMapId(String interfaceName) {
262         return InstanceIdentifier.builder(InterfaceMonitorMap.class)
263                 .child(InterfaceMonitorEntry.class, new InterfaceMonitorEntryKey(interfaceName)).build();
264     }
265
266 }