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.base.Optional;
15 import com.google.common.collect.ImmutableMap;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
22 import java.util.Map.Entry;
24 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
25 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
28 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
29 import org.opendaylight.ovsdb.lib.notation.Mutator;
30 import org.opendaylight.ovsdb.lib.notation.UUID;
31 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
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.ControllerMdsalUtils;
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 public class PhysicalSwitchUpdateCommand extends AbstractTransactCommand {
51 private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
53 public PhysicalSwitchUpdateCommand(final HwvtepOperationalState state,
54 final Collection<DataTreeModification<Node>> changes) {
55 super(state, changes);
59 public void execute(final TransactionBuilder transaction) {
60 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> created =
61 extractCreated(getChanges(),PhysicalSwitchAugmentation.class);
62 if (!created.isEmpty()) {
63 for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
65 updatePhysicalSwitch(transaction, physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
68 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> updated =
69 extractUpdatedSwitches(getChanges(),PhysicalSwitchAugmentation.class);
70 if (!updated.isEmpty()) {
71 for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
73 updatePhysicalSwitch(transaction, physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
79 private void updatePhysicalSwitch(final TransactionBuilder transaction,
80 final InstanceIdentifier<Node> iid, final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
81 LOG.debug("Creating a physical switch named: {}", physicalSwitchAugmentation.getHwvtepNodeName());
82 Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional =
83 getOperationalState().getPhysicalSwitchAugmentation(iid);
84 PhysicalSwitch physicalSwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
85 setDescription(physicalSwitch, physicalSwitchAugmentation);
86 setManagementIps(physicalSwitch, physicalSwitchAugmentation);
87 setTunnuleIps(physicalSwitch, operationalPhysicalSwitchOptional.get());
89 setTunnels(transaction, iid, physicalSwitch, physicalSwitchAugmentation,
90 operationalPhysicalSwitchOptional.isPresent());
91 } catch (SchemaVersionMismatchException e) {
92 schemaMismatchLog("tunnels", "Physical_Switch", e);
94 if (!operationalPhysicalSwitchOptional.isPresent()) {
95 //create a physical switch
96 setName(physicalSwitch, physicalSwitchAugmentation, operationalPhysicalSwitchOptional);
97 String pswitchUuid = "PhysicalSwitch_" + HwvtepSouthboundMapper.getRandomUUID();
98 transaction.add(op.insert(physicalSwitch).withId(pswitchUuid));
99 transaction.add(op.comment("Physical Switch: Creating "
100 + physicalSwitchAugmentation.getHwvtepNodeName().getValue()));
101 //update global table
102 Global global = transaction.getTypedRowWrapper(Global.class);
103 global.setSwitches(Collections.singleton(new UUID(pswitchUuid)));
105 LOG.trace("execute: create physical switch: {}", physicalSwitch);
106 transaction.add(op.mutate(global)
107 .addMutation(global.getSwitchesColumn().getSchema(), Mutator.INSERT,
108 global.getSwitchesColumn().getData()));
109 transaction.add(op.comment("Global: Mutating "
110 + physicalSwitchAugmentation.getHwvtepNodeName().getValue() + " " + pswitchUuid));
112 PhysicalSwitchAugmentation updatedPhysicalSwitch = operationalPhysicalSwitchOptional.get();
113 String existingPhysicalSwitchName = updatedPhysicalSwitch.getHwvtepNodeName().getValue();
114 /* In case TOR devices don't allow creation of PhysicalSwitch name might be null
115 * as user is only adding configurable parameters to MDSAL like BFD params
117 * TODO Note: Consider handling tunnel udpate/remove in separate command
119 if (existingPhysicalSwitchName == null) {
120 existingPhysicalSwitchName = operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue();
122 // Name is immutable, and so we *can't* update it. So we use extraPhysicalSwitch for the schema stuff
123 PhysicalSwitch extraPhysicalSwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
124 extraPhysicalSwitch.setName("");
125 LOG.trace("execute: updating physical switch: {}", physicalSwitch);
126 transaction.add(op.update(physicalSwitch)
127 .where(extraPhysicalSwitch.getNameColumn().getSchema().opEqual(existingPhysicalSwitchName))
129 transaction.add(op.comment("Physical Switch: Updating " + existingPhysicalSwitchName));
133 private static void setName(final PhysicalSwitch physicalSwitch,
134 final PhysicalSwitchAugmentation physicalSwitchAugmentation,
135 final Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional) {
136 if (physicalSwitchAugmentation.getHwvtepNodeName() != null) {
137 physicalSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
138 } else if (operationalPhysicalSwitchOptional.isPresent()
139 && operationalPhysicalSwitchOptional.get().getHwvtepNodeName() != null) {
140 physicalSwitch.setName(operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue());
144 private static void setDescription(final PhysicalSwitch physicalSwitch,
145 final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
146 if (physicalSwitchAugmentation.getHwvtepNodeDescription() != null) {
147 physicalSwitch.setDescription(physicalSwitchAugmentation.getHwvtepNodeDescription());
151 private static void setManagementIps(final PhysicalSwitch physicalSwitch,
152 final 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 static void setTunnuleIps(final PhysicalSwitch physicalSwitch,
163 final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
164 Set<String> ipSet = new HashSet<>();
165 if (physicalSwitchAugmentation.getTunnelIps() != null) {
166 for (TunnelIps ip: physicalSwitchAugmentation.getTunnelIps()) {
167 ipSet.add(ip.getTunnelIpsKey().getIpv4Address().getValue());
169 physicalSwitch.setTunnelIps(ipSet);
173 @SuppressWarnings("unchecked")
174 private void setTunnels(final TransactionBuilder transaction, final InstanceIdentifier<Node> iid,
175 final PhysicalSwitch physicalSwitch, final PhysicalSwitchAugmentation physicalSwitchAugmentation,
176 final boolean switchExists) {
177 //TODO: revisit this code for optimizations
178 //TODO: needs more testing
179 if (physicalSwitchAugmentation.getTunnels() != null) {
180 for (Tunnels tunnel : physicalSwitchAugmentation.getTunnels()) {
181 Optional<Tunnels> opTunnelOpt = getOperationalState().getTunnels(iid, tunnel.key());
182 Tunnel newTunnel = transaction.getTypedRowWrapper(Tunnel.class);
184 UUID localUUID = getLocatorUUID(transaction,
185 (InstanceIdentifier<TerminationPoint>) tunnel.getLocalLocatorRef().getValue());
186 UUID remoteUUID = getLocatorUUID(transaction,
187 (InstanceIdentifier<TerminationPoint>) tunnel.getRemoteLocatorRef().getValue());
188 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 phySwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
205 phySwitch.setTunnels(Collections.singleton(new UUID(tunnelUuid)));
206 phySwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
207 transaction.add(op.mutate(phySwitch)
208 .addMutation(phySwitch.getTunnels().getSchema(), Mutator.INSERT,
209 phySwitch.getTunnels().getData())
210 .where(phySwitch.getNameColumn().getSchema()
211 .opEqual(phySwitch.getNameColumn().getData()))
213 transaction.add(op.comment("PhysicalSwitch: Mutating " + tunnelUuid));
216 UUID uuid = new UUID(opTunnelOpt.get().getTunnelUuid().getValue());
217 Tunnel extraTunnel = transaction.getTypedRowSchema(Tunnel.class);
218 extraTunnel.getUuidColumn().setData(uuid);
219 transaction.add(op.update(newTunnel)
220 .where(extraTunnel.getUuidColumn().getSchema().opEqual(uuid))
222 transaction.add(op.comment("Tunnel: Updating " + uuid));
229 private static void setBfdParams(final Tunnel tunnel, final Tunnels psAugTunnel) {
230 List<BfdParams> bfdParams = psAugTunnel.getBfdParams();
231 if (bfdParams != null) {
232 Map<String, String> bfdParamMap = new HashMap<>();
233 for (BfdParams bfdParam : bfdParams) {
234 bfdParamMap.put(bfdParam.getBfdParamKey(), bfdParam.getBfdParamValue());
237 tunnel.setBfdParams(ImmutableMap.copyOf(bfdParamMap));
238 } catch (NullPointerException e) {
239 LOG.warn("Incomplete BFD Params for tunnel", e);
244 private static void setBfdLocalConfigs(final Tunnel tunnel, final Tunnels psAugTunnel) {
245 List<BfdLocalConfigs> bfdLocalConfigs = psAugTunnel.getBfdLocalConfigs();
246 if (bfdLocalConfigs != null) {
247 Map<String, String> configLocalMap = new HashMap<>();
248 for (BfdLocalConfigs localConfig : bfdLocalConfigs) {
249 configLocalMap.put(localConfig.getBfdLocalConfigKey(), localConfig.getBfdLocalConfigValue());
252 tunnel.setBfdConfigLocal(ImmutableMap.copyOf(configLocalMap));
253 } catch (NullPointerException e) {
254 LOG.warn("Incomplete BFD LocalConfig for tunnel", e);
259 private static void setBfdRemoteConfigs(final Tunnel tunnel, final Tunnels psAugTunnel) {
260 List<BfdRemoteConfigs> bfdRemoteConfigs = psAugTunnel.getBfdRemoteConfigs();
261 if (bfdRemoteConfigs != null) {
262 Map<String, String> configRemoteMap = new HashMap<>();
263 for (BfdRemoteConfigs remoteConfig : bfdRemoteConfigs) {
264 configRemoteMap.put(remoteConfig.getBfdRemoteConfigKey(), remoteConfig.getBfdRemoteConfigValue());
267 tunnel.setBfdConfigRemote(ImmutableMap.copyOf(configRemoteMap));
268 } catch (NullPointerException e) {
269 LOG.warn("Incomplete BFD RemoteConfig for tunnel", e);
274 private UUID getLocatorUUID(final TransactionBuilder transaction, final InstanceIdentifier<TerminationPoint> iid) {
275 UUID locatorUUID = null;
276 Optional<HwvtepPhysicalLocatorAugmentation> opLocOptional =
277 getOperationalState().getPhysicalLocatorAugmentation(iid);
278 if (opLocOptional.isPresent()) {
279 // Get Locator UUID from operational
280 HwvtepPhysicalLocatorAugmentation locatorAug = opLocOptional.get();
281 locatorUUID = new UUID(locatorAug.getPhysicalLocatorUuid().getValue());
283 // TODO/FIXME: Not in operational, do we create a new one?
284 LOG.warn("Trying to create tunnel without creating physical locators first");
285 Optional<TerminationPoint> confLocOptional = new ControllerMdsalUtils(getOperationalState().getDataBroker())
286 .readOptional(LogicalDatastoreType.CONFIGURATION, iid);
287 if (confLocOptional.isPresent()) {
288 locatorUUID = TransactUtils.createPhysicalLocator(transaction, getOperationalState(), iid);
290 LOG.warn("Unable to find endpoint for tunnel. Endpoint indentifier is {}", iid);
296 private static Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreated(
297 final Collection<DataTreeModification<Node>> changes, final Class<PhysicalSwitchAugmentation> class1) {
298 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
299 if (changes != null && !changes.isEmpty()) {
300 for (DataTreeModification<Node> change : changes) {
301 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
302 final DataObjectModification<Node> mod = change.getRootNode();
303 Node created = TransactUtils.getCreated(mod);
304 if (created != null) {
305 PhysicalSwitchAugmentation physicalSwitch =
306 created.augmentation(PhysicalSwitchAugmentation.class);
307 if (physicalSwitch != null) {
308 result.put(key, physicalSwitch);
316 private static Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractUpdatedSwitches(
317 final Collection<DataTreeModification<Node>> changes, final Class<PhysicalSwitchAugmentation> class1) {
318 Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
319 if (changes != null && !changes.isEmpty()) {
320 for (DataTreeModification<Node> change : changes) {
321 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
322 final DataObjectModification<Node> mod = change.getRootNode();
323 Node updated = TransactUtils.getUpdated(mod);
324 if (updated != null) {
325 PhysicalSwitchAugmentation physicalSwitch =
326 updated.augmentation(PhysicalSwitchAugmentation.class);
327 if (physicalSwitch != null) {
328 result.put(key, physicalSwitch);