b1748d28d9bf2561d23c235584967a1624a40947
[genius.git] / alivenessmonitor / alivenessmonitor-impl-protocols / src / main / java / org / opendaylight / genius / alivenessmonitor / protocols / internal / AlivenessProtocolHandlerIPv6ND.java
1 /*
2  * Copyright (c) 2018 Alten Calsoft Labs India 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.protocols.internal;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.genius.alivenessmonitor.protocols.AlivenessMonitorAndProtocolsConstants.SEPERATOR;
12
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
18 import java.net.UnknownHostException;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.apache.aries.blueprint.annotation.service.Reference;
26 import org.apache.commons.lang3.StringUtils;
27 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandlerRegistry;
28 import org.opendaylight.genius.alivenessmonitor.utils.AlivenessMonitorUtil;
29 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
30 import org.opendaylight.genius.ipv6util.api.decoders.Ipv6NaDecoder;
31 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
32 import org.opendaylight.genius.mdsalutil.packet.utils.PacketUtil;
33 import org.opendaylight.mdsal.binding.api.DataBroker;
34 import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
35 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProtocolType;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborAdvertisePacket;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.Ipv6NdUtilService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationOutput;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.interfaces.InterfaceAddress;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.interfaces.InterfaceAddressBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
53 import org.opendaylight.yangtools.yang.common.RpcResult;
54 import org.opendaylight.yangtools.yang.common.Uint64;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 @Singleton
59 public class AlivenessProtocolHandlerIPv6ND extends AbstractAlivenessProtocolHandler<Packet> {
60
61     private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerIPv6ND.class);
62
63     private final Ipv6NdUtilService ndService;
64     private final OdlInterfaceRpcService interfaceManager;
65
66     @Inject
67     public AlivenessProtocolHandlerIPv6ND(@Reference final DataBroker dataBroker,
68                                           @Reference final AlivenessProtocolHandlerRegistry
69                                                       alivenessProtocolHandlerRegistry,
70                                           final OdlInterfaceRpcService interfaceManager,
71                                           final Ipv6NdUtilService ndService) {
72         super(dataBroker, alivenessProtocolHandlerRegistry, MonitorProtocolType.Ipv6Nd);
73         this.interfaceManager = interfaceManager;
74         this.ndService = ndService;
75         LOG.trace("AlivenessProtocolHandlerIPv6ND constructor called.");
76     }
77
78     @Override
79     public Class<Packet> getPacketClass() {
80         return Packet.class;
81     }
82
83     @Override
84     @SuppressFBWarnings("NP_NONNULL_RETURN_VIOLATION")
85     public String handlePacketIn(Packet packet, PacketReceived packetReceived) {
86         // parameter "packet" is expected to be null in this case
87         byte[] data = packetReceived.getPayload();
88         if (!PacketUtil.isIpv6NaPacket(data)) {
89             LOG.warn("Packet received is not an IPv6 NA packet, ignored.");
90             return null;
91         }
92
93         Ipv6NaDecoder ipv6NaDecoder = new Ipv6NaDecoder(data);
94         NeighborAdvertisePacket naPacket;
95         try {
96             naPacket = ipv6NaDecoder.decode();
97         } catch (UnknownHostException | BufferException e) {
98             LOG.warn("Failed to decode IPv6 NA packet={}", data, e);
99             return null;
100         }
101         short tableId = packetReceived.getTableId().getValue().toJava();
102         LOG.trace("packet: {}, tableId {}, ipv6Type {}", packetReceived, tableId, naPacket.getIcmp6Type());
103
104         Uint64 metadata = packetReceived.getMatch().getMetadata().getMetadata();
105         int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
106         String interfaceName = null;
107
108         try {
109             GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex(portTag).build();
110             Future<RpcResult<GetInterfaceFromIfIndexOutput>> output = interfaceManager.getInterfaceFromIfIndex(input);
111             RpcResult<GetInterfaceFromIfIndexOutput> result = output.get();
112             if (result.isSuccessful()) {
113                 GetInterfaceFromIfIndexOutput ifIndexOutput = result.getResult();
114                 interfaceName = ifIndexOutput.getInterfaceName();
115             } else {
116                 LOG.warn("RPC call to get interface name for if index {} failed with errors {}", portTag,
117                         result.getErrors());
118                 return null;
119             }
120         } catch (InterruptedException | ExecutionException e) {
121             LOG.warn("Error retrieving interface Name for tag {}", portTag, e);
122         }
123         if (StringUtils.isNotBlank(interfaceName)) {
124             String sourceIp = Ipv6Util.getFormattedIpv6Address(naPacket.getSourceIpv6());
125             String targetIp = Ipv6Util.getFormattedIpv6Address(naPacket.getDestinationIpv6());
126             return getMonitoringKey(interfaceName, targetIp, sourceIp);
127         } else {
128             LOG.debug("No interface associated with tag {} to interpret the received ipv6 NA Reply", portTag);
129         }
130         return null;
131     }
132
133     @Override
134     public void startMonitoringTask(MonitoringInfo monitorInfo) {
135         EndpointType source = monitorInfo.getSource().getEndpointType();
136         final String sourceInterface = requireNonNull(AlivenessMonitorUtil.getInterfaceName(source),
137                 "Source interface is required to send Ipv6 ND Packet for monitoring");
138         final String srcIp = requireNonNull(AlivenessMonitorUtil.getIpAddress(source),
139                 "Source IP address is required to send Ipv6 ND Packet for monitoring");
140         final PhysAddress srcMacAddress = requireNonNull(AlivenessMonitorUtil.getMacAddress(source),
141                 "Source MAC address is required to send Ipv6 ND Packet for monitoring");
142
143         EndpointType target = monitorInfo.getDestination().getEndpointType();
144         final String targetIp = requireNonNull(AlivenessMonitorUtil.getIpAddress(target),
145                 "Target Ip address is required to send ipv6 ND Packet for monitoring");
146         LOG.trace("sendNA interface {}, senderIPAddress {}, targetAddress {}", sourceInterface, srcIp, targetIp);
147
148         SendNeighborSolicitationInput input = buildNsInput(sourceInterface, srcIp, srcMacAddress, targetIp);
149         ListenableFuture<RpcResult<SendNeighborSolicitationOutput>> future = ndService.sendNeighborSolicitation(input);
150
151         final String msgFormat =
152                 String.format("Send NS packet on interface %s to destination %s", sourceInterface, targetIp);
153         Futures.addCallback(future, new FutureCallback<RpcResult<SendNeighborSolicitationOutput>>() {
154             @Override
155             public void onFailure(Throwable error) {
156                 LOG.error("Error - {}", msgFormat, error);
157             }
158
159             @Override
160             public void onSuccess(RpcResult<SendNeighborSolicitationOutput> result) {
161                 if (result != null && !result.isSuccessful()) {
162                     LOG.warn("Rpc call to {} failed {}", msgFormat,
163                             AlivenessMonitorUtil.getErrorText(result.getErrors()));
164                 } else {
165                     LOG.debug("Successful RPC Result - {}", msgFormat);
166                 }
167             }
168         }, MoreExecutors.directExecutor());
169     }
170
171     private SendNeighborSolicitationInput buildNsInput(final String sourceInterface, final String srcIp,
172             final PhysAddress srcMacAddress, final String targetIp) {
173         InterfaceAddressBuilder interfaceAddressBuilder = new InterfaceAddressBuilder().setInterface(sourceInterface)
174                 .setSrcIpAddress(Ipv6Address.getDefaultInstance(srcIp));
175         if (srcMacAddress != null) {
176             interfaceAddressBuilder.setSrcMacAddress(srcMacAddress);
177         }
178         List<InterfaceAddress> addresses = Collections.singletonList(interfaceAddressBuilder.build());
179         SendNeighborSolicitationInput input = new SendNeighborSolicitationInputBuilder().setInterfaceAddress(addresses)
180                 .setTargetIpAddress(Ipv6Address.getDefaultInstance(targetIp)).build();
181         return input;
182     }
183
184     @Override
185     public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
186         String interfaceName = AlivenessMonitorUtil.getInterfaceName(monitorInfo.getSource().getEndpointType());
187         String sourceIp = AlivenessMonitorUtil.getIpAddress(monitorInfo.getSource().getEndpointType());
188         String targetIp = AlivenessMonitorUtil.getIpAddress(monitorInfo.getDestination().getEndpointType());
189         return getMonitoringKey(interfaceName, sourceIp, targetIp);
190     }
191
192     private String getMonitoringKey(String interfaceName, String sourceIp, String targetIp) {
193         return interfaceName + SEPERATOR + sourceIp + SEPERATOR + targetIp + SEPERATOR + MonitorProtocolType.Ipv6Nd;
194     }
195 }
196