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