org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessProtocolHandlerLLDP.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.vpnservice.alivenessmonitor.internal.AlivenessProtocolHandlerLLDP.java

Source

/*
 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.vpnservice.alivenessmonitor.internal;

import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.Future;

import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.liblldp.EtherTypes;
import org.opendaylight.controller.liblldp.LLDP;
import org.opendaylight.controller.liblldp.LLDPTLV;
import org.opendaylight.controller.liblldp.LLDPTLV.TLVType;
import org.opendaylight.controller.liblldp.Packet;
import org.opendaylight.controller.liblldp.PacketException;
import org.opendaylight.vpnservice.interfacemgr.globals.IfmConstants;
import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
import org.opendaylight.vpnservice.mdsalutil.ActionType;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.EndpointType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.endpoint.endpoint.type.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.alivenessmonitor.rev150629.monitor.configs.MonitoringInfo;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetPortFromInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;

public class AlivenessProtocolHandlerLLDP extends AbstractAlivenessProtocolHandler {
    private static final Logger LOG = LoggerFactory.getLogger(AlivenessProtocolHandlerLLDP.class);
    private AtomicInteger packetId = new AtomicInteger(0);

    public AlivenessProtocolHandlerLLDP(ServiceProvider serviceProvider) {
        super(serviceProvider);
    }

    @Override
    public Class<?> getPacketClass() {
        return LLDP.class;
    }

    @Override
    public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
        String sSourceDpnId = null;
        String sPortNumber = null;
        int nServiceId = -1;
        int packetId = 0;

        String sTmp = null;

        byte lldpTlvTypeCur;

        LLDP lldpPacket = (LLDP) protocolPacket;

        LLDPTLV lldpTlvCur = lldpPacket.getSystemNameId();
        if (lldpTlvCur != null) {
            sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
        }

        lldpTlvCur = lldpPacket.getPortId();
        if (lldpTlvCur != null) {
            sPortNumber = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
        }

        for (LLDPTLV lldpTlv : lldpPacket.getOptionalTLVList()) {
            lldpTlvTypeCur = lldpTlv.getType();

            if (lldpTlvTypeCur == LLDPTLV.TLVType.SystemName.getValue()) {
                sSourceDpnId = new String(lldpTlvCur.getValue(), Charset.defaultCharset());
            }
        }

        for (LLDPTLV lldpTlv : lldpPacket.getCustomTlvList()) {
            lldpTlvTypeCur = lldpTlv.getType();

            if (lldpTlvTypeCur == LLDPTLV.TLVType.Custom.getValue()) {
                sTmp = new String(lldpTlv.getValue());
                nServiceId = 0;
            }
        }

        String interfaceName = null;

        //TODO: Check if the below fields are required
        if (!Strings.isNullOrEmpty(sTmp) && sTmp.contains("#")) {
            String[] asTmp = sTmp.split("#");
            interfaceName = asTmp[0];
            packetId = Integer.parseInt(asTmp[1]);
            LOG.debug("Custom LLDP Value on received packet: " + sTmp);
        }

        if (!Strings.isNullOrEmpty(interfaceName)) {
            String monitorKey = new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString();
            return monitorKey;
        } else {
            LOG.debug("No associated interface found to handle received LLDP Packet");
        }
        return null;
    }

    @Override
    public void sendPacketOut(MonitoringInfo monitorInfo) {
        String sourceInterface;

        EndpointType source = monitorInfo.getSource().getEndpointType();
        if (source instanceof Interface) {
            Interface intf = (Interface) source;
            sourceInterface = intf.getInterfaceName();
        } else {
            LOG.warn("Invalid source endpoint. Could not retrieve source interface to send LLDP Packet");
            return;
        }

        //Get Mac Address for the source interface
        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = getInterfaceFromOperDS(
                sourceInterface);
        byte[] sourceMac = getMacAddress(interfaceState, sourceInterface);
        if (sourceMac == null) {
            LOG.error("Could not read mac address for the source interface {} from the Inventory. "
                    + "LLDP packet cannot be send.", sourceInterface);
            return;
        }

        OdlInterfaceRpcService interfaceService = serviceProvider.getInterfaceManager();

        long nodeId = -1, portNum = -1;
        try {
            String lowerLayerIf = interfaceState.getLowerLayerIf().get(0);
            NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
            nodeId = Long.valueOf(getDpnFromNodeConnectorId(nodeConnectorId));
            portNum = Long.valueOf(getPortNoFromNodeConnectorId(nodeConnectorId));
        } catch (Exception e) {
            LOG.error("Failed to retrieve node id and port number ", e);
            return;
        }

        Ethernet ethenetLLDPPacket = makeLLDPPacket(Long.toString(nodeId), portNum, 0, sourceMac, sourceInterface);

        try {
            List<ActionInfo> actions = getInterfaceActions(interfaceState, portNum);
            if (actions.isEmpty()) {
                LOG.error("No interface actions to send packet out over interface {}", sourceInterface);
                return;
            }
            TransmitPacketInput transmitPacketInput = MDSALUtil.getPacketOut(actions, ethenetLLDPPacket.serialize(),
                    nodeId, MDSALUtil.getNodeConnRef(BigInteger.valueOf(nodeId), "0xfffffffd"));
            serviceProvider.getPacketProcessingService().transmitPacket(transmitPacketInput);
        } catch (Exception e) {
            LOG.error("Error while sending LLDP Packet", e);
        }
    }

    public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
        /*
         * NodeConnectorId is of form 'openflow:dpnid:portnum'
         */
        String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
        return split[1];
    }

    public static String getPortNoFromNodeConnectorId(NodeConnectorId portId) {
        /*
         * NodeConnectorId is of form 'openflow:dpnid:portnum'
         */
        String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
        return split[2];
    }

    private List<ActionInfo> getInterfaceActions(
            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState,
            long portNum) throws InterruptedException, ExecutionException {
        Class<? extends InterfaceType> intfType;
        if (interfaceState != null) {
            intfType = interfaceState.getType();
        } else {
            LOG.error("Could not retrieve port type for interface {} to construct actions",
                    interfaceState.getName());
            return Collections.emptyList();
        }

        List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
        // Set the LLDP service Id which is 0
        if (Tunnel.class.equals(intfType)) {
            actionInfos.add(
                    new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { BigInteger.valueOf(0) }));
        }
        actionInfos.add(new ActionInfo(ActionType.output, new String[] { Long.toString(portNum) }));
        return actionInfos;
    }

    private static LLDPTLV buildLLDTLV(LLDPTLV.TLVType tlvType, byte[] abyTLV) {
        return new LLDPTLV().setType(tlvType.getValue()).setLength((short) abyTLV.length).setValue(abyTLV);
    }

    private int getPacketId() {
        int id = packetId.incrementAndGet();
        if (id > 16000) {
            LOG.debug("Resetting the LLDP Packet Id counter");
            packetId.set(0);
        }

        return id;
    }

    public Ethernet makeLLDPPacket(String nodeId, long portNum, int serviceId, byte[] srcMac,
            String sourceInterface) {

        // Create LLDP TTL TLV
        LLDPTLV lldpTlvTTL = buildLLDTLV(LLDPTLV.TLVType.TTL, new byte[] { (byte) 0, (byte) 120 });

        LLDPTLV lldpTlvChassisId = buildLLDTLV(LLDPTLV.TLVType.ChassisID,
                LLDPTLV.createChassisIDTLVValue(colonize(StringUtils
                        .leftPad(Long.toHexString(MDSALUtil.getDpnIdFromNodeName(nodeId).longValue()), 16, "0"))));
        LLDPTLV lldpTlvSystemName = buildLLDTLV(TLVType.SystemName, LLDPTLV.createSystemNameTLVValue(nodeId));

        LLDPTLV lldpTlvPortId = buildLLDTLV(TLVType.PortID,
                LLDPTLV.createPortIDTLVValue(Long.toHexString(portNum)));

        String customValue = sourceInterface + "#" + getPacketId();

        LOG.debug("Sending LLDP packet, custome value " + customValue);

        LLDPTLV lldpTlvCustom = buildLLDTLV(TLVType.Custom, customValue.getBytes());

        List<LLDPTLV> lstLLDPTLVCustom = new ArrayList<>();
        lstLLDPTLVCustom.add(lldpTlvCustom);

        LLDP lldpDiscoveryPacket = new LLDP();
        lldpDiscoveryPacket.setChassisId(lldpTlvChassisId).setPortId(lldpTlvPortId).setTtl(lldpTlvTTL)
                .setSystemNameId(lldpTlvSystemName).setOptionalTLVList(lstLLDPTLVCustom);

        byte[] destMac = LLDP.LLDPMulticastMac;

        Ethernet ethernetPacket = new Ethernet();
        ethernetPacket.setSourceMACAddress(srcMac).setDestinationMACAddress(destMac)
                .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(lldpDiscoveryPacket);

        return ethernetPacket;
    }

    private String colonize(String orig) {
        return orig.replaceAll("(?<=..)(..)", ":$1");
    }

    @Override
    public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
        String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
        return new StringBuilder().append(interfaceName).append(EtherTypes.LLDP).toString();
    }

    private String getInterfaceName(EndpointType endpoint) {
        String interfaceName = null;
        if (endpoint instanceof Interface) {
            interfaceName = ((Interface) endpoint).getInterfaceName();
        }
        return interfaceName;
    }

}