2 * Copyright (c) 2016 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.genius.alivenessmonitor.protocols.internal;
10 import static org.opendaylight.infrautils.utils.concurrent.JdkFutures.addErrorLogging;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Strings;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.math.BigInteger;
16 import java.nio.charset.Charset;
17 import java.nio.charset.StandardCharsets;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.atomic.AtomicInteger;
23 import org.apache.commons.lang3.StringUtils;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandlerRegistry;
27 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
28 import org.opendaylight.genius.mdsalutil.ActionInfo;
29 import org.opendaylight.genius.mdsalutil.MDSALUtil;
30 import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
31 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
32 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
33 import org.opendaylight.openflowplugin.libraries.liblldp.EtherTypes;
34 import org.opendaylight.openflowplugin.libraries.liblldp.LLDP;
35 import org.opendaylight.openflowplugin.libraries.liblldp.LLDPTLV;
36 import org.opendaylight.openflowplugin.libraries.liblldp.LLDPTLV.TLVType;
37 import org.opendaylight.openflowplugin.libraries.liblldp.PacketException;
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.inet.types.rev130715.Uri;
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.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandler<LLDP> {
53 private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerLLDP.class);
55 // TODO org.opendaylight.openflowplugin.libraries.liblldp.LLDPTLV uses Charset.defaultCharset() .. bug there?
56 private static final Charset LLDPTLV_CHARSET = StandardCharsets.US_ASCII;
58 private final PacketProcessingService packetProcessingService;
59 private final AtomicInteger packetId = new AtomicInteger(0);
61 public AlivenessProtocolHandlerLLDP(
62 final DataBroker dataBroker,
63 final AlivenessProtocolHandlerRegistry alivenessProtocolHandlerRegistry,
64 final PacketProcessingService packetProcessingService) {
65 super(dataBroker, alivenessProtocolHandlerRegistry,
66 org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes.Lldp);
67 this.packetProcessingService = packetProcessingService;
71 public Class<LLDP> getPacketClass() {
76 // TODO remove DLS_DEAD_LOCAL_STORE when 1st below lldpTlvTypeCur below is removed
77 @SuppressFBWarnings({"DLS_DEAD_LOCAL_STORE", "NP_NULL_PARAM_DEREF"})
78 public String handlePacketIn(LLDP lldpPacket, PacketReceived packetReceived) {
79 String tempString = null;
82 // TODO Remove? this seems completely pointless - lldpTlvTypeCur will get overwritten below..
83 for (LLDPTLV lldpTlv : lldpPacket.getOptionalTLVList()) {
84 lldpTlvTypeCur = lldpTlv.getType();
87 for (LLDPTLV lldpTlv : lldpPacket.getCustomTlvList()) {
88 lldpTlvTypeCur = lldpTlv.getType();
90 if (lldpTlvTypeCur == LLDPTLV.TLVType.Custom.getValue()) {
91 tempString = new String(lldpTlv.getValue(), LLDPTLV_CHARSET);
95 String interfaceName = null;
97 // TODO: Check if the below fields are required
98 if (!Strings.isNullOrEmpty(tempString) && tempString.contains("#")) {
99 String[] asTmp = tempString.split("#");
100 interfaceName = asTmp[0];
101 LOG.debug("Custom LLDP Value on received packet: {}", tempString);
104 if (!Strings.isNullOrEmpty(interfaceName)) {
105 String monitorKey = interfaceName + EtherTypes.LLDP;
108 LOG.debug("No associated interface found to handle received LLDP Packet");
114 public void startMonitoringTask(MonitoringInfo monitorInfo) {
115 String sourceInterface;
117 EndpointType source = monitorInfo.getSource().getEndpointType();
118 if (source instanceof Interface) {
119 Interface intf = (Interface) source;
120 sourceInterface = intf.getInterfaceName();
122 LOG.warn("Invalid source endpoint. Could not retrieve source interface to send LLDP Packet");
126 // Get Mac Address for the source interface
127 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
128 .interfaces.state.Interface interfaceState;
130 interfaceState = getInterfaceFromOperDS(sourceInterface);
131 } catch (ReadFailedException e) {
132 LOG.error("getInterfaceFromOperDS failed for sourceInterface: {}", sourceInterface, e);
136 Optional<byte[]> optSourceMac = getMacAddress(interfaceState);
137 if (!optSourceMac.isPresent()) {
138 LOG.error("Could not read mac address for the source interface {} from the Inventory. "
139 + "LLDP packet cannot be send.", sourceInterface);
142 byte[] sourceMac = optSourceMac.get();
144 String lowerLayerIf = interfaceState.getLowerLayerIf().get(0);
145 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
146 long nodeId = Long.parseLong(getDpnFromNodeConnectorId(nodeConnectorId));
147 long portNum = Long.parseLong(getPortNoFromNodeConnectorId(nodeConnectorId));
148 Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, sourceMac, sourceInterface);
151 List<ActionInfo> actions = getInterfaceActions(interfaceState, portNum);
152 if (actions.isEmpty()) {
153 LOG.error("No interface actions to send packet out over interface {}", sourceInterface);
156 TransmitPacketInput transmitPacketInput = MDSALUtil.getPacketOut(actions, ethenetLLDPPacket.serialize(),
157 nodeId, MDSALUtil.getNodeConnRef(BigInteger.valueOf(nodeId), "0xfffffffd"));
158 addErrorLogging(packetProcessingService.transmitPacket(transmitPacketInput),
159 LOG, "transmitPacket() failed: {}", transmitPacketInput);
160 } catch (InterruptedException | ExecutionException | PacketException e) {
161 LOG.error("Error while sending LLDP Packet", e);
165 public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
167 * NodeConnectorId is of form 'openflow:dpnid:portnum'
169 String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
173 public static String getPortNoFromNodeConnectorId(NodeConnectorId portId) {
175 * NodeConnectorId is of form 'openflow:dpnid:portnum'
177 String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
181 private List<ActionInfo> getInterfaceActions(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
182 .interfaces.rev140508.interfaces.state.Interface interfaceState, long portNum)
183 throws InterruptedException, ExecutionException {
184 Class<? extends InterfaceType> intfType;
185 if (interfaceState != null) {
186 intfType = interfaceState.getType();
188 LOG.error("Could not retrieve port type for interface to construct actions");
189 return Collections.emptyList();
192 List<ActionInfo> actionInfos = new ArrayList<>();
193 // Set the LLDP service Id which is 0
194 if (Tunnel.class.equals(intfType)) {
195 actionInfos.add(new ActionSetFieldTunnelId(BigInteger.ZERO));
197 actionInfos.add(new ActionOutput(new Uri(Long.toString(portNum))));
201 @SuppressWarnings("AbbreviationAsWordInName")
202 private static LLDPTLV buildLLDTLV(LLDPTLV.TLVType tlvType, byte[] abyTLV) {
203 return new LLDPTLV().setType(tlvType.getValue()).setLength((short) abyTLV.length).setValue(abyTLV);
206 private int getPacketId() {
207 int id = packetId.incrementAndGet();
209 LOG.debug("Resetting the LLDP Packet Id counter");
216 public Ethernet makeLLDPPacket(String nodeId, long portNum, byte[] srcMac, String sourceInterface) {
218 // Create LLDP TTL TLV
219 LLDPTLV lldpTlvTTL = buildLLDTLV(LLDPTLV.TLVType.TTL, new byte[] { (byte) 0, (byte) 120 });
221 LLDPTLV lldpTlvChassisId = buildLLDTLV(LLDPTLV.TLVType.ChassisID, LLDPTLV.createChassisIDTLVValue(colonize(
222 StringUtils.leftPad(Long.toHexString(MDSALUtil.getDpnIdFromNodeName(nodeId).longValue()), 16, "0"))));
223 LLDPTLV lldpTlvSystemName = buildLLDTLV(TLVType.SystemName, LLDPTLV.createSystemNameTLVValue(nodeId));
225 LLDPTLV lldpTlvPortId = buildLLDTLV(TLVType.PortID, LLDPTLV.createPortIDTLVValue(Long.toHexString(portNum)));
227 String customValue = sourceInterface + "#" + getPacketId();
229 LOG.debug("Sending LLDP packet, custome value {}", customValue);
231 LLDPTLV lldpTlvCustom = buildLLDTLV(TLVType.Custom, customValue.getBytes(LLDPTLV_CHARSET));
233 @SuppressWarnings("AbbreviationAsWordInName")
234 List<LLDPTLV> lstLLDPTLVCustom = new ArrayList<>();
235 lstLLDPTLVCustom.add(lldpTlvCustom);
237 LLDP lldpDiscoveryPacket = new LLDP();
238 lldpDiscoveryPacket.setChassisId(lldpTlvChassisId).setPortId(lldpTlvPortId).setTtl(lldpTlvTTL)
239 .setSystemNameId(lldpTlvSystemName).setOptionalTLVList(lstLLDPTLVCustom);
241 byte[] destMac = LLDP.LLDP_MULTICAST_MAC;
243 Ethernet ethernetPacket = new Ethernet();
244 ethernetPacket.setSourceMACAddress(srcMac).setDestinationMACAddress(destMac)
245 .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(lldpDiscoveryPacket);
247 return ethernetPacket;
250 private String colonize(String orig) {
251 return orig.replaceAll("(?<=..)(..)", ":$1");
255 public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
256 String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
257 return interfaceName + EtherTypes.LLDP;
260 private String getInterfaceName(EndpointType endpoint) {
261 String interfaceName = null;
262 if (endpoint instanceof Interface) {
263 interfaceName = ((Interface) endpoint).getInterfaceName();
265 return interfaceName;