NETVIRT-1187 Imported FIB Route is not being translated to flows
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / 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;
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 org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.genius.arputil.api.ArpConstants;
17 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
18 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
19 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInputBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitoringMode;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.InterfaceBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.params.DestinationBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.params.SourceBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.Profile;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.ProfileBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.start.input.ConfigBuilder;
44
45 import org.opendaylight.yangtools.yang.common.RpcResult;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public final class AlivenessMonitorUtils {
50
51     private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorUtils.class);
52     private static Map<Long, MacEntry> alivenessCache = new ConcurrentHashMap<>();
53
54     private AlivenessMonitorUtils() { }
55
56     public static void startArpMonitoring(MacEntry macEntry, Long arpMonitorProfileId,
57             AlivenessMonitorService alivenessMonitorService, DataBroker dataBroker,
58             INeutronVpnManager neutronVpnService,
59             IInterfaceManager interfaceManager) {
60         if (interfaceManager.isExternalInterface(macEntry.getInterfaceName())) {
61             LOG.debug("ARP monitoring is currently not supported through external interfaces,"
62                     + "skipping ARP monitoring from interface {} for IP {} (last known MAC {})",
63                 macEntry.getInterfaceName(), macEntry.getIpAddress().getHostAddress(), macEntry.getMacAddress());
64             return;
65         }
66         Optional<IpAddress> gatewayIpOptional =
67             VpnUtil.getGatewayIpAddressFromInterface(macEntry.getInterfaceName(), neutronVpnService);
68         if (!gatewayIpOptional.isPresent()) {
69             LOG.error("Error while retrieving GatewayIp for interface{}", macEntry.getInterfaceName());
70             return;
71         }
72         final IpAddress gatewayIp = gatewayIpOptional.get();
73         Optional<String> gatewayMacOptional = VpnUtil.getGWMacAddressFromInterface(macEntry,
74             gatewayIp, dataBroker);
75         if (!gatewayMacOptional.isPresent()) {
76             LOG.error("Error while retrieving GatewayMac for interface{}", macEntry.getInterfaceName());
77             return;
78         }
79         final PhysAddress gatewayMac = new PhysAddress(gatewayMacOptional.get());
80         if (arpMonitorProfileId == null || arpMonitorProfileId.equals(0L)) {
81             Optional<Long> profileIdOptional = allocateProfile(alivenessMonitorService,
82                 ArpConstants.FAILURE_THRESHOLD, ArpConstants.ARP_CACHE_TIMEOUT_MILLIS,
83                 ArpConstants.MONITORING_WINDOW, EtherTypes.Arp);
84             if (!profileIdOptional.isPresent()) {
85                 LOG.error("Error while allocating Profile Id for alivenessMonitorService");
86                 return;
87             }
88             arpMonitorProfileId = profileIdOptional.get();
89         }
90
91         IpAddress targetIp = new IpAddress(new Ipv4Address(macEntry.getIpAddress().getHostAddress()));
92         MonitorStartInput arpMonitorInput = new MonitorStartInputBuilder().setConfig(new ConfigBuilder()
93             .setSource(new SourceBuilder().setEndpointType(getSourceEndPointType(macEntry.getInterfaceName(),
94                 gatewayIp, gatewayMac)).build())
95             .setDestination(new DestinationBuilder().setEndpointType(getEndPointIpAddress(targetIp)).build())
96             .setMode(MonitoringMode.OneOne)
97             .setProfileId(arpMonitorProfileId).build()).build();
98         try {
99             Future<RpcResult<MonitorStartOutput>> result = alivenessMonitorService.monitorStart(arpMonitorInput);
100             RpcResult<MonitorStartOutput> rpcResult = result.get();
101             long monitorId;
102             if (rpcResult.isSuccessful()) {
103                 monitorId = rpcResult.getResult().getMonitorId();
104                 createOrUpdateInterfaceMonitorIdMap(monitorId, macEntry);
105                 LOG.trace("Started ARP monitoring with id {}", monitorId);
106             } else {
107                 LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
108             }
109         } catch (InterruptedException | ExecutionException e) {
110             LOG.warn("Exception when starting monitoring", e);
111         }
112     }
113
114     public static void stopArpMonitoring(AlivenessMonitorService alivenessMonitorService,
115         Long monitorId) {
116         MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
117
118         JdkFutures.addErrorLogging(alivenessMonitorService.monitorStop(input), LOG, "Stop monitoring");
119
120         alivenessCache.remove(monitorId);
121         return;
122     }
123
124     private static void createOrUpdateInterfaceMonitorIdMap(long monitorId, MacEntry macEntry) {
125         alivenessCache.put(monitorId, macEntry);
126     }
127
128     private static Interface getSourceEndPointType(String interfaceName, IpAddress ipAddress,
129         PhysAddress gwMac) {
130         return new InterfaceBuilder()
131             .setInterfaceIp(ipAddress)
132             .setInterfaceName(interfaceName)
133             .setMacAddress(gwMac)
134             .build();
135     }
136
137     public static Optional<Long> allocateProfile(AlivenessMonitorService alivenessMonitor,
138         long failureThreshold, long monitoringInterval,
139         long monitoringWindow, EtherTypes etherTypes) {
140         MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder()
141             .setProfile(new ProfileBuilder().setFailureThreshold(failureThreshold)
142                 .setMonitorInterval(monitoringInterval).setMonitorWindow(monitoringWindow)
143                 .setProtocolType(etherTypes).build()).build();
144         return createMonitorProfile(alivenessMonitor, input);
145     }
146
147     // TODO Clean up the exception handling
148     @SuppressWarnings("checkstyle:IllegalCatch")
149     public static Optional<Long> createMonitorProfile(AlivenessMonitorService alivenessMonitor,
150             MonitorProfileCreateInput monitorProfileCreateInput) {
151         try {
152             Future<RpcResult<MonitorProfileCreateOutput>> result =
153                 alivenessMonitor.monitorProfileCreate(monitorProfileCreateInput);
154             RpcResult<MonitorProfileCreateOutput> rpcResult = result.get();
155             if (rpcResult.isSuccessful()) {
156                 return Optional.of(rpcResult.getResult().getProfileId());
157             } else {
158                 LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID",
159                     rpcResult.getErrors());
160                 try {
161                     Profile createProfile = monitorProfileCreateInput.getProfile();
162                     Future<RpcResult<MonitorProfileGetOutput>> existingProfile =
163                         alivenessMonitor.monitorProfileGet(buildMonitorGetProfile(createProfile.getMonitorInterval(),
164                             createProfile.getMonitorWindow(), createProfile.getFailureThreshold(),
165                             createProfile.getProtocolType()));
166                     RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
167                     if (rpcGetResult.isSuccessful()) {
168                         return Optional.of(rpcGetResult.getResult().getProfileId());
169                     } else {
170                         LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}",
171                             rpcGetResult.getErrors());
172                     }
173                 } catch (Exception e) {
174                     LOG.warn("Exception when getting existing profile", e);
175                 }
176             }
177         } catch (InterruptedException | ExecutionException e) {
178             LOG.warn("Exception when allocating profile Id", e);
179         }
180         return Optional.absent();
181     }
182
183     private static MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval,
184         long monitorWindow, long failureThreshold, EtherTypes protocolType) {
185         MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
186         org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.get.input
187             .ProfileBuilder
188             profileBuilder =
189             new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.get
190                 .input.ProfileBuilder();
191         profileBuilder.setFailureThreshold(failureThreshold)
192             .setMonitorInterval(monitorInterval)
193             .setMonitorWindow(monitorWindow)
194             .setProtocolType(protocolType);
195         buildGetProfile.setProfile(profileBuilder.build());
196         return buildGetProfile.build();
197     }
198
199     public static MacEntry getMacEntryFromMonitorId(Long monitorId) {
200         return alivenessCache.get(monitorId);
201     }
202
203     private static org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411
204         .endpoint.endpoint.type.IpAddress getEndPointIpAddress(IpAddress ip) {
205         return new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411
206             .endpoint.endpoint.type.IpAddressBuilder().setIpAddress(ip).build();
207     }
208
209     public static java.util.Optional<Long> getMonitorIdFromInterface(MacEntry macEntry) {
210         java.util.Optional<Long> monitorId = alivenessCache.entrySet().parallelStream()
211             .filter(map -> macEntry.equals(map.getValue()))
212             .map(Map.Entry::getKey)
213             .findFirst();
214         return monitorId;
215     }
216
217 }