Bump upstreams for 2022.09 Chlorine
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / transactions / md / HwvtepPhysicalSwitchUpdateCommand.java
1 /*
2  * Copyright (c) 2015, 2017 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.Sets;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.Set;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
24 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
25 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
26 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactUtils;
27 import org.opendaylight.ovsdb.lib.message.TableUpdates;
28 import org.opendaylight.ovsdb.lib.notation.UUID;
29 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
30 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
31 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
32 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
33 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchRef;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.Switches;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.SwitchesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIpsBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.SwitchFaultStatus;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.SwitchFaultStatusBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.SwitchFaultStatusKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIpsKey;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
55 import org.opendaylight.yangtools.yang.binding.DataObject;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 public final class HwvtepPhysicalSwitchUpdateCommand extends AbstractTransactionCommand {
62     private static final Logger LOG = LoggerFactory.getLogger(HwvtepPhysicalSwitchUpdateCommand.class);
63
64     private final Map<UUID, PhysicalSwitch> updatedPSRows;
65     private Map<UUID, Tunnel> updatedTunnelRows;
66     private final Map<UUID, PhysicalSwitch> oldPSRows;
67
68     public HwvtepPhysicalSwitchUpdateCommand(HwvtepConnectionInstance key, TableUpdates updates,
69             DatabaseSchema dbSchema) {
70         super(key, updates, dbSchema);
71         updatedPSRows = TyperUtils.extractRowsUpdated(PhysicalSwitch.class, getUpdates(), getDbSchema());
72         oldPSRows = TyperUtils.extractRowsOld(PhysicalSwitch.class, getUpdates(), getDbSchema());
73         try {
74             updatedTunnelRows = TyperUtils.extractRowsUpdated(Tunnel.class, getUpdates(), getDbSchema());
75         } catch (IllegalArgumentException e) {
76             LOG.debug("Tunnel Table not supported on this HWVTEP device", e);
77         }
78     }
79
80     @Override
81     public void execute(ReadWriteTransaction transaction) {
82         for (Map.Entry<UUID, PhysicalSwitch> entry : updatedPSRows.entrySet()) {
83             updatePhysicalSwitch(transaction, entry.getKey(), entry.getValue());
84         }
85     }
86
87     private void updatePhysicalSwitch(ReadWriteTransaction transaction, UUID uuid, PhysicalSwitch phySwitch) {
88         final InstanceIdentifier<Node> connectionIId = getOvsdbConnectionInstance().getInstanceIdentifier();
89         //TODO remove this read
90         Optional<Node> connection = HwvtepSouthboundUtil.readNode(transaction, connectionIId);
91         if (connection.isPresent()) {
92             LOG.debug("Connection {} is present", connection);
93             // Update the connection node to let it know it manages this
94             // Physical Switch
95             Node connectionNode = buildConnectionNode(phySwitch);
96             transaction.merge(LogicalDatastoreType.OPERATIONAL, connectionIId, connectionNode);
97
98             // Update the Physical Switch with whatever data we are getting
99             InstanceIdentifier<Node> psIid = getInstanceIdentifier(phySwitch);
100             Node psNode = buildPhysicalSwitchNode(connection.get(), phySwitch);
101             transaction.merge(LogicalDatastoreType.OPERATIONAL, psIid, psNode);
102             addToDeviceUpdate(TransactionType.ADD, phySwitch);
103             LOG.info("DEVICE - {} {}", TransactionType.ADD, phySwitch);
104
105             PhysicalSwitch oldPSwitch = oldPSRows.get(uuid);
106             updateTunnelIps(phySwitch, oldPSwitch, transaction);
107
108             getOvsdbConnectionInstance().getDeviceInfo().putPhysicalSwitch(phySwitch.getUuid(), phySwitch);
109             getDeviceInfo().updateDeviceOperData(Node.class, psIid, phySwitch.getUuid(), phySwitch);
110             // TODO: Delete entries that are no longer needed
111             // TODO: Deletion of tunnels
112             // TODO: Deletion of Tunnel BFD config and params
113             //Deleting old switch fault status entries
114             deleteEntries(transaction, getSwitchFaultStatusToRemove(psIid,phySwitch));
115         }
116     }
117
118     private static InstanceIdentifier<TunnelIps> getTunnelIpIid(final String tunnelIp,
119             final InstanceIdentifier<Node> psIid) {
120         IpAddress ip = TransactUtils.parseIpAddress(tunnelIp);
121         TunnelIps tunnelIps = new TunnelIpsBuilder().withKey(new TunnelIpsKey(ip)).setTunnelIpsKey(ip).build();
122         return psIid.augmentation(PhysicalSwitchAugmentation.class).child(TunnelIps.class, tunnelIps.key());
123     }
124
125     private void updateTunnelIps(@NonNull final PhysicalSwitch newPSwitch, @Nullable final PhysicalSwitch oldPSwitch,
126                                  final ReadWriteTransaction transaction) {
127         Set<String> oldTunnelIps = oldPSwitch != null && oldPSwitch.getTunnelIpsColumn() != null ? oldPSwitch
128                 .getTunnelIpsColumn().getData() : Collections.emptySet();
129         Set<String> newTunelIps = newPSwitch.getTunnelIpsColumn() != null ? newPSwitch
130                 .getTunnelIpsColumn().getData() : Collections.emptySet();
131
132         Set<String> addedTunnelIps = Sets.difference(newTunelIps, oldTunnelIps);
133         Set<String> removedTunnelIps = Sets.difference(oldTunnelIps, newTunelIps);
134
135         InstanceIdentifier<Node> psIid = getInstanceIdentifier(newPSwitch);
136         for (String tunnelIp : removedTunnelIps) {
137             InstanceIdentifier<TunnelIps> tunnelIpsInstanceIdentifier = getTunnelIpIid(tunnelIp, psIid);
138             transaction.delete(LogicalDatastoreType.OPERATIONAL, tunnelIpsInstanceIdentifier);
139         }
140         for (String tunnelIp : addedTunnelIps) {
141             IpAddress ip = TransactUtils.parseIpAddress(tunnelIp);
142             InstanceIdentifier<TunnelIps> tunnelIpsInstanceIdentifier = getTunnelIpIid(tunnelIp, psIid);
143             TunnelIps tunnelIps = new TunnelIpsBuilder().withKey(new TunnelIpsKey(ip)).setTunnelIpsKey(ip).build();
144             transaction.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, tunnelIpsInstanceIdentifier,
145                 tunnelIps);
146         }
147     }
148
149     private Node buildPhysicalSwitchNode(Node node, PhysicalSwitch phySwitch) {
150         NodeBuilder psNodeBuilder = new NodeBuilder();
151         NodeId psNodeId = getNodeId(phySwitch);
152         psNodeBuilder.setNodeId(psNodeId);
153         PhysicalSwitchAugmentationBuilder psAugmentationBuilder = new PhysicalSwitchAugmentationBuilder();
154         psAugmentationBuilder.setPhysicalSwitchUuid(new Uuid(phySwitch.getUuid().toString()));
155         setManagedBy(psAugmentationBuilder);
156         setPhysicalSwitchId(psAugmentationBuilder, phySwitch);
157         setManagementIps(psAugmentationBuilder, phySwitch);
158         setTunnels(psAugmentationBuilder, phySwitch);
159         setSwitchFaultStatus(psAugmentationBuilder, phySwitch);
160
161         psNodeBuilder.addAugmentation(psAugmentationBuilder.build());
162
163         LOG.trace("Built with the intent to store PhysicalSwitch data {}", psAugmentationBuilder.build());
164         return psNodeBuilder.build();
165     }
166
167     private void setTunnels(PhysicalSwitchAugmentationBuilder psAugmentationBuilder, PhysicalSwitch phySwitch) {
168         if (updatedTunnelRows != null && phySwitch.getTunnels() != null && phySwitch.getTunnels().getData() != null
169                 && !phySwitch.getTunnels().getData().isEmpty()) {
170             // Nothing to do but update deviceInfo cache
171             for (UUID uuid: phySwitch.getTunnels().getData()) {
172                 getOvsdbConnectionInstance().getDeviceInfo().putPhysicalSwitchForTunnel(uuid, phySwitch.getUuid());
173             }
174         }
175     }
176
177     private void setManagedBy(PhysicalSwitchAugmentationBuilder psAugmentationBuilder) {
178         InstanceIdentifier<Node> connectionNodePath = getOvsdbConnectionInstance().getInstanceIdentifier();
179         psAugmentationBuilder.setManagedBy(new HwvtepGlobalRef(connectionNodePath));
180     }
181
182     private static void setPhysicalSwitchId(PhysicalSwitchAugmentationBuilder psAugmentationBuilder,
183             PhysicalSwitch phySwitch) {
184         if (phySwitch.getName() != null) {
185             psAugmentationBuilder.setHwvtepNodeName(new HwvtepNodeName(phySwitch.getName()));
186         }
187         if (phySwitch.getDescription() != null) {
188             psAugmentationBuilder.setHwvtepNodeDescription(phySwitch.getDescription());
189         }
190     }
191
192     private static void setManagementIps(PhysicalSwitchAugmentationBuilder psAugmentationBuilder,
193             PhysicalSwitch phySwitch) {
194         if (phySwitch.getManagementIpsColumn() != null && phySwitch.getManagementIpsColumn().getData() != null
195                 && !phySwitch.getManagementIpsColumn().getData().isEmpty()) {
196             var mgmtIps = phySwitch.getManagementIpsColumn().getData().stream()
197                 .map(ip -> new ManagementIpsBuilder()
198                     .setManagementIpsKey(TransactUtils.parseIpAddress(ip))
199                     .build())
200                 .collect(BindingMap.toMap());
201             psAugmentationBuilder.setManagementIps(mgmtIps);
202         }
203     }
204
205     private Node buildConnectionNode(PhysicalSwitch phySwitch) {
206         // Update node with PhysicalSwitch reference
207         NodeBuilder connectionNode = new NodeBuilder();
208         connectionNode.setNodeId(getOvsdbConnectionInstance().getNodeId());
209
210         InstanceIdentifier<Node> switchIid =
211                 HwvtepSouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(), phySwitch);
212         Switches physicalSwitch = new SwitchesBuilder().setSwitchRef(new HwvtepPhysicalSwitchRef(switchIid)).build();
213
214         connectionNode.addAugmentation(new HwvtepGlobalAugmentationBuilder()
215             .setSwitches(Map.of(physicalSwitch.key(), physicalSwitch))
216             .build());
217
218         LOG.debug("Update node with physicalswitch ref {}", physicalSwitch);
219         return connectionNode.build();
220     }
221
222     private InstanceIdentifier<Node> getInstanceIdentifier(PhysicalSwitch phySwitch) {
223         return HwvtepSouthboundMapper.createInstanceIdentifier(getOvsdbConnectionInstance(), phySwitch);
224     }
225
226     private NodeId getNodeId(PhysicalSwitch phySwitch) {
227         NodeKey nodeKey = getInstanceIdentifier(phySwitch).firstKeyOf(Node.class);
228         return nodeKey.getNodeId();
229     }
230
231     private static <T extends DataObject> void deleteEntries(ReadWriteTransaction transaction,
232             List<InstanceIdentifier<T>> entryIids) {
233         for (InstanceIdentifier<T> entryIid : entryIids) {
234             transaction.delete(LogicalDatastoreType.OPERATIONAL, entryIid);
235         }
236     }
237
238     private List<InstanceIdentifier<SwitchFaultStatus>> getSwitchFaultStatusToRemove(InstanceIdentifier<Node> psIid,
239             PhysicalSwitch phySwitch) {
240         requireNonNull(psIid);
241         requireNonNull(phySwitch);
242         List<InstanceIdentifier<SwitchFaultStatus>> result = new ArrayList<>();
243         PhysicalSwitch oldSwitch = oldPSRows.get(phySwitch.getUuid());
244         if (oldSwitch != null && oldSwitch.getSwitchFaultStatusColumn() != null) {
245             for (String switchFltStat : oldSwitch.getSwitchFaultStatusColumn().getData()) {
246                 if (phySwitch.getSwitchFaultStatusColumn() == null
247                         || !phySwitch.getSwitchFaultStatusColumn().getData().contains(switchFltStat)) {
248                     InstanceIdentifier<SwitchFaultStatus> iid = psIid.augmentation(PhysicalSwitchAugmentation.class)
249                             .child(SwitchFaultStatus.class, new SwitchFaultStatusKey(switchFltStat));
250                     result.add(iid);
251                 }
252             }
253         }
254         return result;
255     }
256
257     private static void setSwitchFaultStatus(PhysicalSwitchAugmentationBuilder psAugmentationBuilder,
258             PhysicalSwitch phySwitch) {
259         if (phySwitch.getSwitchFaultStatusColumn() != null && phySwitch.getSwitchFaultStatusColumn().getData() != null
260                 && !phySwitch.getSwitchFaultStatusColumn().getData().isEmpty()) {
261             var switchFaultStatusLst = phySwitch.getSwitchFaultStatusColumn().getData().stream()
262                 .map(switchFaultStatus -> new SwitchFaultStatusBuilder()
263                     .setSwitchFaultStatusKey(switchFaultStatus)
264                     .build())
265                 .collect(BindingMap.toOrderedMap());
266             psAugmentationBuilder.setSwitchFaultStatus(switchFaultStatusLst);
267         }
268     }
269 }