2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.vpnservice.alivenessmonitor.internal;
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;
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;
52 import com.google.common.base.Strings;
54 public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandler {
55 private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerLLDP.class);
56 private AtomicInteger packetId = new AtomicInteger(0);
58 public AlivenessProtocolHandlerLLDP(ServiceProvider serviceProvider) {
59 super(serviceProvider);
63 public Class<?> getPacketClass() {
68 public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
69 String sSourceDpnId = null;
70 String sPortNumber = null;
78 LLDP lldpPacket = (LLDP)protocolPacket;
80 LLDPTLV lldpTlvCur = lldpPacket.getSystemNameId();
81 if (lldpTlvCur != null) {
82 sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
85 lldpTlvCur = lldpPacket.getPortId();
86 if (lldpTlvCur != null) {
87 sPortNumber = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
90 for (LLDPTLV lldpTlv : lldpPacket.getOptionalTLVList()) {
91 lldpTlvTypeCur = lldpTlv.getType();
93 if (lldpTlvTypeCur == LLDPTLV.TLVType.SystemName.getValue()) {
94 sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
98 for (LLDPTLV lldpTlv : lldpPacket.getCustomTlvList()) {
99 lldpTlvTypeCur = lldpTlv.getType();
101 if (lldpTlvTypeCur == LLDPTLV.TLVType.Custom.getValue()) {
102 sTmp = new String(lldpTlv.getValue());
107 String interfaceName = null;
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);
117 BigInteger metadata = packetReceived.getMatch().getMetadata().getMetadata();
118 int portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
120 LOG.trace("Ignoring Packet-in for interface tag 0");
124 String destInterfaceName = null;
125 //TODO: Use latest interface RPC
127 // destInterfaceName = serviceProvider.getInterfaceManager().getInterfaceNameForInterfaceTag(portTag);
128 // } catch(InterfaceNotFoundException e) {
129 // LOG.warn("Error retrieving interface Name for tag {}", portTag, e);
132 if(!Strings.isNullOrEmpty(interfaceName)) {
133 String monitorKey = new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString();
136 LOG.debug("No interface associated with tag {} to handle received LLDP Packet", portTag);
142 public void sendPacketOut(MonitoringInfo monitorInfo) {
143 String sourceInterface;
145 EndpointType source = monitorInfo.getSource().getEndpointType();
146 if( source instanceof Interface) {
147 Interface intf = (Interface)source;
148 sourceInterface = intf.getInterfaceName();
150 LOG.warn("Invalid source endpoint. Could not retrieve source interface to send LLDP Packet");
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);
162 OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager();
164 long nodeId = -1, portNum = -1;
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();
173 LOG.error("Could not retrieve DPN Id for interface {}", sourceInterface);
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();
185 LOG.error("Could not retrieve port number for interface {}", sourceInterface);
188 }catch(InterruptedException | ExecutionException e) {
189 LOG.error("Failed to retrieve RPC Result ", e);
193 Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, 0, sourceMac, sourceInterface);
196 List<ActionInfo> actions = getInterfaceActions(sourceInterface);
197 if(actions.isEmpty()) {
198 LOG.error("No interface actions to send packet out over interface {}", sourceInterface);
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);
209 private List<ActionInfo> getInterfaceActions(String interfaceName) throws InterruptedException, ExecutionException {
211 OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager();
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();
221 LOG.error("Could not retrieve port number for interface {} to construct actions", interfaceName);
222 return Collections.emptyList();
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();
231 LOG.error("Could not retrieve port type for interface {} to construct actions", interfaceName);
232 return Collections.emptyList();
235 List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
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}));
242 actionInfos.add(new ActionInfo(ActionType.output, new String[] { Long.toString(portNum) }));
246 private static LLDPTLV buildLLDTLV(LLDPTLV.TLVType tlvType,byte[] abyTLV) {
247 return new LLDPTLV().setType(tlvType.getValue()).setLength((short) abyTLV.length).setValue(abyTLV);
250 private int getPacketId() {
251 int id = packetId.incrementAndGet();
253 LOG.debug("Resetting the LLDP Packet Id counter");
260 public Ethernet makeLLDPPacket(String nodeId,
261 long portNum, int serviceId, byte[] srcMac, String sourceInterface) {
263 // Create LLDP TTL TLV
264 LLDPTLV lldpTlvTTL = buildLLDTLV(LLDPTLV.TLVType.TTL, new byte[] { (byte) 0, (byte) 120 });
266 LLDPTLV lldpTlvChassisId = buildLLDTLV(LLDPTLV.TLVType.ChassisID, LLDPTLV.createChassisIDTLVValue(colonize(StringUtils
267 .leftPad(Long.toHexString(MDSALUtil.getDpnIdFromNodeName(nodeId).longValue()), 16,
269 LLDPTLV lldpTlvSystemName = buildLLDTLV(TLVType.SystemName, LLDPTLV.createSystemNameTLVValue(nodeId));
271 LLDPTLV lldpTlvPortId = buildLLDTLV(TLVType.PortID, LLDPTLV.createPortIDTLVValue(
272 Long.toHexString(portNum)));
274 String customValue = sourceInterface + "#" + getPacketId();
276 LOG.debug("Sending LLDP packet, custome value " + customValue);
278 LLDPTLV lldpTlvCustom = buildLLDTLV(TLVType.Custom, customValue.getBytes());
280 List<LLDPTLV> lstLLDPTLVCustom = new ArrayList<>();
281 lstLLDPTLVCustom.add(lldpTlvCustom);
283 LLDP lldpDiscoveryPacket = new LLDP();
284 lldpDiscoveryPacket.setChassisId(lldpTlvChassisId)
285 .setPortId(lldpTlvPortId)
287 .setSystemNameId(lldpTlvSystemName)
288 .setOptionalTLVList(lstLLDPTLVCustom);
290 byte[] destMac = LLDP.LLDPMulticastMac;
292 Ethernet ethernetPacket = new Ethernet();
293 ethernetPacket.setSourceMACAddress(srcMac)
294 .setDestinationMACAddress(destMac)
295 .setEtherType(EtherTypes.LLDP.shortValue())
296 .setPayload(lldpDiscoveryPacket);
298 return ethernetPacket;
301 private String colonize(String orig) {
302 return orig.replaceAll("(?<=..)(..)", ":$1");
306 public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
307 String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
308 return new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString();
311 private String getInterfaceName(EndpointType endpoint) {
312 String interfaceName = null;
313 if(endpoint instanceof Interface) {
314 interfaceName = ((Interface)endpoint).getInterfaceName();
316 return interfaceName;