/* * Copyright (c) 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.dhcpservice; import java.math.BigInteger; import java.util.List; import org.apache.commons.lang3.tuple.ImmutablePair; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants; import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener; import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils; import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; 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.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.util.concurrent.FutureCallback; public class DhcpInterfaceEventListener extends AbstractDataChangeListener implements AutoCloseable { private static final Logger logger = LoggerFactory.getLogger(DhcpInterfaceEventListener.class); private DhcpManager dhcpManager; private ListenerRegistration listenerRegistration; private DataBroker dataBroker; private static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @Override public void onSuccess(Void result) { logger.debug("Success in Datastore write operation"); } @Override public void onFailure(Throwable error) { logger.error("Error in Datastore write operation", error); } }; private DhcpExternalTunnelManager dhcpExternalTunnelManager; public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker, DhcpExternalTunnelManager dhcpExternalTunnelManager) { super(Interface.class); this.dhcpManager = dhcpManager; this.dataBroker = dataBroker; this.dhcpExternalTunnelManager = dhcpExternalTunnelManager; registerListener(); } private void registerListener() { try { listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, getWildCardPath(), DhcpInterfaceEventListener.this, DataChangeScope.SUBTREE); } catch (final Exception e) { logger.error("DhcpInterfaceEventListener DataChange listener registration fail!", e); throw new IllegalStateException("DhcpInterfaceEventListener registration Listener failed.", e); } } private InstanceIdentifier getWildCardPath() { return InstanceIdentifier.create(InterfacesState.class).child(Interface.class); } @Override public void close() throws Exception { if (listenerRegistration != null) { try { listenerRegistration.close(); } catch (final Exception e) { logger.error("Error when cleaning up DataChangeListener.", e); } listenerRegistration = null; } logger.info("Interface Manager Closed"); } @Override protected void remove(InstanceIdentifier identifier, Interface del) { List ofportIds = del.getLowerLayerIf(); if (ofportIds == null || ofportIds.isEmpty()) { return; } NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0)); BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId)); org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = DhcpServiceUtils.getInterfaceFromConfigDS(del.getName(), dataBroker); if (iface != null) { IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class); if (tunnelInterface != null && !tunnelInterface.isInternal()) { IpAddress tunnelIp = tunnelInterface.getTunnelDestination(); List dpns = DhcpServiceUtils.getListOfDpns(dataBroker); if (dpns.contains(dpId)) { dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId); } return; } } String interfaceName = del.getName(); logger.trace("Received remove DCN for interface {} dpId {}", interfaceName, dpId); unInstallDhcpEntries(interfaceName, dpId); dhcpManager.removeInterfaceCache(interfaceName); } @Override protected void update(InstanceIdentifier identifier, Interface original, Interface update) { List ofportIds = update.getLowerLayerIf(); if (ofportIds == null || ofportIds.isEmpty()) { return; } NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0)); BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId)); String interfaceName = update.getName(); org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = DhcpServiceUtils.getInterfaceFromConfigDS(interfaceName, dataBroker); if (iface == null) { logger.trace("Interface {} is not present in the config DS", interfaceName); return; } if (update.getType() == null) { logger.trace("Interface type for interface {} is null", interfaceName); return; } if ((original.getOperStatus().getIntValue() ^ update.getOperStatus().getIntValue()) == 0) { logger.trace("Interface operstatus {} is same", update.getOperStatus()); return; } if (Tunnel.class.equals(update.getType())) { IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class); if (tunnelInterface != null && !tunnelInterface.isInternal()) { IpAddress tunnelIp = tunnelInterface.getTunnelDestination(); List dpns = DhcpServiceUtils.getListOfDpns(dataBroker); if (dpns.contains(dpId)) { if (update.getOperStatus() == OperStatus.Down) { dhcpExternalTunnelManager.handleTunnelStateDown(tunnelIp, dpId); } else if (update.getOperStatus() == OperStatus.Up) { dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId); } } } return; } if (update.getOperStatus() == OperStatus.Down) { unInstallDhcpEntries(interfaceName, dpId); dhcpManager.removeInterfaceCache(interfaceName); } else if (update.getOperStatus() == OperStatus.Up) { if (!dpId.equals(DHCPMConstants.INVALID_DPID)) { installDhcpEntries(interfaceName, dpId); dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair(dpId, update.getPhysAddress().getValue())); } } } @Override protected void add(InstanceIdentifier identifier, Interface add) { String interfaceName = add.getName(); List ofportIds = add.getLowerLayerIf(); if (ofportIds == null || ofportIds.isEmpty()) { return; } NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0)); BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId)); logger.trace("Received add DCN for interface {}, dpid {}", interfaceName, dpId); org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = DhcpServiceUtils.getInterfaceFromConfigDS(add.getName(), dataBroker); if (iface != null) { IfTunnel tunnelInterface = iface.getAugmentation(IfTunnel.class); if (tunnelInterface != null && !tunnelInterface.isInternal()) { IpAddress tunnelIp = tunnelInterface.getTunnelDestination(); List dpns = DhcpServiceUtils.getListOfDpns(dataBroker); if (dpns.contains(dpId)) { dhcpExternalTunnelManager.handleTunnelStateUp(tunnelIp, dpId); } return; } } if (!dpId.equals(DHCPMConstants.INVALID_DPID)) { installDhcpEntries(interfaceName, dpId); dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair(dpId, add.getPhysAddress().getValue())); } } private String getNeutronMacAddress(String interfaceName) { Port port = dhcpManager.getNeutronPort(interfaceName); if (port!=null) { logger.trace("Port found in neutron. Interface Name {}, port {}", interfaceName, port); return port.getMacAddress(); } return null; } private void unInstallDhcpEntries(String interfaceName, BigInteger dpId) { String vmMacAddress = getAndRemoveVmMacAddress(interfaceName); dhcpManager.unInstallDhcpEntries(dpId, vmMacAddress); } private void installDhcpEntries(String interfaceName, BigInteger dpId) { String vmMacAddress = getAndUpdateVmMacAddress(interfaceName); dhcpManager.installDhcpEntries(dpId, vmMacAddress); } private String getAndUpdateVmMacAddress(String interfaceName) { InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(InterfaceNameMacAddresses.class).child(InterfaceNameMacAddress.class, new InterfaceNameMacAddressKey(interfaceName)).build(); Optional existingEntry = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, instanceIdentifier); if (!existingEntry.isPresent()) { logger.trace("Entry for interface {} missing in InterfaceNameVmMacAddress map", interfaceName); String vmMacAddress = getNeutronMacAddress(interfaceName); if (vmMacAddress==null || vmMacAddress.isEmpty()) { return null; } logger.trace("Updating InterfaceNameVmMacAddress map with {}, {}", interfaceName,vmMacAddress); InterfaceNameMacAddress interfaceNameMacAddress = new InterfaceNameMacAddressBuilder().setKey(new InterfaceNameMacAddressKey(interfaceName)).setInterfaceName(interfaceName).setMacAddress(vmMacAddress).build(); MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, instanceIdentifier, interfaceNameMacAddress); return vmMacAddress; } return existingEntry.get().getMacAddress(); } private String getAndRemoveVmMacAddress(String interfaceName) { InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(InterfaceNameMacAddresses.class).child(InterfaceNameMacAddress.class, new InterfaceNameMacAddressKey(interfaceName)).build(); Optional existingEntry = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, instanceIdentifier); if (existingEntry.isPresent()) { String vmMacAddress = existingEntry.get().getMacAddress(); logger.trace("Entry for interface found in InterfaceNameVmMacAddress map {}, {}", interfaceName, vmMacAddress); MDSALDataStoreUtils.asyncRemove(dataBroker, LogicalDatastoreType.OPERATIONAL, instanceIdentifier, DEFAULT_CALLBACK); return vmMacAddress; } logger.trace("Entry for interface {} missing in InterfaceNameVmMacAddress map", interfaceName); return null; } }