Merge "BUG 5479: HWVtep Southbound doesn't retry connection"
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transact / PhysicalSwitchUpdateCommand.java
1 /*
2  * Copyright (c) 2015, 2016 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.lib.operations.Operations.op;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Set;
20
21 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
24 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
25 import org.opendaylight.ovsdb.lib.notation.Mutator;
26 import org.opendaylight.ovsdb.lib.notation.UUID;
27 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
28 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
29 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
30 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
31 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.common.base.Optional;
47 import com.google.common.collect.ImmutableMap;
48 import com.google.common.collect.Sets;
49
50 public class PhysicalSwitchUpdateCommand extends AbstractTransactCommand {
51     private static final Logger LOG = LoggerFactory.getLogger(PhysicalSwitchUpdateCommand.class);
52
53     public PhysicalSwitchUpdateCommand(HwvtepOperationalState state,
54             Collection<DataTreeModification<Node>> changes) {
55         super(state, changes);
56     }
57
58     @Override
59     public void execute(TransactionBuilder transaction) {
60         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> created =
61                 extractCreated(getChanges(),PhysicalSwitchAugmentation.class);
62         if (!created.isEmpty()) {
63             for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
64                 created.entrySet()) {
65                 updatePhysicalSwitch(transaction,  physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
66             }
67         }
68         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> updated =
69                 extractUpdated(getChanges(),PhysicalSwitchAugmentation.class);
70         if (!updated.isEmpty()) {
71             for (Entry<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> physicalSwitchEntry:
72                 updated.entrySet()) {
73                 updatePhysicalSwitch(transaction,  physicalSwitchEntry.getKey(), physicalSwitchEntry.getValue());
74             }
75         }
76     }
77
78
79     private void updatePhysicalSwitch(TransactionBuilder transaction,
80             InstanceIdentifier<Node> iid, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
81         LOG.debug("Creating a physical switch named: {}", physicalSwitchAugmentation.getHwvtepNodeName());
82         Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional =
83                 getOperationalState().getPhysicalSwitchAugmentation(iid);
84         PhysicalSwitch physicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), PhysicalSwitch.class);
85         setDescription(physicalSwitch, physicalSwitchAugmentation);
86         setManagementIps(physicalSwitch, physicalSwitchAugmentation);
87         setTunnuleIps(physicalSwitch, physicalSwitchAugmentation);
88         try {
89             setTunnels(transaction, iid, physicalSwitch, physicalSwitchAugmentation,
90                             operationalPhysicalSwitchOptional.isPresent());
91         } catch (SchemaVersionMismatchException e) {
92             LOG.debug("tunnels table unsupported for this version of HWVTEP schema", e);
93         }
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 = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Global.class);
103             global.setSwitches(Sets.newHashSet(new UUID(pswitchUuid)));
104
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));
111         } else {
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
116              * 
117              * TODO Note: Consider handling tunnel udpate/remove in separate command
118              */
119             if(existingPhysicalSwitchName == null) {
120                 existingPhysicalSwitchName = operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue();
121             }
122             // Name is immutable, and so we *can't* update it.  So we use extraPhysicalSwitch for the schema stuff
123             PhysicalSwitch extraPhysicalSwitch = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), 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))
128                     .build());
129             transaction.add(op.comment("Physical Switch: Updating " + existingPhysicalSwitchName));
130         }
131     }
132
133     private void setName(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation,
134             Optional<PhysicalSwitchAugmentation> operationalPhysicalSwitchOptional) {
135         if (physicalSwitchAugmentation.getHwvtepNodeName() != null) {
136             physicalSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
137         } else if (operationalPhysicalSwitchOptional.isPresent() && operationalPhysicalSwitchOptional.get().getHwvtepNodeName() != null) {
138             physicalSwitch.setName(operationalPhysicalSwitchOptional.get().getHwvtepNodeName().getValue());
139         }
140     }
141
142     private void setDescription(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
143         if (physicalSwitchAugmentation.getHwvtepNodeDescription() != null) {
144             physicalSwitch.setDescription(physicalSwitchAugmentation.getHwvtepNodeDescription());
145         }
146     }
147
148     private void setManagementIps(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
149         Set<String> ipSet = new HashSet<String>();
150         if (physicalSwitchAugmentation.getManagementIps() != null) {
151             for (ManagementIps ip: physicalSwitchAugmentation.getManagementIps()) {
152                 ipSet.add(ip.getManagementIpsKey().getIpv4Address().getValue());
153             }
154             physicalSwitch.setManagementIps(ipSet);
155         }
156     }
157
158     private void setTunnuleIps(PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation) {
159         Set<String> ipSet = new HashSet<String>();
160         if (physicalSwitchAugmentation.getTunnelIps() != null) {
161             for (TunnelIps ip: physicalSwitchAugmentation.getTunnelIps()) {
162                 ipSet.add(ip.getTunnelIpsKey().getIpv4Address().getValue());
163             }
164             physicalSwitch.setTunnelIps(ipSet);
165         }
166     }
167
168     @SuppressWarnings("unchecked")
169     private void setTunnels(TransactionBuilder transaction, InstanceIdentifier<Node> iid,
170                     PhysicalSwitch physicalSwitch, PhysicalSwitchAugmentation physicalSwitchAugmentation,
171                     boolean pSwitchExists) {
172         //TODO: revisit this code for optimizations
173         //TODO: needs more testing
174         if(physicalSwitchAugmentation.getTunnels() != null) {
175             for(Tunnels tunnel: physicalSwitchAugmentation.getTunnels()) {
176                 Optional<Tunnels> opTunnelOpt = getOperationalState().getTunnels(iid, tunnel.getKey());
177                 Tunnel newTunnel = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Tunnel.class);
178
179                 UUID localUUID = getLocatorUUID(transaction,
180                                 (InstanceIdentifier<TerminationPoint>) tunnel.getLocalLocatorRef().getValue());
181                 UUID remoteUUID = getLocatorUUID(transaction,
182                                 (InstanceIdentifier<TerminationPoint>) tunnel.getRemoteLocatorRef().getValue());
183                 if(localUUID != null && remoteUUID != null) {
184                     UUID uuid;
185                     // local and remote must exist
186                     newTunnel.setLocal(localUUID);
187                     newTunnel.setRemote(remoteUUID);
188                     setBfdParams(newTunnel, tunnel);
189                     setBfdLocalConfigs(newTunnel, tunnel);
190                     setBfdRemoteConfigs(newTunnel, tunnel);
191                     if(!opTunnelOpt.isPresent()) {
192                         String tunnelUuid = "Tunnel_" + HwvtepSouthboundMapper.getRandomUUID();
193                         transaction.add(op.insert(newTunnel).withId(tunnelUuid));
194                         transaction.add(op.comment("Tunnel: Creating " + tunnelUuid));
195                         if(!pSwitchExists) {
196                             //TODO: Figure out a way to handle this
197                             LOG.warn("Tunnel configuration requires pre-existing physicalSwitch");
198                         } else {
199                             // TODO: Can we reuse physicalSwitch instead?
200                             PhysicalSwitch pSwitch =
201                                             TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(),
202                                                             PhysicalSwitch.class);
203                             pSwitch.setTunnels(Sets.newHashSet(new UUID(tunnelUuid)));
204                             pSwitch.setName(physicalSwitchAugmentation.getHwvtepNodeName().getValue());
205                             transaction.add(op.mutate(pSwitch)
206                                             .addMutation(pSwitch.getTunnels().getSchema(), Mutator.INSERT,
207                                                     pSwitch.getTunnels().getData())
208                                             .where(pSwitch.getNameColumn().getSchema().
209                                                             opEqual(pSwitch.getNameColumn().getData()))
210                                             .build());
211                             transaction.add(op.comment("PhysicalSwitch: Mutating " + tunnelUuid));
212                         }
213                         uuid = new UUID(tunnelUuid);
214                     } else {
215                         uuid = new UUID (opTunnelOpt.get().getTunnelUuid().getValue());
216                         Tunnel extraTunnel =
217                                 TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Tunnel.class, null);
218                         extraTunnel.getUuidColumn().setData(uuid);
219                         transaction.add(op.update(newTunnel)
220                                         .where(extraTunnel.getUuidColumn().getSchema().opEqual(uuid))
221                                         .build());
222                         transaction.add(op.comment("Tunnel: Updating " + uuid));
223                     }
224                 }
225             }
226         }
227     }
228
229     private void setBfdParams(Tunnel tunnel, 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());
235             }
236             try {
237                 tunnel.setBfdParams(ImmutableMap.copyOf(bfdParamMap));
238             } catch (NullPointerException e) {
239                 LOG.warn("Incomplete BFD Params for tunnel", e);
240             }
241         }
242     }
243
244     private void setBfdLocalConfigs(Tunnel tunnel, 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());
250             }
251             try {
252                 tunnel.setBfdConfigLocal(ImmutableMap.copyOf(configLocalMap));
253             } catch (NullPointerException e) {
254                 LOG.warn("Incomplete BFD LocalConfig for tunnel", e);
255             }
256         }
257     }
258
259     private void setBfdRemoteConfigs(Tunnel tunnel, 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());
265             }
266             try {
267                 tunnel.setBfdConfigRemote(ImmutableMap.copyOf(configRemoteMap));
268             } catch (NullPointerException e) {
269                 LOG.warn("Incomplete BFD RemoteConfig for tunnel", e);
270             }
271         }
272     }
273
274     private UUID getLocatorUUID(TransactionBuilder transaction, 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());
282         } else {
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 =
286                             TransactUtils.readNodeFromConfig(getOperationalState().getReadWriteTransaction(), iid);
287             if (confLocOptional.isPresent()) {
288                 HwvtepPhysicalLocatorAugmentation locatorAugmentation =
289                                 confLocOptional.get().getAugmentation(HwvtepPhysicalLocatorAugmentation.class);
290                 locatorUUID = TransactUtils.createPhysicalLocator(transaction, locatorAugmentation);
291             } else {
292                 LOG.warn("Unable to find endpoint for tunnel. Endpoint indentifier is {}", iid);
293             }
294         }
295         return locatorUUID;
296     }
297
298     private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractCreated(
299             Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
300         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result
301             = new HashMap<InstanceIdentifier<Node>, PhysicalSwitchAugmentation>();
302         if (changes != null && !changes.isEmpty()) {
303             for (DataTreeModification<Node> change : changes) {
304                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
305                 final DataObjectModification<Node> mod = change.getRootNode();
306                 Node created = TransactUtils.getCreated(mod);
307                 if (created != null) {
308                     PhysicalSwitchAugmentation physicalSwitch = created.getAugmentation(PhysicalSwitchAugmentation.class);
309                     if (physicalSwitch != null) {
310                         result.put(key, physicalSwitch);
311                     }
312                 }
313             }
314         }
315         return result;
316     }
317
318     private Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> extractUpdated(
319             Collection<DataTreeModification<Node>> changes, Class<PhysicalSwitchAugmentation> class1) {
320         Map<InstanceIdentifier<Node>, PhysicalSwitchAugmentation> result
321             = new HashMap<InstanceIdentifier<Node>, PhysicalSwitchAugmentation>();
322         if (changes != null && !changes.isEmpty()) {
323             for (DataTreeModification<Node> change : changes) {
324                 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
325                 final DataObjectModification<Node> mod = change.getRootNode();
326                 Node updated = TransactUtils.getUpdated(mod);
327                 if (updated != null) {
328                     PhysicalSwitchAugmentation physicalSwitch = updated.getAugmentation(PhysicalSwitchAugmentation.class);
329                     if (physicalSwitch != null) {
330                         result.put(key, physicalSwitch);
331                     }
332                 }
333             }
334         }
335         return result;
336     }
337
338 }