/* * 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.netvirt.vpnmanager; import com.google.common.base.Optional; import com.google.common.util.concurrent.SettableFuture; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.netvirt.bgpmanager.api.IBgpManager; import org.opendaylight.netvirt.fibmanager.api.IFibManager; import org.opendaylight.netvirt.fibmanager.api.RouteOrigin; import org.opendaylight.netvirt.vpnmanager.intervpnlink.InterVpnLinkUtil; import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.Future; public class VpnRpcServiceImpl implements VpnRpcService { private static final Logger LOG = LoggerFactory.getLogger(VpnRpcServiceImpl.class); private final DataBroker dataBroker; private final IdManagerService idManager; private final VpnInterfaceManager vpnInterfaceMgr; private IFibManager fibManager; private IBgpManager bgpManager; public VpnRpcServiceImpl(final DataBroker dataBroker, final IdManagerService idManager, final VpnInterfaceManager vpnIfaceMgr, final IFibManager fibManager, IBgpManager bgpManager) { this.dataBroker = dataBroker; this.idManager = idManager; this.vpnInterfaceMgr = vpnIfaceMgr; this.fibManager = fibManager; this.bgpManager = bgpManager; } public void setFibManager(IFibManager fibMgr) { this.fibManager = fibMgr; } /** * to generate label for the given ip prefix from the associated VPN * */ @Override public Future> generateVpnLabel(GenerateVpnLabelInput input) { String vpnName = input.getVpnName(); String ipPrefix = input.getIpPrefix(); SettableFuture> futureResult = SettableFuture.create(); String rd = VpnUtil.getVpnRd(dataBroker, vpnName); long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ipPrefix)); if (label == 0) { String msg = String.format("Could not retrieve the label for prefix {} in VPN {}", ipPrefix, vpnName); LOG.error(msg); futureResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, msg) .build()); } else { GenerateVpnLabelOutput output = new GenerateVpnLabelOutputBuilder().setLabel(label).build(); futureResult.set(RpcResultBuilder.success(output).build()); } return futureResult; } /** * to remove label for the given ip prefix from the associated VPN * */ @Override public Future> removeVpnLabel(RemoveVpnLabelInput input) { String vpnName = input.getVpnName(); String ipPrefix = input.getIpPrefix(); String rd = VpnUtil.getVpnRd(dataBroker, vpnName); SettableFuture> futureResult = SettableFuture.create(); VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ipPrefix)); futureResult.set(RpcResultBuilder.success().build()); return futureResult; } private Collection validateAddStaticRouteInput(AddStaticRouteInput input) { Collection rpcErrors = new ArrayList(); String destination = input.getDestination(); String vpnInstanceName = input.getVpnInstanceName(); String nexthop = input.getNexthop(); if ( destination == null || destination.isEmpty() ) { String message = "destination parameter is mandatory"; rpcErrors.add(RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "addStaticRoute", message)); } if ( vpnInstanceName == null || vpnInstanceName.isEmpty() ) { String message = "vpnInstanceName parameter is mandatory"; rpcErrors.add(RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "addStaticRoute", message)); } if ( nexthop == null || nexthop.isEmpty() ) { String message = "nexthop parameter is mandatory"; rpcErrors.add(RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "addStaticRoute", message)); } return rpcErrors; } @Override public Future> addStaticRoute(AddStaticRouteInput input) { SettableFuture> result = SettableFuture.create(); String destination = input.getDestination(); String vpnInstanceName = input.getVpnInstanceName(); String nexthop = input.getNexthop(); Long label = input.getLabel(); LOG.info("Adding static route for Vpn {} with destination {}, nexthop {} and label {}", vpnInstanceName, destination, nexthop, label); Collection rpcErrors = validateAddStaticRouteInput(input); if ( !rpcErrors.isEmpty() ) { result.set(RpcResultBuilder.failed().withRpcErrors(rpcErrors).build()); return result; } if ( label == null || label == 0 ) { label = (long) VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil.getNextHopLabelKey(vpnInstanceName, destination)); if ( label == 0 ) { String message = "Unable to retrieve a new Label for the new Route"; result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, message).build()); return result; } } String vpnRd = VpnUtil.getVpnRd(dataBroker, input.getVpnInstanceName()); if ( vpnRd == null ) { String message = "Could not find Route-Distinguisher for VpnName " + vpnInstanceName; result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, message).build()); return result; } Optional interVpnLink = InterVpnLinkUtil.getInterVpnLinkByEndpointIp(dataBroker, nexthop); if ( interVpnLink.isPresent() ) { // A static route pointing to an InterVpnLink endpoint: write the VrfEntry and inform DC-GW LOG.debug("addStaticRoute: Writing FibEntry to DS: vpnRd={}, prefix={}, label={}, nexthop={} (interVpnLink)", vpnRd, destination, label, nexthop); fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, destination, Arrays.asList(nexthop), label.intValue(), RouteOrigin.STATIC, null); // The nexthop list to advertise to BGP contains the list of IPs of those DPNs where the // endpoint has been instantiated List nexthopList = new ArrayList(); List dpns = InterVpnLinkUtil.getVpnLinkEndpointDPNsByIp(dataBroker, nexthop); for ( BigInteger dpnId : dpns ) { nexthopList.add(InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId)); } try { LOG.debug("addStaticRoute:advertise IVpnLink route to BGP: vpnRd={}, prefix={}, label={}, nexthops={}", vpnRd, destination, label, nexthopList); bgpManager.advertisePrefix(vpnRd, destination, nexthopList, label.intValue()); } catch (Exception e) { String errMsg = "Could not advertise route [vpn=" + vpnRd + ", prefix=" + destination + ", label=" + label + ", nexthops=" + nexthopList + ", ] to BGP. Reason: " + e; LOG.warn("Could not advertise route [vpn={}, prefix={}, label={}, nexthops={}] to BGP. Reason: ", vpnRd, destination, label, nexthopList, e); result.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION, errMsg) .build()); } } else { vpnInterfaceMgr.addExtraRoute(destination, nexthop, vpnRd, null /*routerId */, label.intValue(), null /* intfName */, null, null); } AddStaticRouteOutput labelOutput = new AddStaticRouteOutputBuilder().setLabel(label).build(); result.set(RpcResultBuilder.success(labelOutput).build()); return result; } private Collection validateRemoveStaticRouteInput(RemoveStaticRouteInput input) { Collection rpcErrors = new ArrayList(); String destination = input.getDestination(); String vpnInstanceName = input.getVpnInstanceName(); String nexthop = input.getNexthop(); if ( destination == null || destination.isEmpty() ) { String message = "destination parameter is mandatory"; rpcErrors.add(RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "removeStaticRoute", message)); } if ( vpnInstanceName == null || vpnInstanceName.isEmpty() ) { String message = "vpnInstanceName parameter is mandatory"; rpcErrors.add(RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "removeStaticRoute", message)); } if ( nexthop == null || nexthop.isEmpty() ) { String message = "nexthop parameter is mandatory"; rpcErrors.add(RpcResultBuilder.newError(RpcError.ErrorType.PROTOCOL, "removeStaticRoute", message)); } return rpcErrors; } @Override public Future> removeStaticRoute(RemoveStaticRouteInput input) { SettableFuture> result = SettableFuture.create(); String destination = input.getDestination(); String vpnInstanceName = input.getVpnInstanceName(); String nexthop = input.getNexthop(); LOG.info("Removing static route with destination={}, nexthop={} in VPN={}", destination, nexthop, vpnInstanceName); Collection rpcErrors = validateRemoveStaticRouteInput(input); if ( !rpcErrors.isEmpty() ) { result.set(RpcResultBuilder.failed().withRpcErrors(rpcErrors).build()); return result; } String vpnRd = VpnUtil.getVpnRd(dataBroker, input.getVpnInstanceName()); if ( vpnRd == null ) { String message = "Could not find Route-Distinguisher for VpnName " + vpnInstanceName; result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, message).build()); return result; } Optional optVpnLink = InterVpnLinkUtil.getInterVpnLinkByEndpointIp(dataBroker, nexthop); if ( optVpnLink.isPresent() ) { fibManager.removeOrUpdateFibEntry(dataBroker, vpnRd, destination, nexthop, null); try { bgpManager.withdrawPrefix(vpnRd, destination); } catch (Exception e) { LOG.warn("Could not withdraw route [vpn={} prefix={}] to BGP. Reason:", vpnRd, destination, e); } } else { vpnInterfaceMgr.delExtraRoute(destination, nexthop, vpnRd, null /*routerId*/, null /*intfName*/, null); } result.set(RpcResultBuilder.success().build()); return result; } }