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 java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.Map.Entry;
23 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
24 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
25 import org.opendaylight.controller.md.sal.common.api.data.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.lib.schema.typed.TyperUtils;
32 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
33 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
34 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
35 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
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.Tunnels;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import com.google.common.base.Optional;
51 import com.google.common.collect.ImmutableMap;
52 import com.google.common.collect.Sets;
54 public class PhysicalSwitchUpdateCommand extends AbstractTransactCommand {
55 private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
57 public PhysicalSwitchUpdateCommand(HwvtepOperationalState state,
58 Collection<DataTreeModification<Node>> changes) {
59 super(state, changes);
63 public void execute(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(TransactionBuilder transaction,
84 InstanceIdentifier<Node> iid, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
85 LOG.debug("Creating a physical switch named: {}", physicalSwitchAugmentation.getHwvtepNodeName());
86 Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional =
87 getOperationalState().getPhysicalSwitchAugmentation(iid);
88 PhysicalSwitch physicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalSwitch.class);
89 setDescription(physicalSwitch, physicalSwitchAugmentation);
90 setManagementIps(physicalSwitch, physicalSwitchAugmentation);
91 setTunnuleIps(physicalSwitch, operationalPhysicalSwitchOptional.get());
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 = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), 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.get();
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.get().getHwvtepNodeName().getValue();
126 // Name is immutable, and so we *can't* update it. So we use extraPhysicalSwitch for the schema stuff
127 PhysicalSwitch extraPhysicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalSwitch.class);
128 extraPhysicalSwitch.setName("");
129 LOG.trace("execute: updating physical switch: {}", physicalSwitch);
130 transaction.add(op.update(physicalSwitch)
131 .where(extraPhysicalSwitch.getNameColumn().getSchema().opEqual(existingPhysicalSwitchName))
133 transaction.add(op.comment("Physical Switch: Updating " + existingPhysicalSwitchName));
137 private void setName(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation,
138 Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional) {
139 if (physicalSwitchAugmentation.getHwvtepNodeName() != null) {
140 physicalSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
141 } else if (operationalPhysicalSwitchOptional.isPresent() && operationalPhysicalSwitchOptional.get().getHwvtepNodeName() != null) {
142 physicalSwitch.setName(operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue());
146 private void setDescription(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
147 if (physicalSwitchAugmentation.getHwvtepNodeDescription() != null) {
148 physicalSwitch.setDescription(physicalSwitchAugmentation.getHwvtepNodeDescription());
152 private void setManagementIps(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
153 Set<String> ipSet = new HashSet<>();
154 if (physicalSwitchAugmentation.getManagementIps() != null) {
155 for (ManagementIps ip: physicalSwitchAugmentation.getManagementIps()) {
156 ipSet.add(ip.getManagementIpsKey().getIpv4Address().getValue());
158 physicalSwitch.setManagementIps(ipSet);
162 private void setTunnuleIps(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
163 Set<String> ipSet = new HashSet<>();
164 if (physicalSwitchAugmentation.getTunnelIps() != null) {
165 for (TunnelIps ip: physicalSwitchAugmentation.getTunnelIps()) {
166 ipSet.add(ip.getTunnelIpsKey().getIpv4Address().getValue());
168 physicalSwitch.setTunnelIps(ipSet);
172 @SuppressWarnings("unchecked")
173 private void setTunnels(TransactionBuilder transaction, InstanceIdentifier<Node> iid,
174 PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation,
175 boolean pSwitchExists) {
176 //TODO: revisit this code for optimizations
177 //TODO: needs more testing
178 if(physicalSwitchAugmentation.getTunnels() != null) {
179 for(Tunnels tunnel: physicalSwitchAugmentation.getTunnels()) {
180 Optional<Tunnels> opTunnelOpt = getOperationalState().getTunnels(iid, tunnel.getKey());
181 Tunnel newTunnel = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Tunnel.class);
183 UUID localUUID = getLocatorUUID(transaction,
184 (InstanceIdentifier<TerminationPoint>) tunnel.getLocalLocatorRef().getValue());
185 UUID remoteUUID = getLocatorUUID(transaction,
186 (InstanceIdentifier<TerminationPoint>) tunnel.getRemoteLocatorRef().getValue());
187 if(localUUID != null && remoteUUID != null) {
189 // local and remote must exist
190 newTunnel.setLocal(localUUID);
191 newTunnel.setRemote(remoteUUID);
192 setBfdParams(newTunnel, tunnel);
193 setBfdLocalConfigs(newTunnel, tunnel);
194 setBfdRemoteConfigs(newTunnel, tunnel);
195 if(!opTunnelOpt.isPresent()) {
196 String tunnelUuid = "Tunnel_" + HwvtepSouthboundMapper.getRandomUUID();
197 transaction.add(op.insert(newTunnel).withId(tunnelUuid));
198 transaction.add(op.comment("Tunnel: Creating " + tunnelUuid));
200 //TODO: Figure out a way to handle this
201 LOG.warn("Tunnel configuration requires pre-existing physicalSwitch");
203 // TODO: Can we reuse physicalSwitch instead?
204 PhysicalSwitch pSwitch =
205 TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
206 PhysicalSwitch.class);
207 pSwitch.setTunnels(Collections.singleton(new UUID(tunnelUuid)));
208 pSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
209 transaction.add(op.mutate(pSwitch)
210 .addMutation(pSwitch.getTunnels().getSchema(), Mutator.INSERT,
211 pSwitch.getTunnels().getData())
212 .where(pSwitch.getNameColumn().getSchema().
213 opEqual(pSwitch.getNameColumn().getData()))
215 transaction.add(op.comment("PhysicalSwitch: Mutating " + tunnelUuid));
217 uuid = new UUID(tunnelUuid);
219 uuid = new UUID (opTunnelOpt.get().getTunnelUuid().getValue());
221 TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Tunnel.class, null);
222 extraTunnel.getUuidColumn().setData(uuid);
223 transaction.add(op.update(newTunnel)
224 .where(extraTunnel.getUuidColumn().getSchema().opEqual(uuid))
226 transaction.add(op.comment("Tunnel: Updating " + uuid));
233 private void setBfdParams(Tunnel tunnel, Tunnels psAugTunnel) {
234 List<BfdParams> bfdParams = psAugTunnel.getBfdParams();
235 if(bfdParams != null) {
236 Map<String, String> bfdParamMap = new HashMap<>();
237 for(BfdParams bfdParam : bfdParams) {
238 bfdParamMap.put(bfdParam.getBfdParamKey(), bfdParam.getBfdParamValue());
241 tunnel.setBfdParams(ImmutableMap.copyOf(bfdParamMap));
242 } catch (NullPointerException e) {
243 LOG.warn("Incomplete BFD Params for tunnel", e);
248 private void setBfdLocalConfigs(Tunnel tunnel, Tunnels psAugTunnel) {
249 List<BfdLocalConfigs> bfdLocalConfigs = psAugTunnel.getBfdLocalConfigs();
250 if(bfdLocalConfigs != null) {
251 Map<String, String> configLocalMap = new HashMap<>();
252 for(BfdLocalConfigs localConfig : bfdLocalConfigs) {
253 configLocalMap.put(localConfig.getBfdLocalConfigKey(), localConfig.getBfdLocalConfigValue());
256 tunnel.setBfdConfigLocal(ImmutableMap.copyOf(configLocalMap));
257 } catch (NullPointerException e) {
258 LOG.warn("Incomplete BFD LocalConfig for tunnel", e);
263 private void setBfdRemoteConfigs(Tunnel tunnel, Tunnels psAugTunnel) {
264 List<BfdRemoteConfigs> bfdRemoteConfigs = psAugTunnel.getBfdRemoteConfigs();
265 if(bfdRemoteConfigs != null) {
266 Map<String, String> configRemoteMap = new HashMap<>();
267 for(BfdRemoteConfigs remoteConfig : bfdRemoteConfigs) {
268 configRemoteMap.put(remoteConfig.getBfdRemoteConfigKey(), remoteConfig.getBfdRemoteConfigValue());
271 tunnel.setBfdConfigRemote(ImmutableMap.copyOf(configRemoteMap));
272 } catch (NullPointerException e) {
273 LOG.warn("Incomplete BFD RemoteConfig for tunnel", e);
278 private UUID getLocatorUUID(TransactionBuilder transaction, InstanceIdentifier<TerminationPoint> iid) {
279 UUID locatorUUID = null;
280 Optional<HwvtepPhysicalLocatorAugmentation> opLocOptional =
281 getOperationalState().getPhysicalLocatorAugmentation(iid);
282 if (opLocOptional.isPresent()) {
283 // Get Locator UUID from operational
284 HwvtepPhysicalLocatorAugmentation locatorAug = opLocOptional.get();
285 locatorUUID = new UUID(locatorAug.getPhysicalLocatorUuid().getValue());
287 // TODO/FIXME: Not in operational, do we create a new one?
288 LOG.warn("Trying to create tunnel without creating physical locators first");
289 Optional<TerminationPoint> confLocOptional = new MdsalUtils(getOperationalState().getDataBroker())
290 .readOptional(LogicalDatastoreType.CONFIGURATION, iid);
291 if (confLocOptional.isPresent()) {
292 HwvtepPhysicalLocatorAugmentation locatorAugmentation =
293 confLocOptional.get().getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
294 locatorUUID = TransactUtils.createPhysicalLocator(transaction, getOperationalState(), iid);
296 LOG.warn("Unable to find endpoint for tunnel. Endpoint indentifier is {}", iid);
302 private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreated(
303 Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
304 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
305 if (changes != null && !changes.isEmpty()) {
306 for (DataTreeModification<Node> change : changes) {
307 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
308 final DataObjectModification<Node> mod = change.getRootNode();
309 Node created = TransactUtils.getCreated(mod);
310 if (created != null) {
311 PhysicalSwitchAugmentation physicalSwitch = created.getAugmentation(PhysicalSwitchAugmentation.class);
312 if (physicalSwitch != null) {
313 result.put(key, physicalSwitch);
321 private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractUpdatedSwitches(
322 Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
323 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
324 if (changes != null && !changes.isEmpty()) {
325 for (DataTreeModification<Node> change : changes) {
326 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
327 final DataObjectModification<Node> mod = change.getRootNode();
328 Node updated = TransactUtils.getUpdated(mod);
329 if (updated != null) {
330 PhysicalSwitchAugmentation physicalSwitch = updated.getAugmentation(PhysicalSwitchAugmentation.class);
331 if (physicalSwitch != null) {
332 result.put(key, physicalSwitch);