108c1e96b89f49aae120433126dd06d7fd6791a6
[genius.git] / alivenessmonitor / alivenessmonitor-impl / src / main / java / org / opendaylight / genius / alivenessmonitor / internal / AlivenessProtocolHandlerARP.java
1 /*
2  * Copyright (c) 2016 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.genius.alivenessmonitor.internal;
9
10 import static org.opendaylight.genius.alivenessmonitor.internal.AlivenessMonitorConstants.SEPERATOR;
11 import static org.opendaylight.genius.alivenessmonitor.internal.AlivenessMonitorUtil.toStringIpAddress;
12
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.base.Strings;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.JdkFutureAdapters;
19 import java.math.BigInteger;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Future;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.opendaylight.controller.liblldp.Packet;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
30 import org.opendaylight.genius.mdsalutil.NwConstants;
31 import org.opendaylight.genius.mdsalutil.packet.ARP;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
49 import org.opendaylight.yangtools.yang.common.RpcError;
50 import org.opendaylight.yangtools.yang.common.RpcResult;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 @Singleton
55 public class AlivenessProtocolHandlerARP extends AbstractAlivenessProtocolHandler {
56     private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerARP.class);
57     private final OdlArputilService arpService;
58     private final OdlInterfaceRpcService interfaceManager;
59
60     @Inject
61     public AlivenessProtocolHandlerARP(final DataBroker dataBroker,
62                                        final OdlInterfaceRpcService interfaceManager,
63                                        final AlivenessMonitor alivenessMonitor,
64                                        final OdlArputilService arpService) {
65         super(dataBroker, interfaceManager, alivenessMonitor, EtherTypes.Arp);
66         this.interfaceManager = interfaceManager;
67         this.arpService = arpService;
68     }
69
70     @Override
71     public Class<?> getPacketClass() {
72         return ARP.class;
73     }
74
75     @Override
76     public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
77         ARP packet = (ARP) protocolPacket;
78         short tableId = packetReceived.getTableId().getValue();
79         int arpType = packet.getOpCode();
80
81         if (LOG.isTraceEnabled()) {
82             LOG.trace("packet: {}, tableId {}, arpType {}", packetReceived, tableId, arpType);
83         }
84
85         if (tableId == NwConstants.L3_INTERFACE_TABLE || tableId == NwConstants.L3_GW_MAC_TABLE) {
86             if (arpType == ARP.REPLY) {
87                 if (LOG.isTraceEnabled()) {
88                     LOG.trace("packet: {}, monitorKey {}", packetReceived);
89                 }
90
91                 BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata();
92                 int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
93                 String interfaceName = null;
94
95                 try {
96                     GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex(portTag).build();
97                     Future<RpcResult<GetInterfaceFromIfIndexOutput>> output =
98                             interfaceManager.getInterfaceFromIfIndex(input);
99                     RpcResult<GetInterfaceFromIfIndexOutput> result = output.get();
100                     if(result.isSuccessful()) {
101                         GetInterfaceFromIfIndexOutput ifIndexOutput = result.getResult();
102                         interfaceName = ifIndexOutput.getInterfaceName();
103                     } else {
104                         LOG.warn("RPC call to get interface name for if index {} failed with errors {}", portTag, result.getErrors());
105                         return null;
106                     }
107                 } catch(InterruptedException | ExecutionException e) {
108                     LOG.warn("Error retrieving interface Name for tag {}", portTag, e);
109                 }
110                 if(!Strings.isNullOrEmpty(interfaceName)) {
111                     String sourceIp = toStringIpAddress(packet.getSenderProtocolAddress());
112                     String targetIp = toStringIpAddress(packet.getTargetProtocolAddress());
113                     return getMonitoringKey(interfaceName, targetIp, sourceIp);
114                 } else {
115                     LOG.debug("No interface associated with tag {} to interpret the received ARP Reply", portTag);
116                 }
117             }
118         }
119         return null;
120     }
121
122     @Override
123     public void startMonitoringTask(MonitoringInfo monitorInfo) {
124         if(arpService == null) {
125             LOG.debug("ARP Service not available to send the packet");
126             return;
127         }
128         EndpointType source = monitorInfo.getSource().getEndpointType();
129         final String sourceInterface = Preconditions.checkNotNull(getInterfaceName(source),
130                 "Source interface is required to send ARP Packet for monitoring");
131
132         final String srcIp = Preconditions.checkNotNull(getIpAddress(source),
133                 "Source Ip address is required to send ARP Packet for monitoring");
134         final Optional<PhysAddress> srcMacAddressOptional = getMacAddress(source);
135         if(srcMacAddressOptional.isPresent())
136         {
137             PhysAddress srcMacAddress = srcMacAddressOptional.get();
138             EndpointType target = monitorInfo.getDestination().getEndpointType();
139             final String targetIp = Preconditions.checkNotNull(getIpAddress(target),
140                     "Target Ip address is required to send ARP Packet for monitoring");
141             if (LOG.isTraceEnabled()) {
142                 LOG.trace("sendArpRequest interface {}, senderIPAddress {}, targetAddress {}", sourceInterface, srcIp, targetIp);
143             }
144             InterfaceAddressBuilder interfaceAddressBuilder = new InterfaceAddressBuilder().setInterface(sourceInterface)
145                     .setIpAddress(IpAddressBuilder.getDefaultInstance(srcIp));
146             if (srcMacAddress != null) {
147                 interfaceAddressBuilder.setMacaddress(srcMacAddress);
148             }
149             List<InterfaceAddress> addresses = Collections.singletonList(interfaceAddressBuilder.build());
150             SendArpRequestInput input = new SendArpRequestInputBuilder().setInterfaceAddress(addresses)
151                     .setIpaddress(IpAddressBuilder.getDefaultInstance(targetIp)).build();
152             Future<RpcResult<Void>> future = arpService.sendArpRequest(input);
153             final String msgFormat = String.format("Send ARP Request on interface %s to destination %s", sourceInterface, targetIp);
154             Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
155                 @Override
156                 public void onFailure(Throwable error) {
157                     LOG.error("Error - {}", msgFormat, error);
158                 }
159
160                 @Override
161                 public void onSuccess(RpcResult<Void> result) {
162                     if(!result.isSuccessful()) {
163                         LOG.warn("Rpc call to {} failed {}", msgFormat, getErrorText(result.getErrors()));
164                     } else {
165                         LOG.debug("Successful RPC Result - {}", msgFormat);
166                     }
167                 }
168             });
169         }
170     }
171
172     private String getErrorText(Collection<RpcError> errors) {
173         StringBuilder errorText = new StringBuilder();
174         for(RpcError error : errors) {
175             errorText.append(",").append(error.getErrorType()).append("-")
176                      .append(error.getMessage());
177         }
178         return errorText.toString();
179     }
180
181     @Override
182     public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
183         String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
184         String sourceIp = getIpAddress(monitorInfo.getSource().getEndpointType());
185         String targetIp = getIpAddress(monitorInfo.getDestination().getEndpointType());
186         return getMonitoringKey(interfaceName, sourceIp, targetIp);
187     }
188
189     private String getMonitoringKey(String interfaceName, String sourceIp, String targetIp) {
190         return new StringBuilder().append(interfaceName).append(SEPERATOR).append(sourceIp)
191                 .append(SEPERATOR).append(targetIp).append(SEPERATOR).append(EtherTypes.Arp).toString();
192     }
193
194     private String getIpAddress(EndpointType source) {
195         String ipAddress = null;
196         if( source instanceof IpAddress) {
197             ipAddress = ((IpAddress) source).getIpAddress().getIpv4Address().getValue();
198         } else if (source instanceof Interface) {
199             ipAddress = ((Interface)source).getInterfaceIp().getIpv4Address().getValue();
200         }
201         return ipAddress;
202     }
203
204     private Optional <PhysAddress> getMacAddress(EndpointType source) {
205         Optional <PhysAddress> result = Optional.absent();
206         if (source instanceof Interface) {
207             result =  Optional.of(((Interface)source).getMacAddress());
208         }
209         return result;
210     }
211
212     private String getInterfaceName(EndpointType endpoint) {
213         String interfaceName = null;
214         if(endpoint instanceof Interface) {
215             interfaceName = ((Interface)endpoint).getInterfaceName();
216         }
217         return interfaceName;
218     }
219
220 }