/* * 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.natservice.internal; import java.math.BigInteger; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; 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.GetDpidFromInterfaceInputBuilder; 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.OdlInterfaceRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterAssociatedToVpn; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.RouterDisassociatedFromVpn; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetAddedToVpn; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetDeletedFromVpn; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortAddedToSubnet; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortRemovedFromSubnet; import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.SubnetUpdatedInVpn; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; public class RouterToVpnListener implements NeutronvpnListener { private static final Logger LOG = LoggerFactory.getLogger(RouterToVpnListener.class); private DataBroker dataBroker; private FloatingIPListener floatingIpListener; private OdlInterfaceRpcService interfaceManager; private ExternalRoutersListener externalRoutersListener; public RouterToVpnListener(DataBroker db) { dataBroker = db; } void setInterfaceManager(OdlInterfaceRpcService interfaceManager) { this.interfaceManager = interfaceManager; } void setFloatingIpListener(FloatingIPListener floatingIpListener) { this.floatingIpListener = floatingIpListener; } void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) { this.externalRoutersListener = externalRoutersListener; } /** * router association to vpn * */ @Override public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) { String routerName = notification.getRouterId().getValue(); String vpnName = notification.getVpnId().getValue(); //check router is associated to external network String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName); if(extNetwork != null) { LOG.debug("Router {} is associated with ext nw {}", routerName, extNetwork); handleDNATConfigurationForRouterAssociation(routerName, vpnName, extNetwork); externalRoutersListener.changeLocalVpnIdToBgpVpnId(routerName, vpnName); } else { LOG.debug("Ignoring the Router {} association with VPN {} since it is not external router", routerName); } } /** * router disassociation from vpn * */ @Override public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) { String routerName = notification.getRouterId().getValue(); String vpnName = notification.getVpnId().getValue(); //check router is associated to external network String extNetwork = NatUtil.getAssociatedExternalNetwork(dataBroker, routerName); if(extNetwork != null) { LOG.debug("Router {} is associated with ext nw {}", routerName, extNetwork); handleDNATConfigurationForRouterDisassociation(routerName, vpnName, extNetwork); externalRoutersListener.changeBgpVpnIdToLocalVpnId(routerName, vpnName); } else { LOG.debug("Ignoring the Router {} association with VPN {} since it is not external router", routerName); } } void handleDNATConfigurationForRouterAssociation(String routerName, String vpnName, String externalNetwork) { InstanceIdentifier routerPortsId = NatUtil.getRouterPortsId(routerName); Optional optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId); if(!optRouterPorts.isPresent()) { LOG.debug("Could not read Router Ports data object with id: {} to handle associate vpn {}", routerName, vpnName); return; } Uuid networkId = Uuid.getDefaultInstance(externalNetwork); RouterPorts routerPorts = optRouterPorts.get(); List interfaces = routerPorts.getPorts(); Map portToDpnMap = new HashMap<>(); for(Ports port : interfaces) { String portName = port.getPortName(); BigInteger dpnId = getDpnForInterface(interfaceManager, portName); if(dpnId.equals(BigInteger.ZERO)) { LOG.debug("DPN not found for {}, skip handling of router {} association with vpn", portName, routerName, vpnName); continue; } portToDpnMap.put(portName, dpnId); List ipMapping = port.getIpMapping(); for(IpMapping ipMap : ipMapping) { String externalIp = ipMap.getExternalIp(); //remove all NAT related entries with routerName //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, null, ipMap.getInternalIp(), externalIp); //Create NAT entries with VPN Id LOG.debug("Updating DNAT flows with VPN metadata {} ", vpnName); floatingIpListener.createNATOnlyFlowEntries(dpnId, portName, routerName, vpnName, networkId, ipMap.getInternalIp(), externalIp); } } } void handleDNATConfigurationForRouterDisassociation(String routerName, String vpnName, String externalNetwork) { InstanceIdentifier routerPortsId = NatUtil.getRouterPortsId(routerName); Optional optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId); if(!optRouterPorts.isPresent()) { LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate vpn {}", routerName, vpnName); return; } Uuid networkId = Uuid.getDefaultInstance(externalNetwork); RouterPorts routerPorts = optRouterPorts.get(); List interfaces = routerPorts.getPorts(); for(Ports port : interfaces) { String portName = port.getPortName(); BigInteger dpnId = getDpnForInterface(interfaceManager, portName); if(dpnId.equals(BigInteger.ZERO)) { LOG.debug("DPN not found for {}, skip handling of router {} association with vpn", portName, routerName, vpnName); continue; } List ipMapping = port.getIpMapping(); for(IpMapping ipMap : ipMapping) { String externalIp = ipMap.getExternalIp(); //remove all NAT related entries with routerName //floatingIpListener.removeNATOnlyFlowEntries(dpnId, portName, routerName, vpnName, ipMap.getInternalIp(), externalIp); //Create NAT entries with VPN Id floatingIpListener.createNATOnlyFlowEntries(dpnId, portName, routerName, null, networkId, ipMap.getInternalIp(), externalIp); } } } private BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) { BigInteger nodeId = BigInteger.ZERO; try { GetDpidFromInterfaceInput dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build(); Future> dpIdOutput = interfaceManagerRpcService.getDpidFromInterface(dpIdInput); RpcResult dpIdResult = dpIdOutput.get(); if (dpIdResult.isSuccessful()) { nodeId = dpIdResult.getResult().getDpid(); } else { LOG.error("Could not retrieve DPN Id for interface {}", ifName); } } catch (InterruptedException | ExecutionException e) { LOG.error("Exception when getting dpn for interface {}", ifName, e); } return nodeId; } @Override public void onSubnetAddedToVpn(SubnetAddedToVpn notification) { throw new RuntimeException("Unsupported notification"); } @Override public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) { throw new RuntimeException("Unsupported notification"); } @Override public void onPortAddedToSubnet(PortAddedToSubnet notification) { throw new RuntimeException("Unsupported notification"); } @Override public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) { throw new RuntimeException("Unsupported notification"); } @Override public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) { throw new RuntimeException("Unsupported notification"); } }