/* * Copyright (c) 2015 China Telecom Beijing Research Institute 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.ovsdb.hwvtepsouthbound.transact; import static org.opendaylight.ovsdb.lib.operations.Operations.op; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import org.opendaylight.mdsal.binding.api.DataTreeModification; import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepDeviceInfo; import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants; import org.opendaylight.ovsdb.lib.notation.UUID; import org.opendaylight.ovsdb.lib.operations.TransactionBuilder; import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable; import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils; import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch; import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal; import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote; import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort; import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal; import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote; import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogicalSwitchUcastsRemoveCommand extends AbstractTransactCommand { private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchUcastsRemoveCommand.class); volatile Map> updatedPortBindings = new HashMap<>(); private AtomicInteger retryCount = new AtomicInteger(5); private LogicalSwitches logicalSwitches; private InstanceIdentifier nodeIid; private List deletedLs; private boolean firstAttempt = true; public LogicalSwitchUcastsRemoveCommand(HwvtepOperationalState state, Collection> changes, List deletedLs, LogicalSwitches logicalSwitches) { super(state, changes); this.deletedLs = deletedLs; this.logicalSwitches = logicalSwitches; this.nodeIid = getOperationalState().getConnectionInstance().getInstanceIdentifier(); } @Override public void execute(TransactionBuilder transaction) { InstanceIdentifier lsKey = nodeIid.augmentation(HwvtepGlobalAugmentation.class) .child(LogicalSwitches.class, logicalSwitches.key()); HwvtepDeviceInfo.DeviceData deviceData = super.fetchDeviceData(LogicalSwitches.class, lsKey); if (deviceData != null && deviceData.getUuid() != null) { UUID logicalSwitchUuid = deviceData.getUuid(); UcastMacsRemote ucastMacsRemote = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), UcastMacsRemote.class, null); transaction.add(op.delete(ucastMacsRemote.getSchema()) .where(ucastMacsRemote.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build()); UcastMacsLocal ucastMacsLocal = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), UcastMacsLocal.class, null); transaction.add(op.delete(ucastMacsLocal.getSchema()) .where(ucastMacsLocal.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build()); McastMacsRemote mcastMacsRemote = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), McastMacsRemote.class, null); transaction.add(op.delete(mcastMacsRemote.getSchema()) .where(mcastMacsRemote.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build()); McastMacsLocal mcastMacsLocal = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), McastMacsLocal.class, null); transaction.add(op.delete(mcastMacsLocal.getSchema()) .where(mcastMacsLocal.getLogicalSwitchColumn().getSchema().opEqual(logicalSwitchUuid)).build()); if (firstAttempt) { LogicalSwitch logicalSwitch = TyperUtils.getTypedRowWrapper( transaction.getDatabaseSchema(), LogicalSwitch.class, null); transaction.add(op.delete(logicalSwitch.getSchema()).where(logicalSwitch.getNameColumn().getSchema() .opEqual(logicalSwitches.getHwvtepNodeName().getValue())).build()); updateControllerTxHistory(TransactionType.DELETE, new StringBuilder(logicalSwitch.toString()) .append(": ").append(logicalSwitches.getHwvtepNodeName()).append(" ") .append(logicalSwitches.getLogicalSwitchUuid()).append(" ") .append(logicalSwitches.getTunnelKey())); LOG.info("CONTROLLER - {} {} {} {} {}", TransactionType.DELETE, logicalSwitch, logicalSwitches.getHwvtepNodeName(), logicalSwitches.getLogicalSwitchUuid(), logicalSwitches.getTunnelKey()); } else { for (Entry> entry : updatedPortBindings.entrySet()) { PhysicalPort physicalPort = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalPort.class); physicalPort.setName(entry.getKey()); physicalPort.setVlanBindings(entry.getValue()); transaction.add(op.update(physicalPort) .where(physicalPort.getNameColumn().getSchema().opEqual(physicalPort.getName())).build()); updateControllerTxHistory(TransactionType.UPDATE, physicalPort); LOG.info("CONTROLLER - {} {}", TransactionType.UPDATE, physicalPort); } } } else { firstAttempt = false; onSuccess(transaction); } } @Override protected List getData(HwvtepGlobalAugmentation augmentation) { return augmentation.getLogicalSwitches(); } @Override protected boolean areEqual(LogicalSwitches logicalSwitches1 , LogicalSwitches logicalSwitches2) { return logicalSwitches1.key().equals(logicalSwitches2.key()) && Objects.equals(logicalSwitches1.getTunnelKey(), logicalSwitches2.getTunnelKey()); } @Override public void onSuccess(TransactionBuilder tx) { if (firstAttempt) { //LOG.error("check succeeded in deletion of logical swtich at first attempt "); //succeed in removing the logical switch upon first attempt return; } //LOG.error("check succeeded in deletion of logical swtich after first attempt "); PlainLogicalSwitchRemoveCmd cmd = new PlainLogicalSwitchRemoveCmd( newOperState(), getChanges(), logicalSwitches, HwvtepSouthboundConstants.LS_REMOVE_RETRIES); hwvtepOperationalState.getConnectionInstance().transact(cmd); } @Override public void onFailure(TransactionBuilder tx) { //Failed to remove logical swith upon first attempt, //will attempt to remove the local ucasts and vlan bindings alone in the next attemtps firstAttempt = false; getFreshPortBindingsExcludingDeleted(); super.onFailure(tx); } private void getFreshPortBindingsExcludingDeleted() { Set deletedLsUuids = new HashSet<>(); for (LogicalSwitches ls : deletedLs) { InstanceIdentifier lsKey = nodeIid .augmentation(HwvtepGlobalAugmentation.class) .child(LogicalSwitches.class, ls.key()); HwvtepDeviceInfo.DeviceData deviceData = super.fetchDeviceData(LogicalSwitches.class, lsKey); if (deviceData.getUuid() != null) { deletedLsUuids.add(deviceData.getUuid()); } } updatedPortBindings = new HashMap<>(); List portsFromDevice = getOperationalState().getConnectionInstance() .getHwvtepTableReader().getHwvtepTableEntries(VlanBindings.class); if (portsFromDevice == null || portsFromDevice.isEmpty()) { LOG.debug("Check did not get any bindings from tor while doing failure of logical switch delete"); return; } portsFromDevice.stream() .map(row -> (PhysicalPort) row) .filter(port -> port.getVlanBindingsColumn() != null && port.getVlanBindingsColumn().getData() != null) .forEach(port -> { int originalBindingsSize = port.getVlanBindingsColumn().getData().size(); Map bindingsAfterExclusion = excludeVlanBindings(deletedLsUuids, port); if (bindingsAfterExclusion.size() < originalBindingsSize) { updatedPortBindings.put(port.getName(), bindingsAfterExclusion); } }); } private Map excludeVlanBindings(Set deletedLsUuids, PhysicalPort port) { return port.getVlanBindingsColumn().getData() .entrySet().stream() .peek(entry -> { if (deletedLsUuids.contains(entry.getValue())) { LOG.trace("check Excluding the vlan binding {}", entry.getValue()); } }) .filter(entry -> !deletedLsUuids.contains(entry.getValue())) .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue())); } public boolean retry() { boolean ret = retryCount.decrementAndGet() > 0; return ret; } protected boolean isDeleteCmd() { return true; } }