2 * Copyright © 2015, 2017 China Telecom Beijing Research Institute and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
11 import static org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil.schemaMismatchLog;
12 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
14 import com.google.common.collect.ImmutableMap;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.HashSet;
20 import java.util.Map.Entry;
21 import java.util.Optional;
23 import org.opendaylight.mdsal.binding.api.DataObjectModification;
24 import org.opendaylight.mdsal.binding.api.DataTreeModification;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
27 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
28 import org.opendaylight.ovsdb.lib.notation.Mutator;
29 import org.opendaylight.ovsdb.lib.notation.UUID;
30 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
31 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
32 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
33 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
34 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIpsKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsKey;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
54 public final class PhysicalSwitchUpdateCommand extends AbstractTransactCommand {
55 private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
57 public PhysicalSwitchUpdateCommand(final HwvtepOperationalState state,
58 final Collection<DataTreeModification<Node>> changes) {
59 super(state, changes);
63 public void execute(final TransactionBuilder transaction) {
64 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> created =
65 extractCreated(getChanges(),PhysicalSwitchAugmentation.class);
66 if (!created.isEmpty()) {
67 for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
69 updatePhysicalSwitch(transaction, physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
72 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> updated =
73 extractUpdatedSwitches(getChanges(),PhysicalSwitchAugmentation.class);
74 if (!updated.isEmpty()) {
75 for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
77 updatePhysicalSwitch(transaction, physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
83 private void updatePhysicalSwitch(final TransactionBuilder transaction,
84 final InstanceIdentifier<Node> iid, final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
85 LOG.debug("Creating a physical switch named: {}", physicalSwitchAugmentation.getHwvtepNodeName());
86 Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional =
87 getOperationalState().getPhysicalSwitchAugmentation(iid);
88 PhysicalSwitch physicalSwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
89 setDescription(physicalSwitch, physicalSwitchAugmentation);
90 setManagementIps(physicalSwitch, physicalSwitchAugmentation);
91 setTunnuleIps(physicalSwitch, operationalPhysicalSwitchOptional.orElseThrow());
93 setTunnels(transaction, iid, physicalSwitch, physicalSwitchAugmentation,
94 operationalPhysicalSwitchOptional.isPresent());
95 } catch (SchemaVersionMismatchException e) {
96 schemaMismatchLog("tunnels", "Physical_Switch", e);
98 if (!operationalPhysicalSwitchOptional.isPresent()) {
99 //create a physical switch
100 setName(physicalSwitch, physicalSwitchAugmentation, operationalPhysicalSwitchOptional);
101 String pswitchUuid = "PhysicalSwitch_" + HwvtepSouthboundMapper.getRandomUUID();
102 transaction.add(op.insert(physicalSwitch).withId(pswitchUuid));
103 transaction.add(op.comment("Physical Switch: Creating "
104 + physicalSwitchAugmentation.getHwvtepNodeName().getValue()));
105 //update global table
106 Global global = transaction.getTypedRowWrapper(Global.class);
107 global.setSwitches(Collections.singleton(new UUID(pswitchUuid)));
109 LOG.trace("execute: create physical switch: {}", physicalSwitch);
110 transaction.add(op.mutate(global)
111 .addMutation(global.getSwitchesColumn().getSchema(), Mutator.INSERT,
112 global.getSwitchesColumn().getData()));
113 transaction.add(op.comment("Global: Mutating "
114 + physicalSwitchAugmentation.getHwvtepNodeName().getValue() + " " + pswitchUuid));
116 PhysicalSwitchAugmentation updatedPhysicalSwitch = operationalPhysicalSwitchOptional.orElseThrow();
117 String existingPhysicalSwitchName = updatedPhysicalSwitch.getHwvtepNodeName().getValue();
118 /* In case TOR devices don't allow creation of PhysicalSwitch name might be null
119 * as user is only adding configurable parameters to MDSAL like BFD params
121 * TODO Note: Consider handling tunnel udpate/remove in separate command
123 if (existingPhysicalSwitchName == null) {
124 existingPhysicalSwitchName = operationalPhysicalSwitchOptional.orElseThrow()
125 .getHwvtepNodeName().getValue();
127 // Name is immutable, and so we *can't* update it. So we use extraPhysicalSwitch for the schema stuff
128 PhysicalSwitch extraPhysicalSwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
129 extraPhysicalSwitch.setName("");
130 LOG.trace("execute: updating physical switch: {}", physicalSwitch);
131 transaction.add(op.update(physicalSwitch)
132 .where(extraPhysicalSwitch.getNameColumn().getSchema().opEqual(existingPhysicalSwitchName))
134 transaction.add(op.comment("Physical Switch: Updating " + existingPhysicalSwitchName));
138 private static void setName(final PhysicalSwitch physicalSwitch,
139 final PhysicalSwitchAugmentation physicalSwitchAugmentation,
140 final Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional) {
141 if (physicalSwitchAugmentation.getHwvtepNodeName() != null) {
142 physicalSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
143 } else if (operationalPhysicalSwitchOptional.isPresent()
144 && operationalPhysicalSwitchOptional.orElseThrow().getHwvtepNodeName() != null) {
145 physicalSwitch.setName(operationalPhysicalSwitchOptional.orElseThrow().getHwvtepNodeName().getValue());
149 private static void setDescription(final PhysicalSwitch physicalSwitch,
150 final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
151 if (physicalSwitchAugmentation.getHwvtepNodeDescription() != null) {
152 physicalSwitch.setDescription(physicalSwitchAugmentation.getHwvtepNodeDescription());
156 private static void setManagementIps(final PhysicalSwitch physicalSwitch,
157 final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
158 Map<ManagementIpsKey, ManagementIps> managementIps = physicalSwitchAugmentation.getManagementIps();
159 if (managementIps != null) {
160 Set<String> ipSet = new HashSet<>();
161 for (ManagementIps ip: managementIps.values()) {
162 ipSet.add(ip.getManagementIpsKey().getIpv4Address().getValue());
164 physicalSwitch.setManagementIps(ipSet);
168 private static void setTunnuleIps(final PhysicalSwitch physicalSwitch,
169 final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
170 final Map<TunnelIpsKey, TunnelIps> tunnelIps = physicalSwitchAugmentation.getTunnelIps();
171 if (tunnelIps != null) {
172 Set<String> ipSet = new HashSet<>();
173 for (TunnelIps ip: tunnelIps.values()) {
174 ipSet.add(ip.getTunnelIpsKey().getIpv4Address().getValue());
176 physicalSwitch.setTunnelIps(ipSet);
180 @SuppressWarnings("unchecked")
181 private void setTunnels(final TransactionBuilder transaction, final InstanceIdentifier<Node> iid,
182 final PhysicalSwitch physicalSwitch, final PhysicalSwitchAugmentation physicalSwitchAugmentation,
183 final boolean switchExists) {
184 //TODO: revisit this code for optimizations
185 //TODO: needs more testing
186 for (Tunnels tunnel : physicalSwitchAugmentation.nonnullTunnels().values()) {
187 Optional<Tunnels> opTunnelOpt = getOperationalState().getTunnels(iid, tunnel.key());
188 Tunnel newTunnel = transaction.getTypedRowWrapper(Tunnel.class);
190 UUID localUUID = getLocatorUUID(transaction,
191 (InstanceIdentifier<TerminationPoint>) tunnel.getLocalLocatorRef().getValue());
192 UUID remoteUUID = getLocatorUUID(transaction,
193 (InstanceIdentifier<TerminationPoint>) tunnel.getRemoteLocatorRef().getValue());
194 if (localUUID != null && remoteUUID != null) {
195 // local and remote must exist
196 newTunnel.setLocal(localUUID);
197 newTunnel.setRemote(remoteUUID);
198 setBfdParams(newTunnel, tunnel);
199 setBfdLocalConfigs(newTunnel, tunnel);
200 setBfdRemoteConfigs(newTunnel, tunnel);
201 if (!opTunnelOpt.isPresent()) {
202 String tunnelUuid = "Tunnel_" + HwvtepSouthboundMapper.getRandomUUID();
203 transaction.add(op.insert(newTunnel).withId(tunnelUuid));
204 transaction.add(op.comment("Tunnel: Creating " + tunnelUuid));
206 //TODO: Figure out a way to handle this
207 LOG.warn("Tunnel configuration requires pre-existing physicalSwitch");
209 // TODO: Can we reuse physicalSwitch instead?
210 PhysicalSwitch phySwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
211 phySwitch.setTunnels(Collections.singleton(new UUID(tunnelUuid)));
212 phySwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
213 transaction.add(op.mutate(phySwitch)
214 .addMutation(phySwitch.getTunnels().getSchema(), Mutator.INSERT,
215 phySwitch.getTunnels().getData())
216 .where(phySwitch.getNameColumn().getSchema()
217 .opEqual(phySwitch.getNameColumn().getData()))
219 transaction.add(op.comment("PhysicalSwitch: Mutating " + tunnelUuid));
222 UUID uuid = new UUID(opTunnelOpt.orElseThrow().getTunnelUuid().getValue());
223 Tunnel extraTunnel = transaction.getTypedRowSchema(Tunnel.class);
224 extraTunnel.getUuidColumn().setData(uuid);
225 transaction.add(op.update(newTunnel)
226 .where(extraTunnel.getUuidColumn().getSchema().opEqual(uuid))
228 transaction.add(op.comment("Tunnel: Updating " + uuid));
234 private static void setBfdParams(final Tunnel tunnel, final Tunnels psAugTunnel) {
235 Map<BfdParamsKey, BfdParams> bfdParams = psAugTunnel.getBfdParams();
236 if (bfdParams != null) {
237 Map<String, String> bfdParamMap = new HashMap<>();
238 for (BfdParams bfdParam : bfdParams.values()) {
239 bfdParamMap.put(bfdParam.requireBfdParamKey(), bfdParam.requireBfdParamValue());
241 tunnel.setBfdParams(ImmutableMap.copyOf(bfdParamMap));
245 private static void setBfdLocalConfigs(final Tunnel tunnel, final Tunnels psAugTunnel) {
246 Map<BfdLocalConfigsKey, BfdLocalConfigs> bfdLocalConfigs = psAugTunnel.getBfdLocalConfigs();
247 if (bfdLocalConfigs != null) {
248 Map<String, String> configLocalMap = new HashMap<>();
249 for (BfdLocalConfigs localConfig : bfdLocalConfigs.values()) {
250 configLocalMap.put(localConfig.requireBfdLocalConfigKey(), localConfig.requireBfdLocalConfigValue());
252 tunnel.setBfdConfigLocal(ImmutableMap.copyOf(configLocalMap));
256 private static void setBfdRemoteConfigs(final Tunnel tunnel, final Tunnels psAugTunnel) {
257 Map<BfdRemoteConfigsKey, BfdRemoteConfigs> bfdRemoteConfigs = psAugTunnel.getBfdRemoteConfigs();
258 if (bfdRemoteConfigs != null) {
259 Map<String, String> configRemoteMap = new HashMap<>();
260 for (BfdRemoteConfigs remoteConfig : bfdRemoteConfigs.values()) {
261 configRemoteMap.put(remoteConfig.requireBfdRemoteConfigKey(),
262 remoteConfig.requireBfdRemoteConfigValue());
264 tunnel.setBfdConfigRemote(ImmutableMap.copyOf(configRemoteMap));
268 private UUID getLocatorUUID(final TransactionBuilder transaction, final InstanceIdentifier<TerminationPoint> iid) {
269 UUID locatorUUID = null;
270 Optional<HwvtepPhysicalLocatorAugmentation> opLocOptional =
271 getOperationalState().getPhysicalLocatorAugmentation(iid);
272 if (opLocOptional.isPresent()) {
273 // Get Locator UUID from operational
274 HwvtepPhysicalLocatorAugmentation locatorAug = opLocOptional.orElseThrow();
275 locatorUUID = new UUID(locatorAug.getPhysicalLocatorUuid().getValue());
277 // TODO/FIXME: Not in operational, do we create a new one?
278 LOG.warn("Trying to create tunnel without creating physical locators first");
279 Optional<TerminationPoint> confLocOptional = new MdsalUtils(getOperationalState().getDataBroker())
280 .readOptional(LogicalDatastoreType.CONFIGURATION, iid);
281 if (confLocOptional.isPresent()) {
282 locatorUUID = TransactUtils.createPhysicalLocator(transaction, getOperationalState(), iid);
284 LOG.warn("Unable to find endpoint for tunnel. Endpoint indentifier is {}", iid);
290 private static Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreated(
291 final Collection<DataTreeModification<Node>> changes, final Class<PhysicalSwitchAugmentation> class1) {
292 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
293 if (changes != null && !changes.isEmpty()) {
294 for (DataTreeModification<Node> change : changes) {
295 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
296 final DataObjectModification<Node> mod = change.getRootNode();
297 Node created = TransactUtils.getCreated(mod);
298 if (created != null) {
299 PhysicalSwitchAugmentation physicalSwitch =
300 created.augmentation(PhysicalSwitchAugmentation.class);
301 if (physicalSwitch != null) {
302 result.put(key, physicalSwitch);
310 private static Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractUpdatedSwitches(
311 final Collection<DataTreeModification<Node>> changes, final Class<PhysicalSwitchAugmentation> class1) {
312 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
313 if (changes != null && !changes.isEmpty()) {
314 for (DataTreeModification<Node> change : changes) {
315 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
316 final DataObjectModification<Node> mod = change.getRootNode();
317 Node updated = TransactUtils.getUpdated(mod);
318 if (updated != null) {
319 PhysicalSwitchAugmentation physicalSwitch =
320 updated.augmentation(PhysicalSwitchAugmentation.class);
321 if (physicalSwitch != null) {
322 result.put(key, physicalSwitch);