import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.netvirt.neutronvpn.evpn.manager.NeutronEvpnManager;
+import org.opendaylight.netvirt.neutronvpn.evpn.utils.NeutronEvpnUtils;
+import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
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.RemoveStaticRouteInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.OperationalPortStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.Features;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.Feature;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+@Singleton
public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, EventListener {
private static final Logger LOG = LoggerFactory.getLogger(NeutronvpnManager.class);
private final DataBroker dataBroker;
private final NeutronFloatingToFixedIpMappingChangeListener floatingIpMapListener;
private final IElanService elanService;
private final NeutronvpnConfig neutronvpnConfig;
+ private final IVpnManager vpnManager;
+ private final NeutronEvpnManager neutronEvpnManager;
+ private final NeutronEvpnUtils neutronEvpnUtils;
+ @Inject
public NeutronvpnManager(
final DataBroker dataBroker, final NotificationPublishService notiPublishService,
final NeutronvpnNatManager vpnNatMgr, final VpnRpcService vpnRpcSrv, final IElanService elanService,
final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener,
- final NeutronvpnConfig neutronvpnConfig) {
+ final NeutronvpnConfig neutronvpnConfig, final IVpnManager vpnManager) {
this.dataBroker = dataBroker;
nvpnNatManager = vpnNatMgr;
notificationPublishService = notiPublishService;
this.elanService = elanService;
floatingIpMapListener = neutronFloatingToFixedIpMappingChangeListener;
this.neutronvpnConfig = neutronvpnConfig;
+ this.vpnManager = vpnManager;
+ neutronEvpnManager = new NeutronEvpnManager(dataBroker, this);
+ neutronEvpnUtils = new NeutronEvpnUtils(dataBroker, vpnManager);
+
+ configureFeatures();
}
@Override
+ @PreDestroy
public void close() throws Exception {
LOG.info("{} close", getClass().getSimpleName());
}
- public NeutronvpnConfig getNeutronvpnConfig() {
- return neutronvpnConfig;
+ private void configureFeatures() {
+ InstanceIdentifier<Feature> iid = InstanceIdentifier.builder(
+ Neutron.class).child(Features.class).child(
+ Feature.class, new FeatureKey(OperationalPortStatus.class)).build();
+ Feature feature = new FeatureBuilder().setKey(new FeatureKey(OperationalPortStatus.class)).build();
+ try {
+ SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, iid, feature);
+ } catch (TransactionCommitFailedException e) {
+ LOG.warn("Error configuring feature " + feature, e);
+ }
+ }
+
+ public String getOpenDaylightVniRangesConfig() {
+ return neutronvpnConfig.getOpendaylightVniRanges();
}
// TODO Clean up the exception handling
// TODO Clean up the exception handling
@SuppressWarnings("checkstyle:IllegalCatch")
- private Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId) {
+ protected Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId) {
Subnetmap subnetmap = null;
SubnetmapBuilder builder = null;
InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
}
}
+ public void updateVpnInstanceWithRDs(String vpnInstanceId, final List<String> rds) {
+ InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
+ .child(VpnInstance.class, new VpnInstanceKey(vpnInstanceId)).build();
+ Optional<VpnInstance> vpnInstanceConfig =
+ NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
+ if (!vpnInstanceConfig.isPresent()) {
+ LOG.debug("No VpnInstance present under config vpnInstance:{}", vpnInstanceId);
+ return;
+ }
+ VpnInstance vpnInstance = vpnInstanceConfig.get();
+ VpnInstanceBuilder updateVpnInstanceBuilder = new VpnInstanceBuilder(vpnInstance);
+ Ipv4FamilyBuilder ipv4FamilyBuilder = new Ipv4FamilyBuilder(vpnInstance.getIpv4Family());
+ updateVpnInstanceBuilder.setIpv4Family(ipv4FamilyBuilder.setRouteDistinguisher(rds).build());
+ LOG.debug("Updating Config vpn-instance: {} with the list of RDs: {}", vpnInstanceId,rds);
+ try {
+ SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier,
+ updateVpnInstanceBuilder.build());
+ } catch (TransactionCommitFailedException ex) {
+ LOG.warn("Error configuring feature ", ex);
+ }
+ }
+
// TODO Clean up the exception handling
@SuppressWarnings("checkstyle:IllegalCatch")
private void updateVpnInstanceNode(String vpnName, List<String> rd, List<String> irt, List<String> ert,
l3vni = vpn.getL3vni();
}
- if (vpn.getRouteDistinguisher().size() > 1) {
- msg = String.format("Creation of VPN failed for VPN %s due to multiple RD input %s",
- vpn.getId().getValue(), vpn.getRouteDistinguisher());
- LOG.warn(msg);
- error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
- errorList.add(error);
- warningcount++;
- continue;
- }
List<String> existingRDs = NeutronvpnUtils.getExistingRDs(dataBroker);
if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
msg = String.format("Creation of L3VPN failed for VPN %s as another VPN with the same RD %s "
}
final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
+ final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
+ if (isVpnOfTypeL2(vpnInstance)) {
+ neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
+ NeutronEvpnUtils.Operation.ADD);
+ }
// Check if there are ports on this subnet and add corresponding
// vpn-interfaces
List<Uuid> portList = sn.getPortList();
return;
}
- final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- if (sn.getRouterInterfacePortId() != null) {
- portDataStoreCoordinator.enqueueJob("PORT-" + sn.getRouterInterfacePortId().getValue(), () -> {
- WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
- List<ListenableFuture<Void>> futures = new ArrayList<>();
- updateVpnInterface(newVpnId, oldVpnId,
- NeutronvpnUtils.getNeutronPort(dataBroker, sn.getRouterInterfacePortId()),
- isBeingAssociated, true, wrtConfigTxn);
- futures.add(wrtConfigTxn.submit());
- return futures;
- });
+ //Update Router Interface first synchronously.
+ //CAUTION: Please DONOT make the router interface VPN Movement as an asynchronous commit again !
+ try {
+ WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
+ updateVpnInterface(newVpnId, oldVpnId,
+ NeutronvpnUtils.getNeutronPort(dataBroker, sn.getRouterInterfacePortId()),
+ isBeingAssociated, true, wrtConfigTxn);
+ wrtConfigTxn.submit().checkedGet();
+ } catch (TransactionCommitFailedException e) {
+ LOG.error("Failed to update router interface {} in subnet {} from oldVpnId {} to newVpnId {}, returning",
+ sn.getRouterInterfacePortId().getValue(), subnet.getValue(), oldVpnId, newVpnId);
+ return;
}
// Check for ports on this subnet and update association of
for (Uuid port : portList) {
LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
port.getValue(), isBeingAssociated);
+ final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
portDataStoreCoordinator.enqueueJob("PORT-" + port.getValue(), () -> {
WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
List<ListenableFuture<Void>> futures = new ArrayList<>();
}
}
- protected void removeVpn(Uuid id) {
+ public void removeVpn(Uuid id) {
// read VPNMaps
VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, id);
Uuid router = (vpnMap != null) ? vpnMap.getRouterId() : null;
final Uuid routerId = vpnMap.getRouterId();
Subnetmap sn = NeutronvpnUtils.getSubnetmap(dataBroker, subnet);
+ final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
+ if (isVpnOfTypeL2(vpnInstance)) {
+ neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
+ NeutronEvpnUtils.Operation.DELETE);
+ }
if (sn != null) {
// Check if there are ports on this subnet; remove corresponding vpn-interfaces
List<Uuid> portList = sn.getPortList();
}
}
+ private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
+ return vpnInstance != null && vpnInstance.getType() == VpnInstance.Type.L2;
+ }
+
// TODO Clean up the exception handling
@SuppressWarnings("checkstyle:IllegalCatch")
protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
List<String> failedNwList = new ArrayList<>();
List<Uuid> passedNwList = new ArrayList<>();
if (!networks.isEmpty()) {
+ VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpn.getValue());
+ if (vpnInstance == null) {
+ LOG.error("VPN %s not present when associating network to it", vpn.getValue());
+ failedNwList.add(String.format("Failed to associate network on vpn %s as vpn is not present",
+ vpn.getValue()));
+ return failedNwList;
+ }
// process corresponding subnets for VPN
for (Uuid nw : networks) {
Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
} else if (vpnId != null) {
failedNwList.add(String.format("network %s already associated to another VPN %s", nw.getValue(),
vpnId.getValue()));
+ } else if (isVpnOfTypeL2(vpnInstance)
+ && (neutronEvpnUtils.isVpnAssociatedWithNetwork(vpnInstance))) {
+ LOG.error("EVPN supports only one network to be associated");
+ failedNwList.add(String.format("EVPN supports only one network to be associated"));
} else {
List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
LOG.debug("Adding network subnets...{}", networkSubnets);
return result;
}
- @Override
- public Future<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
- return null;
- }
-
- @Override
- public Future<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
- return null;
- }
-
/**
* It handles the invocations to the neutronvpn:associateRouter RPC method.
*/
return result;
}
- @Override
- public Future<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
- return null;
- }
-
/**
* It handles the invocations to the neutronvpn:dissociateRouter RPC method.
*/
return result;
}
- public String getOpenDaylightVniRangesConfig() {
- return neutronvpnConfig.getOpendaylightVniRanges();
- }
-
- public Boolean getEnforceOpenstackSemanticsConfig() {
- return neutronvpnConfig.isEnforceOpenstackSemantics();
- }
-
protected void handleNeutronRouterDeleted(Uuid routerId, List<Uuid> routerSubnetIds) {
// check if the router is associated to some VPN
Uuid vpnId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerId, true);
VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
.setName(infName)
.setVpnInstanceName(vpnId.getValue())
- .setIsRouterInterface(isRouterInterface);
+ .setRouterInterface(isRouterInterface);
if (adjacencies != null) {
vpnb.addAugmentation(Adjacencies.class, adjacencies);
}
protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
}
-}
\ No newline at end of file
+
+ @Override
+ public Future<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
+ return neutronEvpnManager.createEVPN(input);
+ }
+
+ @Override
+ public Future<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
+ return neutronEvpnManager.getEVPN(input);
+ }
+
+ @Override
+ public Future<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
+ return neutronEvpnManager.deleteEVPN(input);
+ }
+}