f0aebff57d4f73e3bdd38f960511ffecb8a0a7bc
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / PhysicalSwitchUpdateCommand.java
1 /*
2  * Copyright © 2015, 2017 China Telecom Beijing Research Institute and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
10
11 import static org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil.schemaMismatchLog;
12 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
13
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;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Optional;
22 import java.util.Set;
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;
53
54 public final class PhysicalSwitchUpdateCommand extends AbstractTransactCommand {
55     private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
56
57     public PhysicalSwitchUpdateCommand(final HwvtepOperationalState state,
58             final Collection<DataTreeModification<Node>> changes) {
59         super(state, changes);
60     }
61
62     @Override
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:
68                 created.entrySet()) {
69                 updatePhysicalSwitch(transaction,  physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
70             }
71         }
72         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> updated =
73                 extractUpdatedSwitches(getChanges(),PhysicalSwitchAugmentation.class);
74         if (!updated.isEmpty()) {
75             for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
76                 updated.entrySet()) {
77                 updatePhysicalSwitch(transaction,  physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
78             }
79         }
80     }
81
82
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.get());
92         try {
93             setTunnels(transaction, iid, physicalSwitch, physicalSwitchAugmentation,
94                             operationalPhysicalSwitchOptional.isPresent());
95         } catch (SchemaVersionMismatchException e) {
96             schemaMismatchLog("tunnels", "Physical_Switch", e);
97         }
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)));
108
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));
115         } else {
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
120              *
121              * TODO Note: Consider handling tunnel udpate/remove in separate command
122              */
123             if (existingPhysicalSwitchName == null) {
124                 existingPhysicalSwitchName = operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue();
125             }
126             // Name is immutable, and so we *can't* update it.  So we use extraPhysicalSwitch for the schema stuff
127             PhysicalSwitch extraPhysicalSwitch = transaction.getTypedRowWrapper(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))
132                     .build());
133             transaction.add(op.comment("Physical Switch: Updating " + existingPhysicalSwitchName));
134         }
135     }
136
137     private static void setName(final PhysicalSwitch physicalSwitch,
138             final PhysicalSwitchAugmentation physicalSwitchAugmentation,
139             final Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional) {
140         if (physicalSwitchAugmentation.getHwvtepNodeName() != null) {
141             physicalSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
142         } else if (operationalPhysicalSwitchOptional.isPresent()
143                 && operationalPhysicalSwitchOptional.get().getHwvtepNodeName() != null) {
144             physicalSwitch.setName(operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue());
145         }
146     }
147
148     private static void setDescription(final PhysicalSwitch physicalSwitch,
149             final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
150         if (physicalSwitchAugmentation.getHwvtepNodeDescription() != null) {
151             physicalSwitch.setDescription(physicalSwitchAugmentation.getHwvtepNodeDescription());
152         }
153     }
154
155     private static void setManagementIps(final PhysicalSwitch physicalSwitch,
156             final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
157         Map<ManagementIpsKey, ManagementIps> managementIps = physicalSwitchAugmentation.getManagementIps();
158         if (managementIps != null) {
159             Set<String> ipSet = new HashSet<>();
160             for (ManagementIps ip: managementIps.values()) {
161                 ipSet.add(ip.getManagementIpsKey().getIpv4Address().getValue());
162             }
163             physicalSwitch.setManagementIps(ipSet);
164         }
165     }
166
167     private static void setTunnuleIps(final PhysicalSwitch physicalSwitch,
168             final PhysicalSwitchAugmentation physicalSwitchAugmentation) {
169         final Map<TunnelIpsKey, TunnelIps> tunnelIps = physicalSwitchAugmentation.getTunnelIps();
170         if (tunnelIps != null) {
171             Set<String> ipSet = new HashSet<>();
172             for (TunnelIps ip: tunnelIps.values()) {
173                 ipSet.add(ip.getTunnelIpsKey().getIpv4Address().getValue());
174             }
175             physicalSwitch.setTunnelIps(ipSet);
176         }
177     }
178
179     @SuppressWarnings("unchecked")
180     private void setTunnels(final TransactionBuilder transaction, final InstanceIdentifier<Node> iid,
181             final PhysicalSwitch physicalSwitch, final PhysicalSwitchAugmentation physicalSwitchAugmentation,
182             final boolean switchExists) {
183         //TODO: revisit this code for optimizations
184         //TODO: needs more testing
185         for (Tunnels tunnel : physicalSwitchAugmentation.nonnullTunnels().values()) {
186             Optional<Tunnels> opTunnelOpt = getOperationalState().getTunnels(iid, tunnel.key());
187             Tunnel newTunnel = transaction.getTypedRowWrapper(Tunnel.class);
188
189             UUID localUUID = getLocatorUUID(transaction,
190                 (InstanceIdentifier<TerminationPoint>) tunnel.getLocalLocatorRef().getValue());
191             UUID remoteUUID = getLocatorUUID(transaction,
192                 (InstanceIdentifier<TerminationPoint>) tunnel.getRemoteLocatorRef().getValue());
193             if (localUUID != null && remoteUUID != null) {
194                 // local and remote must exist
195                 newTunnel.setLocal(localUUID);
196                 newTunnel.setRemote(remoteUUID);
197                 setBfdParams(newTunnel, tunnel);
198                 setBfdLocalConfigs(newTunnel, tunnel);
199                 setBfdRemoteConfigs(newTunnel, tunnel);
200                 if (!opTunnelOpt.isPresent()) {
201                     String tunnelUuid = "Tunnel_" + HwvtepSouthboundMapper.getRandomUUID();
202                     transaction.add(op.insert(newTunnel).withId(tunnelUuid));
203                     transaction.add(op.comment("Tunnel: Creating " + tunnelUuid));
204                     if (!switchExists) {
205                         //TODO: Figure out a way to handle this
206                         LOG.warn("Tunnel configuration requires pre-existing physicalSwitch");
207                     } else {
208                         // TODO: Can we reuse physicalSwitch instead?
209                         PhysicalSwitch phySwitch = transaction.getTypedRowWrapper(PhysicalSwitch.class);
210                         phySwitch.setTunnels(Collections.singleton(new UUID(tunnelUuid)));
211                         phySwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
212                         transaction.add(op.mutate(phySwitch)
213                             .addMutation(phySwitch.getTunnels().getSchema(), Mutator.INSERT,
214                                 phySwitch.getTunnels().getData())
215                             .where(phySwitch.getNameColumn().getSchema()
216                                 .opEqual(phySwitch.getNameColumn().getData()))
217                             .build());
218                         transaction.add(op.comment("PhysicalSwitch: Mutating " + tunnelUuid));
219                     }
220                 } else {
221                     UUID uuid = new UUID(opTunnelOpt.get().getTunnelUuid().getValue());
222                     Tunnel extraTunnel = transaction.getTypedRowSchema(Tunnel.class);
223                     extraTunnel.getUuidColumn().setData(uuid);
224                     transaction.add(op.update(newTunnel)
225                         .where(extraTunnel.getUuidColumn().getSchema().opEqual(uuid))
226                         .build());
227                     transaction.add(op.comment("Tunnel: Updating " + uuid));
228                 }
229             }
230         }
231     }
232
233     private static void setBfdParams(final Tunnel tunnel, final Tunnels psAugTunnel) {
234         Map<BfdParamsKey, BfdParams> bfdParams = psAugTunnel.getBfdParams();
235         if (bfdParams != null) {
236             Map<String, String> bfdParamMap = new HashMap<>();
237             for (BfdParams bfdParam : bfdParams.values()) {
238                 bfdParamMap.put(bfdParam.requireBfdParamKey(), bfdParam.requireBfdParamValue());
239             }
240             tunnel.setBfdParams(ImmutableMap.copyOf(bfdParamMap));
241         }
242     }
243
244     private static void setBfdLocalConfigs(final Tunnel tunnel, final Tunnels psAugTunnel) {
245         Map<BfdLocalConfigsKey, BfdLocalConfigs> bfdLocalConfigs = psAugTunnel.getBfdLocalConfigs();
246         if (bfdLocalConfigs != null) {
247             Map<String, String> configLocalMap = new HashMap<>();
248             for (BfdLocalConfigs localConfig : bfdLocalConfigs.values()) {
249                 configLocalMap.put(localConfig.requireBfdLocalConfigKey(), localConfig.requireBfdLocalConfigValue());
250             }
251             tunnel.setBfdConfigLocal(ImmutableMap.copyOf(configLocalMap));
252         }
253     }
254
255     private static void setBfdRemoteConfigs(final Tunnel tunnel, final Tunnels psAugTunnel) {
256         Map<BfdRemoteConfigsKey, BfdRemoteConfigs> bfdRemoteConfigs = psAugTunnel.getBfdRemoteConfigs();
257         if (bfdRemoteConfigs != null) {
258             Map<String, String> configRemoteMap = new HashMap<>();
259             for (BfdRemoteConfigs remoteConfig : bfdRemoteConfigs.values()) {
260                 configRemoteMap.put(remoteConfig.requireBfdRemoteConfigKey(),
261                     remoteConfig.requireBfdRemoteConfigValue());
262             }
263             tunnel.setBfdConfigRemote(ImmutableMap.copyOf(configRemoteMap));
264         }
265     }
266
267     private UUID getLocatorUUID(final TransactionBuilder transaction, final InstanceIdentifier<TerminationPoint> iid) {
268         UUID locatorUUID = null;
269         Optional<HwvtepPhysicalLocatorAugmentation> opLocOptional =
270                         getOperationalState().getPhysicalLocatorAugmentation(iid);
271         if (opLocOptional.isPresent()) {
272             // Get Locator UUID from operational
273             HwvtepPhysicalLocatorAugmentation locatorAug = opLocOptional.get();
274             locatorUUID = new UUID(locatorAug.getPhysicalLocatorUuid().getValue());
275         } else {
276             // TODO/FIXME: Not in operational, do we create a new one?
277             LOG.warn("Trying to create tunnel without creating physical locators first");
278             Optional<TerminationPoint> confLocOptional = new MdsalUtils(getOperationalState().getDataBroker())
279                     .readOptional(LogicalDatastoreType.CONFIGURATION, iid);
280             if (confLocOptional.isPresent()) {
281                 locatorUUID = TransactUtils.createPhysicalLocator(transaction, getOperationalState(), iid);
282             } else {
283                 LOG.warn("Unable to find endpoint for tunnel. Endpoint indentifier is {}", iid);
284             }
285         }
286         return locatorUUID;
287     }
288
289     private static Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreated(
290             final Collection<DataTreeModification<Node>> changes, final Class<PhysicalSwitchAugmentation> class1) {
291         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
292         if (changes != null && !changes.isEmpty()) {
293             for (DataTreeModification<Node> change : changes) {
294                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
295                 final DataObjectModification<Node> mod = change.getRootNode();
296                 Node created = TransactUtils.getCreated(mod);
297                 if (created != null) {
298                     PhysicalSwitchAugmentation physicalSwitch =
299                             created.augmentation(PhysicalSwitchAugmentation.class);
300                     if (physicalSwitch != null) {
301                         result.put(key, physicalSwitch);
302                     }
303                 }
304             }
305         }
306         return result;
307     }
308
309     private static Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractUpdatedSwitches(
310             final Collection<DataTreeModification<Node>> changes, final Class<PhysicalSwitchAugmentation> class1) {
311         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result = new HashMap<>();
312         if (changes != null && !changes.isEmpty()) {
313             for (DataTreeModification<Node> change : changes) {
314                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
315                 final DataObjectModification<Node> mod = change.getRootNode();
316                 Node updated = TransactUtils.getUpdated(mod);
317                 if (updated != null) {
318                     PhysicalSwitchAugmentation physicalSwitch =
319                             updated.augmentation(PhysicalSwitchAugmentation.class);
320                     if (physicalSwitch != null) {
321                         result.put(key, physicalSwitch);
322                     }
323                 }
324             }
325         }
326         return result;
327     }
328
329 }