46bb1bfe729e6ed5ff31b5599fd6c83a35aae819
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepTableReader.java
1 /*
2  * Copyright (c) 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;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
12
13 import com.google.common.collect.ImmutableClassToInstanceMap;
14 import com.google.common.collect.ImmutableClassToInstanceMap.Builder;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.Lists;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Optional;
24 import java.util.concurrent.ExecutionException;
25 import java.util.function.Function;
26 import java.util.stream.Collectors;
27 import org.opendaylight.ovsdb.lib.message.TableUpdate;
28 import org.opendaylight.ovsdb.lib.message.TableUpdates;
29 import org.opendaylight.ovsdb.lib.notation.Condition;
30 import org.opendaylight.ovsdb.lib.notation.Row;
31 import org.opendaylight.ovsdb.lib.notation.UUID;
32 import org.opendaylight.ovsdb.lib.operations.Operation;
33 import org.opendaylight.ovsdb.lib.operations.OperationResult;
34 import org.opendaylight.ovsdb.lib.operations.Select;
35 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
36 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
37 import org.opendaylight.ovsdb.lib.schema.typed.TypedDatabaseSchema;
38 import org.opendaylight.ovsdb.schema.hardwarevtep.ACL;
39 import org.opendaylight.ovsdb.schema.hardwarevtep.ACLEntry;
40 import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesLocal;
41 import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesRemote;
42 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
43 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalRouter;
44 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
45 import org.opendaylight.ovsdb.schema.hardwarevtep.Manager;
46 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal;
47 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
48 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
49 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocatorSet;
50 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort;
51 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
52 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
53 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal;
54 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacsKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
66 import org.opendaylight.yangtools.yang.binding.DataObject;
67 import org.opendaylight.yangtools.yang.binding.Identifiable;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 public class HwvtepTableReader {
73
74     private static final Logger LOG = LoggerFactory.getLogger(HwvtepTableReader.class);
75     private static final Class<?>[] ALL_TABLES = new Class[] {
76         ACLEntry.class,
77         ACL.class,
78         ArpSourcesLocal.class,
79         Global.class,
80         ArpSourcesRemote.class,
81         LogicalRouter.class,
82         Manager.class,
83         LogicalSwitch.class,
84         McastMacsLocal.class,
85         PhysicalLocator.class,
86         McastMacsRemote.class,
87         PhysicalPort.class,
88         Tunnel.class,
89         PhysicalLocatorSet.class,
90         PhysicalSwitch.class,
91         UcastMacsLocal.class,
92         UcastMacsRemote.class
93     };
94
95     private static final ImmutableMap<Class<?>, Class<? extends TypedBaseTable<?>>> TABLE_MAP = ImmutableMap.of(
96         RemoteMcastMacs.class, McastMacsRemote.class,
97         RemoteUcastMacs.class, UcastMacsRemote.class,
98         LogicalSwitches.class, LogicalSwitch.class,
99         TerminationPoint.class, PhysicalLocator.class,
100         VlanBindings.class, PhysicalPort.class);
101
102     private final ImmutableMap<Class<? extends Identifiable<?>>, WhereClauseGetter<?>> whereClauseGetters;
103     private final ImmutableClassToInstanceMap<TypedBaseTable<?>> tables;
104     private final HwvtepConnectionInstance connectionInstance;
105
106     public HwvtepTableReader(final HwvtepConnectionInstance connectionInstance) {
107         this.connectionInstance = connectionInstance;
108         TypedDatabaseSchema dbSchema = null;
109         try {
110             dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
111         } catch (InterruptedException | ExecutionException e) {
112             LOG.warn("Not able to fetch schema for database {} from device {}",
113                     HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
114         }
115
116         final Builder<TypedBaseTable<?>> tableBuilder = ImmutableClassToInstanceMap.<TypedBaseTable<?>>builder();
117         final ImmutableMap.Builder<Class<? extends Identifiable<?>>, WhereClauseGetter<?>> whereBuilder =
118                 ImmutableMap.builderWithExpectedSize(4);
119
120         if (dbSchema != null) {
121             final McastMacsRemote mcastMacsTable = dbSchema.getTypedRowWrapper(McastMacsRemote.class, null);
122             if (mcastMacsTable != null) {
123                 tableBuilder.put(McastMacsRemote.class, mcastMacsTable);
124                 whereBuilder.put(RemoteMcastMacs.class, new RemoteMcastMacWhereClauseGetter(mcastMacsTable));
125             }
126             final UcastMacsRemote ucastMacsTable = dbSchema.getTypedRowWrapper(UcastMacsRemote.class, null);
127             if (ucastMacsTable != null) {
128                 tableBuilder.put(UcastMacsRemote.class, ucastMacsTable);
129                 whereBuilder.put(RemoteUcastMacs.class, new RemoteUcastMacWhereClauseGetter(ucastMacsTable));
130             }
131             final LogicalSwitch lsTable = dbSchema.getTypedRowWrapper(LogicalSwitch.class, null);
132             if (lsTable != null) {
133                 tableBuilder.put(LogicalSwitch.class, lsTable);
134                 whereBuilder.put(LogicalSwitches.class, new LogicalSwitchWhereClauseGetter(lsTable));
135             }
136             final PhysicalLocator plTable = dbSchema.getTypedRowWrapper(PhysicalLocator.class, null);
137             if (plTable != null) {
138                 tableBuilder.put(PhysicalLocator.class, plTable);
139                 whereBuilder.put(TerminationPoint.class, new LocatorWhereClauseGetter(plTable));
140             }
141             final PhysicalPort physicalPort = dbSchema.getTypedRowWrapper(PhysicalPort.class, null);
142             if (physicalPort != null) {
143                 tableBuilder.put(PhysicalPort.class, physicalPort);
144             }
145         }
146
147         tables = tableBuilder.build();
148         whereClauseGetters = whereBuilder.build();
149     }
150
151     @FunctionalInterface
152     private interface WhereClauseGetter<T extends DataObject> extends Function<InstanceIdentifier<T>, List<Condition>> {
153
154     }
155
156     class RemoteMcastMacWhereClauseGetter implements WhereClauseGetter<RemoteMcastMacs> {
157         private final McastMacsRemote macTable;
158
159         RemoteMcastMacWhereClauseGetter(final McastMacsRemote macTable) {
160             this.macTable = requireNonNull(macTable);
161         }
162
163         @Override
164         public List<Condition> apply(final InstanceIdentifier<RemoteMcastMacs> iid) {
165             RemoteMcastMacsKey key = iid.firstKeyOf(RemoteMcastMacs.class);
166             InstanceIdentifier<LogicalSwitches> lsIid = (InstanceIdentifier<LogicalSwitches>) key.getLogicalSwitchRef()
167                     .getValue();
168             UUID lsUUID = getLsUuid(lsIid);
169             if (lsUUID == null) {
170                 LOG.warn("Could not find uuid for ls key {}", getNodeKeyStr(lsIid));
171                 return null;
172             }
173
174             ArrayList<Condition> conditions = new ArrayList<>();
175             conditions.add(macTable.getLogicalSwitchColumn().getSchema().opEqual(lsUUID));
176             return conditions;
177         }
178     }
179
180     protected <T extends DataObject> String getNodeKeyStr(InstanceIdentifier<T> iid) {
181         return iid.firstKeyOf(Node.class).getNodeId().getValue() + "." + getLsKeyStr(iid);
182     }
183
184     protected <T extends DataObject> String getLsKeyStr(InstanceIdentifier<T> iid) {
185         return ((InstanceIdentifier<LogicalSwitches>)iid).firstKeyOf(LogicalSwitches.class)
186             .getHwvtepNodeName().getValue();
187     }
188
189     public UUID getLsUuid(InstanceIdentifier lsIid) {
190         UUID lsUUID = connectionInstance.getDeviceInfo().getUUID(LogicalSwitches.class, lsIid);
191         if (lsUUID == null) {
192             Optional<TypedBaseTable> optional =
193                     getHwvtepTableEntryUUID(LogicalSwitches.class, lsIid, null);
194             if (optional.isPresent()) {
195                 lsUUID = optional.get().getUuid();
196             }
197         }
198         return lsUUID;
199     }
200
201     class RemoteUcastMacWhereClauseGetter implements WhereClauseGetter<RemoteUcastMacs> {
202         private final UcastMacsRemote macTable;
203
204         RemoteUcastMacWhereClauseGetter(final UcastMacsRemote macTable) {
205             this.macTable = requireNonNull(macTable);
206         }
207
208         @Override
209         public List<Condition> apply(final InstanceIdentifier<RemoteUcastMacs> iid) {
210             RemoteUcastMacsKey key = iid.firstKeyOf(RemoteUcastMacs.class);
211             InstanceIdentifier<LogicalSwitches> lsIid = (InstanceIdentifier<LogicalSwitches>) key.getLogicalSwitchRef()
212                     .getValue();
213             UUID lsUUID = connectionInstance.getDeviceInfo().getUUID(LogicalSwitches.class, lsIid);
214             if (lsUUID == null) {
215                 LOG.error("Could not find uuid for ls key {}", lsIid);
216                 return null;
217             }
218
219             ArrayList<Condition> conditions = new ArrayList<>();
220             conditions.add(macTable.getLogicalSwitchColumn().getSchema().opEqual(lsUUID));
221             conditions.add(macTable.getMacColumn().getSchema().opEqual(key.getMacEntryKey().getValue()));
222             return conditions;
223         }
224     }
225
226     static class LogicalSwitchWhereClauseGetter implements WhereClauseGetter<LogicalSwitches> {
227         private final LogicalSwitch logicalSwitch;
228
229         LogicalSwitchWhereClauseGetter(final LogicalSwitch logicalSwitch) {
230             this.logicalSwitch = requireNonNull(logicalSwitch);
231         }
232
233         @Override
234         public List<Condition> apply(final InstanceIdentifier<LogicalSwitches> iid) {
235             String lsName = iid.firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
236             return Lists.newArrayList(logicalSwitch.getNameColumn().getSchema().opEqual(lsName));
237         }
238     }
239
240     static class LocatorWhereClauseGetter implements WhereClauseGetter<TerminationPoint> {
241         private final PhysicalLocator locatorTable;
242
243         LocatorWhereClauseGetter(final PhysicalLocator locatorTable) {
244             this.locatorTable = requireNonNull(locatorTable);
245         }
246
247         @Override
248         public List<Condition> apply(final InstanceIdentifier<TerminationPoint> iid) {
249             String locatorIp = iid.firstKeyOf(TerminationPoint.class).getTpId().getValue();
250             locatorIp = locatorIp.substring(locatorIp.indexOf(":") + 1);
251             LOG.info("Locator ip to look for {}", locatorIp);
252             return Lists.newArrayList(locatorTable.getDstIpColumn().getSchema().opEqual(locatorIp));
253         }
254     }
255
256     @SuppressWarnings("checkstyle:IllegalCatch")
257     public Optional<TypedBaseTable> getHwvtepTableEntryUUID(final Class<? extends Identifiable> cls,
258                                                             final InstanceIdentifier iid,
259                                                             final UUID existingUUID) {
260         final TypedDatabaseSchema dbSchema;
261         try {
262             dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
263         } catch (InterruptedException | ExecutionException e) {
264             LOG.warn("Not able to fetch schema for database {} from device {}",
265                 HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
266             return Optional.empty();
267         }
268
269         final Class<? extends TypedBaseTable<?>> tableClass = TABLE_MAP.get(cls);
270         final GenericTableSchema hwvtepSchema = dbSchema.getTableSchema(tableClass);
271
272         final Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
273         selectOperation.setColumns(hwvtepSchema.getColumnList());
274
275         if (existingUUID == null) {
276             final WhereClauseGetter<?> whereClausule = whereClauseGetters.get(cls);
277             if (whereClausule == null) {
278                 LOG.error("Could not get where class for cls {} ", cls);
279                 return Optional.empty();
280             }
281             final List<Condition> conditions = whereClausule.apply(iid);
282             if (conditions == null) {
283                 LOG.error("Could not get where conditions for cls {} key {}", cls, iid);
284                 return Optional.empty();
285             }
286
287             if (conditions.size() == 2) {
288                 selectOperation.where(conditions.get(0)).and(conditions.get(1));
289             } else {
290                 selectOperation.where(conditions.get(0));
291             }
292         } else {
293             TypedBaseTable<?> table = tables.get(tableClass);
294             LOG.info("Setting uuid condition {} ", existingUUID);
295             selectOperation.where(table.getUuidColumn().getSchema().opEqual(existingUUID));
296         }
297
298         final List<OperationResult> results;
299         try {
300             results = connectionInstance.transact(dbSchema, Collections.singletonList(selectOperation)).get();
301         } catch (InterruptedException | ExecutionException e) {
302             LOG.warn("Not able to fetch hardware_vtep table row from device {}",
303                 connectionInstance.getConnectionInfo(), e);
304             return Optional.empty();
305         }
306         if (results == null || results.isEmpty()) {
307             return Optional.empty();
308         }
309
310         final List<Row<GenericTableSchema>> selectResult = results.get(0).getRows();
311         if (selectResult == null || selectResult.isEmpty()) {
312             return Optional.empty();
313         }
314
315         final TypedBaseTable globalRow = dbSchema.getTypedRowWrapper(tableClass, selectResult.get(0));
316         LOG.trace("Fetched {} from hardware_vtep schema", globalRow);
317         return globalRow != null && globalRow.getUuid() != null ?  Optional.of(globalRow) : Optional.empty();
318     }
319
320     @SuppressWarnings("checkstyle:IllegalCatch")
321     public List<TypedBaseTable> getHwvtepTableEntries(final Class<? extends Identifiable> cls) {
322         final TypedDatabaseSchema dbSchema;
323         try {
324             dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
325         } catch (InterruptedException | ExecutionException e) {
326             LOG.error("Not able to fetch schema for database {} from device {}",
327                 HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
328             return null;
329         }
330
331         final Class<? extends TypedBaseTable<?>> tableClass = TABLE_MAP.get(cls);
332         final GenericTableSchema hwvtepSchema = dbSchema.getTableSchema(tableClass);
333         final Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
334         selectOperation.setColumns(hwvtepSchema.getColumnList());
335
336         final List<OperationResult> results;
337         try {
338             results = connectionInstance.transact(dbSchema, Collections.singletonList(selectOperation)).get();
339         } catch (InterruptedException | ExecutionException e) {
340             LOG.error("Not able to fetch hardware_vtep table row from device {}",
341                 connectionInstance.getConnectionInfo(), e);
342             return Collections.emptyList();
343         }
344         if (results == null || results.isEmpty()) {
345             return Collections.emptyList();
346         }
347
348         try {
349             final List<TypedBaseTable> tableRows = new ArrayList<>();
350             for (OperationResult selectResult : results) {
351                 if (selectResult.getRows() != null && !selectResult.getRows().isEmpty()) {
352                     for (Row<GenericTableSchema> row : selectResult.getRows()) {
353                         tableRows.add(dbSchema.getTypedRowWrapper(tableClass, row));
354                     }
355                 }
356             }
357             return tableRows;
358         } catch (RuntimeException e) {
359             LOG.error("Failed to get the hwvtep ", e);
360             return Collections.emptyList();
361         }
362     }
363
364     public TableUpdates readAllTables() throws ExecutionException, InterruptedException {
365         TypedDatabaseSchema dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
366         List<Operation> operations = Arrays.stream(ALL_TABLES)
367                 .map(tableClass -> dbSchema.getTableSchema(tableClass))
368                 .map(HwvtepTableReader::buildSelectOperationFor)
369                 .collect(Collectors.toList());
370         List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
371
372         Map<String, TableUpdate> tableUpdates = new HashMap<>();
373         if (results != null) {
374             for (OperationResult result : results) {
375                 final List<Row<GenericTableSchema>> rows = result.getRows();
376                 if (rows != null) {
377                     for (Row<GenericTableSchema> row : rows) {
378                         tableUpdates.computeIfAbsent(row.getTableSchema().getName(), key -> new TableUpdate<>())
379                             .addRow(getRowUuid(row), null, row);
380                     }
381                 }
382             }
383         }
384         return new TableUpdates(tableUpdates);
385     }
386
387     public void refreshLocators() {
388         List<TypedBaseTable> physicalLocators = connectionInstance.getHwvtepTableReader()
389                 .getHwvtepTableEntries(TerminationPoint.class);
390         for (TypedBaseTable row : physicalLocators) {
391             PhysicalLocator physicalLocator = (PhysicalLocator)row;
392             InstanceIdentifier<TerminationPoint> tpPath =
393                     HwvtepSouthboundMapper.createInstanceIdentifier(connectionInstance.getInstanceIdentifier(),
394                             physicalLocator);
395             connectionInstance.getDeviceInfo().updateDeviceOperData(
396                     TerminationPoint.class, tpPath, physicalLocator.getUuid(), physicalLocator);
397         }
398     }
399
400     public void refreshLogicalSwitches() {
401         List<TypedBaseTable> logicalSwitches = connectionInstance.getHwvtepTableReader()
402                 .getHwvtepTableEntries(LogicalSwitches.class);
403         for (TypedBaseTable row : logicalSwitches) {
404             LogicalSwitch logicalSwitch = (LogicalSwitch)row;
405             InstanceIdentifier<LogicalSwitches> switchIid = connectionInstance.getInstanceIdentifier()
406                     .augmentation(HwvtepGlobalAugmentation.class)
407                     .child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName(logicalSwitch.getName())));
408             connectionInstance.getDeviceInfo().updateDeviceOperData(LogicalSwitches.class, switchIid,
409                     logicalSwitch.getUuid(), logicalSwitch);
410         }
411     }
412
413     private static Select<GenericTableSchema> buildSelectOperationFor(final GenericTableSchema tableSchema) {
414         Select<GenericTableSchema> selectOperation = op.select(tableSchema);
415         selectOperation.setColumns(tableSchema.getColumnList());
416         return selectOperation;
417     }
418
419     private static UUID getRowUuid(final Row<GenericTableSchema> row) {
420         return row.getColumns().stream()
421                 .filter(column -> column.getSchema().getName().equals("_uuid"))
422                 .map(column -> (UUID) column.getData())
423                 .findFirst().orElse(new UUID("test"));
424     }
425 }