Using latest RPC from interface mgr
[vpnservice.git] / alivenessmonitor / alivenessmonitor-impl / src / main / java / org / opendaylight / vpnservice / alivenessmonitor / internal / AlivenessProtocolHandlerLLDP.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.vpnservice.alivenessmonitor.internal;
9
10 import java.math.BigInteger;
11 import java.nio.charset.Charset;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.atomic.AtomicInteger;
17 import java.util.concurrent.Future;
18
19 import org.apache.commons.lang3.StringUtils;
20 import org.opendaylight.controller.liblldp.EtherTypes;
21 import org.opendaylight.controller.liblldp.LLDP;
22 import org.opendaylight.controller.liblldp.LLDPTLV;
23 import org.opendaylight.controller.liblldp.LLDPTLV.TLVType;
24 import org.opendaylight.controller.liblldp.Packet;
25 import org.opendaylight.controller.liblldp.PacketException;
26 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
27 import org.opendaylight.vpnservice.mdsalutil.ActionType;
28 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
29 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
30 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.EndpointType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.Interface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexOutput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceOutput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
50 import org.opendaylight.yangtools.yang.common.RpcResult;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Strings;
55
56 public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandler {
57     private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerLLDP.class);
58     private AtomicInteger packetId = new AtomicInteger(0);
59
60     public AlivenessProtocolHandlerLLDP(ServiceProvider serviceProvider) {
61         super(serviceProvider);
62     }
63
64     @Override
65     public Class<?> getPacketClass() {
66         return LLDP.class;
67     }
68
69     @Override
70     public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
71         String sSourceDpnId = null;
72         String sPortNumber = null;
73         int nServiceId = -1;
74         int packetId = 0;
75
76         String sTmp = null;
77
78         byte lldpTlvTypeCur;
79
80         LLDP lldpPacket = (LLDP)protocolPacket;
81
82         LLDPTLV lldpTlvCur = lldpPacket.getSystemNameId();
83         if (lldpTlvCur != null) {
84             sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
85         }
86
87         lldpTlvCur = lldpPacket.getPortId();
88         if (lldpTlvCur != null) {
89             sPortNumber = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
90         }
91
92         for (LLDPTLV lldpTlv : lldpPacket.getOptionalTLVList()) {
93             lldpTlvTypeCur = lldpTlv.getType();
94
95             if (lldpTlvTypeCur == LLDPTLV.TLVType.SystemName.getValue()) {
96                 sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
97             }
98         }
99
100         for (LLDPTLV lldpTlv : lldpPacket.getCustomTlvList()) {
101             lldpTlvTypeCur = lldpTlv.getType();
102
103             if (lldpTlvTypeCur == LLDPTLV.TLVType.Custom.getValue()) {
104                 sTmp = new String(lldpTlv.getValue());
105                 nServiceId = 0;
106             }
107         }
108
109         String interfaceName = null;
110
111         //TODO: Check if the below fields are required
112         if (!Strings.isNullOrEmpty(sTmp) && sTmp.contains("#")) {
113             String[] asTmp = sTmp.split("#");
114             interfaceName = asTmp[0];
115             packetId = Integer.parseInt(asTmp[1]);
116             LOG.debug("Custom LLDP Value on received packet: " + sTmp);
117         }
118
119         BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata();
120         int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
121         if(portTag == 0) {
122             LOG.trace("Ignoring Packet-in for interface tag 0");
123             return null;
124         }
125
126         String destInterfaceName = null;
127
128         try {
129             GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex(portTag).build();
130             Future<RpcResult<GetInterfaceFromIfIndexOutput>> output = serviceProvider.getInterfaceManager().getInterfaceFromIfIndex(input);
131             RpcResult<GetInterfaceFromIfIndexOutput> result = output.get();
132             if(result.isSuccessful()) {
133                 GetInterfaceFromIfIndexOutput ifIndexOutput = result.getResult();
134                 destInterfaceName = ifIndexOutput.getInterfaceName();
135             } else {
136                 LOG.warn("RPC call to get interface name for if index {} failed with errors {}", portTag, result.getErrors());
137                 return null;
138             }
139         } catch(InterruptedException | ExecutionException e) {
140             LOG.warn("Error retrieving interface Name for tag {}", portTag, e);
141         }
142
143         if(!Strings.isNullOrEmpty(interfaceName)) {
144             String monitorKey = new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString();
145             return monitorKey;
146         } else {
147             LOG.debug("No interface associated with tag {} to handle received LLDP Packet", portTag);
148         }
149         return null;
150     }
151
152     @Override
153     public void sendPacketOut(MonitoringInfo monitorInfo) {
154         String sourceInterface;
155
156         EndpointType source = monitorInfo.getSource().getEndpointType();
157         if( source instanceof Interface) {
158             Interface intf = (Interface)source;
159             sourceInterface = intf.getInterfaceName();
160         } else {
161             LOG.warn("Invalid source endpoint. Could not retrieve source interface to send LLDP Packet");
162             return;
163         }
164
165         //Get Mac Address for the source interface
166         byte[] sourceMac = getMacAddress(sourceInterface);
167         if(sourceMac == null) {
168             LOG.error("Could not read mac address for the source interface {} from the Inventory. "
169                     + "LLDP packet cannot be send.", sourceInterface);
170             return;
171         }
172
173         OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager();
174
175         long nodeId = -1, portNum = -1;
176         try {
177             GetDpidFromInterfaceInput dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(sourceInterface).build();
178             Future<RpcResult<GetDpidFromInterfaceOutput>> dpIdOutput = interfaceService.getDpidFromInterface(dpIdInput);
179             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
180             if(dpIdResult.isSuccessful()) {
181                 GetDpidFromInterfaceOutput output = dpIdResult.getResult();
182                 nodeId = output.getDpid().longValue();
183             } else {
184                 LOG.error("Could not retrieve DPN Id for interface {}", sourceInterface);
185                 return;
186             }
187
188
189             GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(sourceInterface).build();
190             Future<RpcResult<GetPortFromInterfaceOutput>> portOutput = interfaceService.getPortFromInterface(input);
191             RpcResult<GetPortFromInterfaceOutput> result = portOutput.get();
192             if(result.isSuccessful()) {
193                 GetPortFromInterfaceOutput output = result.getResult();
194                 portNum = output.getPortno();
195             } else {
196                 LOG.error("Could not retrieve port number for interface {}", sourceInterface);
197                 return;
198             }
199         }catch(InterruptedException | ExecutionException e) {
200             LOG.error("Failed to retrieve interface service RPC Result ", e);
201             return;
202         }
203
204         Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, 0, sourceMac, sourceInterface);
205
206         try {
207             List<ActionInfo> actions = getInterfaceActions(sourceInterface);
208             if(actions.isEmpty()) {
209                 LOG.error("No interface actions to send packet out over interface {}", sourceInterface);
210                 return;
211             }
212             TransmitPacketInput transmitPacketInput = MDSALUtil.getPacketOut(actions,
213                     ethenetLLDPPacket.serialize(), nodeId, MDSALUtil.getNodeConnRef(BigInteger.valueOf(nodeId), "0xfffffffd"));
214             serviceProvider.getPacketProcessingService().transmitPacket(transmitPacketInput);
215         } catch (Exception  e) {
216             LOG.error("Error while sending LLDP Packet", e);
217         }
218     }
219
220     private List<ActionInfo> getInterfaceActions(String interfaceName) throws InterruptedException, ExecutionException {
221
222         OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager();
223
224         long portNum = -1;
225         GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(interfaceName).build();
226         Future<RpcResult<GetPortFromInterfaceOutput>> portOutput = interfaceService.getPortFromInterface(input);
227         RpcResult<GetPortFromInterfaceOutput> result = portOutput.get();
228         if(result.isSuccessful()) {
229             GetPortFromInterfaceOutput output = result.getResult();
230             portNum = output.getPortno();
231         } else {
232             LOG.error("Could not retrieve port number for interface {} to construct actions", interfaceName);
233             return Collections.emptyList();
234         }
235
236         Class<? extends InterfaceType> intfType = null;
237         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface interfaceInfo =
238                                                                                                      getInterfaceFromConfigDS(interfaceName);
239         if(interfaceInfo != null) {
240             intfType = interfaceInfo.getType();
241         } else {
242             LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceName);
243             return Collections.emptyList();
244         }
245
246         List<ActionInfo> actionInfos  = new ArrayList<ActionInfo>();
247
248         if(Tunnel.class.equals(intfType)) {
249             actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
250                                          MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(0x08000000),
251                                          MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID}));
252         }
253         actionInfos.add(new ActionInfo(ActionType.output, new String[] { Long.toString(portNum) }));
254         return actionInfos;
255     }
256
257     private static LLDPTLV buildLLDTLV(LLDPTLV.TLVType tlvType,byte[] abyTLV) {
258         return new LLDPTLV().setType(tlvType.getValue()).setLength((short) abyTLV.length).setValue(abyTLV);
259     }
260
261     private int getPacketId() {
262         int id = packetId.incrementAndGet();
263         if(id > 16000) {
264             LOG.debug("Resetting the LLDP Packet Id counter");
265             packetId.set(0);
266         }
267
268         return id;
269     }
270
271     public Ethernet makeLLDPPacket(String nodeId,
272             long portNum, int serviceId, byte[] srcMac, String sourceInterface) {
273
274         // Create LLDP TTL TLV
275         LLDPTLV lldpTlvTTL = buildLLDTLV(LLDPTLV.TLVType.TTL, new byte[] { (byte) 0, (byte) 120 });
276
277         LLDPTLV lldpTlvChassisId = buildLLDTLV(LLDPTLV.TLVType.ChassisID, LLDPTLV.createChassisIDTLVValue(colonize(StringUtils
278                 .leftPad(Long.toHexString(MDSALUtil.getDpnIdFromNodeName(nodeId).longValue()), 16,
279                         "0"))));
280         LLDPTLV lldpTlvSystemName = buildLLDTLV(TLVType.SystemName, LLDPTLV.createSystemNameTLVValue(nodeId));
281
282         LLDPTLV lldpTlvPortId = buildLLDTLV(TLVType.PortID, LLDPTLV.createPortIDTLVValue(
283                 Long.toHexString(portNum)));
284
285         String customValue = sourceInterface + "#" + getPacketId();
286
287         LOG.debug("Sending LLDP packet, custome value " + customValue);
288
289         LLDPTLV lldpTlvCustom = buildLLDTLV(TLVType.Custom, customValue.getBytes());
290
291         List<LLDPTLV> lstLLDPTLVCustom = new ArrayList<>();
292         lstLLDPTLVCustom.add(lldpTlvCustom);
293
294         LLDP lldpDiscoveryPacket = new LLDP();
295         lldpDiscoveryPacket.setChassisId(lldpTlvChassisId)
296                            .setPortId(lldpTlvPortId)
297                            .setTtl(lldpTlvTTL)
298                            .setSystemNameId(lldpTlvSystemName)
299                            .setOptionalTLVList(lstLLDPTLVCustom);
300
301         byte[] destMac = LLDP.LLDPMulticastMac;
302
303         Ethernet ethernetPacket = new Ethernet();
304         ethernetPacket.setSourceMACAddress(srcMac)
305                       .setDestinationMACAddress(destMac)
306                       .setEtherType(EtherTypes.LLDP.shortValue())
307                       .setPayload(lldpDiscoveryPacket);
308
309         return ethernetPacket;
310     }
311
312     private String colonize(String orig) {
313         return orig.replaceAll("(?<=..)(..)", ":$1");
314     }
315
316     @Override
317     public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
318         String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
319         return new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString();
320     }
321
322     private String getInterfaceName(EndpointType endpoint) {
323         String interfaceName = null;
324         if(endpoint instanceof Interface) {
325             interfaceName = ((Interface)endpoint).getInterfaceName();
326         }
327         return interfaceName;
328     }
329
330 }