ae3716b8e8d26434c2709ac2acb4e9f9bc8dd3da
[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 org.opendaylight.ovsdb.lib.operations.Operations.op;
11
12 import com.google.common.collect.Lists;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import java.util.function.Function;
22 import java.util.stream.Collectors;
23 import org.opendaylight.ovsdb.lib.message.TableUpdate;
24 import org.opendaylight.ovsdb.lib.message.TableUpdates;
25 import org.opendaylight.ovsdb.lib.notation.Condition;
26 import org.opendaylight.ovsdb.lib.notation.Row;
27 import org.opendaylight.ovsdb.lib.notation.UUID;
28 import org.opendaylight.ovsdb.lib.operations.Operation;
29 import org.opendaylight.ovsdb.lib.operations.OperationResult;
30 import org.opendaylight.ovsdb.lib.operations.Select;
31 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
32 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
33 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
34 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
35 import org.opendaylight.ovsdb.schema.hardwarevtep.ACL;
36 import org.opendaylight.ovsdb.schema.hardwarevtep.ACLEntry;
37 import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesLocal;
38 import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesRemote;
39 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
40 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalRouter;
41 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
42 import org.opendaylight.ovsdb.schema.hardwarevtep.Manager;
43 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal;
44 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
45 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
46 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocatorSet;
47 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort;
48 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
49 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
50 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal;
51 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
56 import org.opendaylight.yangtools.yang.binding.Identifiable;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 public class HwvtepTableReader {
62
63     private static final Logger LOG = LoggerFactory.getLogger(HwvtepTableReader.class);
64
65     private final Class[] alltables = new Class[] {
66         ACLEntry.class,
67         ACL.class,
68         ArpSourcesLocal.class,
69         Global.class,
70         ArpSourcesRemote.class,
71         LogicalRouter.class,
72         Manager.class,
73         LogicalSwitch.class,
74         McastMacsLocal.class,
75         PhysicalLocator.class,
76         McastMacsRemote.class,
77         PhysicalPort.class,
78         Tunnel.class,
79         PhysicalLocatorSet.class,
80         PhysicalSwitch.class,
81         UcastMacsLocal.class,
82         UcastMacsRemote.class
83     };
84
85     private final Map<Class, Function<InstanceIdentifier, List<Condition>>> whereClauseGetterMap = new HashMap();
86     private final Map<Class, Class> tableMap = new HashMap();
87     private final Map<Class, TypedBaseTable> tables = new HashMap<>();
88
89     private final HwvtepConnectionInstance connectionInstance;
90
91     public HwvtepTableReader(HwvtepConnectionInstance connectionInstance) {
92         this.connectionInstance = connectionInstance;
93         DatabaseSchema dbSchema = null;
94         try {
95             dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
96         } catch (InterruptedException | ExecutionException e) {
97             LOG.warn("Not able to fetch schema for database {} from device {}",
98                     HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
99         }
100
101         tableMap.put(RemoteMcastMacs.class, McastMacsRemote.class);
102         tableMap.put(RemoteUcastMacs.class, UcastMacsRemote.class);
103         tableMap.put(LogicalSwitches.class, LogicalSwitch.class);
104         tableMap.put(TerminationPoint.class, PhysicalLocator.class);
105
106         whereClauseGetterMap.put(RemoteMcastMacs.class, new RemoteMcastMacWhereClauseGetter());
107         whereClauseGetterMap.put(RemoteUcastMacs.class, new RemoteUcastMacWhereClauseGetter());
108         whereClauseGetterMap.put(LogicalSwitches.class, new LogicalSwitchWhereClauseGetter());
109         whereClauseGetterMap.put(TerminationPoint.class, new LocatorWhereClauseGetter());
110
111         tables.put(McastMacsRemote.class, TyperUtils.getTypedRowWrapper(dbSchema, McastMacsRemote.class, null));
112         tables.put(UcastMacsRemote.class, TyperUtils.getTypedRowWrapper(dbSchema, UcastMacsRemote.class, null));
113         tables.put(LogicalSwitch.class, TyperUtils.getTypedRowWrapper(dbSchema, LogicalSwitch.class, null));
114         tables.put(PhysicalLocator.class, TyperUtils.getTypedRowWrapper(dbSchema, PhysicalLocator.class, null));
115     }
116
117     class RemoteMcastMacWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
118         @Override
119         public List<Condition> apply(InstanceIdentifier iid) {
120             InstanceIdentifier<RemoteMcastMacs> macIid = iid;
121             String mac = macIid.firstKeyOf(RemoteMcastMacs.class).getMacEntryKey().getValue();
122             InstanceIdentifier<LogicalSwitches> lsIid = (InstanceIdentifier<LogicalSwitches>) macIid.firstKeyOf(
123                     RemoteMcastMacs.class).getLogicalSwitchRef().getValue();
124             UUID lsUUID = connectionInstance.getDeviceInfo().getUUID(LogicalSwitches.class, lsIid);
125             if (lsUUID == null) {
126                 LOG.error("Could not find uuid for ls key {}", lsIid);
127                 return null;
128             }
129
130             McastMacsRemote macTable = (McastMacsRemote) tables.get(McastMacsRemote.class);
131             ArrayList<Condition> conditions = new ArrayList<>();
132             conditions.add(macTable.getLogicalSwitchColumn().getSchema().opEqual(lsUUID));
133             conditions.add(macTable.getMacColumn().getSchema().opEqual(mac));
134             return conditions;
135         }
136     }
137
138     class RemoteUcastMacWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
139         @Override
140         public List<Condition> apply(InstanceIdentifier iid) {
141             InstanceIdentifier<RemoteUcastMacs> macIid = iid;
142             String mac = macIid.firstKeyOf(RemoteUcastMacs.class).getMacEntryKey().getValue();
143             InstanceIdentifier<LogicalSwitches> lsIid = (InstanceIdentifier<LogicalSwitches>) macIid.firstKeyOf(
144                     RemoteUcastMacs.class).getLogicalSwitchRef().getValue();
145             UUID lsUUID = connectionInstance.getDeviceInfo().getUUID(LogicalSwitches.class, lsIid);
146             if (lsUUID == null) {
147                 LOG.error("Could not find uuid for ls key {}", lsIid);
148                 return null;
149             }
150
151             UcastMacsRemote macTable = (UcastMacsRemote) tables.get(UcastMacsRemote.class);
152             ArrayList<Condition> conditions = new ArrayList<>();
153             conditions.add(macTable.getLogicalSwitchColumn().getSchema().opEqual(lsUUID));
154             conditions.add(macTable.getMacColumn().getSchema().opEqual(mac));
155             return conditions;
156         }
157     }
158
159     class LogicalSwitchWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
160         @Override
161         public List<Condition> apply(InstanceIdentifier iid) {
162             InstanceIdentifier<LogicalSwitches> lsIid = iid;
163             String lsName = lsIid.firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
164             LogicalSwitch logicalSwitch = (LogicalSwitch) tables.get(LogicalSwitch.class);
165             return Lists.newArrayList(logicalSwitch.getNameColumn().getSchema().opEqual(lsName));
166         }
167     }
168
169     class LocatorWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
170         @Override
171         public List<Condition> apply(InstanceIdentifier iid) {
172             InstanceIdentifier<TerminationPoint> tepIid = iid;
173             String locatorIp = tepIid.firstKeyOf(TerminationPoint.class).getTpId().getValue();
174             locatorIp = locatorIp.substring(locatorIp.indexOf(":") + 1);
175             LOG.info("Locator ip to look for {}", locatorIp);
176             PhysicalLocator locatorTable = (PhysicalLocator) tables.get(PhysicalLocator.class);
177             return Lists.newArrayList(locatorTable.getDstIpColumn().getSchema().opEqual(locatorIp));
178         }
179     }
180
181     @SuppressWarnings("checkstyle:IllegalCatch")
182     public Optional<TypedBaseTable> getHwvtepTableEntryUUID(Class<? extends Identifiable> cls,
183                                                             InstanceIdentifier iid,
184                                                             UUID existingUUID) {
185         try {
186             DatabaseSchema dbSchema = null;
187             TypedBaseTable globalRow = null;
188             Class<TypedBaseTable> tableClass = tableMap.get(cls);
189             try {
190                 dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
191             } catch (InterruptedException | ExecutionException e) {
192                 LOG.warn("Not able to fetch schema for database {} from device {}",
193                         HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
194             }
195
196             if (dbSchema != null) {
197                 GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, tableClass);
198
199                 List<String> hwvtepTableColumn = new ArrayList<>();
200                 hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
201                 Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
202                 selectOperation.setColumns(hwvtepTableColumn);
203
204                 if (existingUUID != null) {
205                     TypedBaseTable table = tables.get(tableClass);
206                     LOG.info("Setting uuid condition {} ", existingUUID);
207                     selectOperation.where(table.getUuidColumn().getSchema().opEqual(existingUUID));
208                 } else {
209                     if (whereClauseGetterMap.get(cls) != null) {
210                         List<Condition> conditions = whereClauseGetterMap.get(cls).apply(iid);
211                         if (conditions != null) {
212                             if (conditions.size() == 2) {
213                                 selectOperation.where(conditions.get(0)).and(conditions.get(1));
214                             } else {
215                                 selectOperation.where(conditions.get(0));
216                             }
217                         } else {
218                             LOG.error("Could not get where conditions for cls {} key {}", cls, iid);
219                             return Optional.empty();
220                         }
221                     } else {
222                         LOG.error("Could not get where class for cls {} ", cls);
223                         return Optional.empty();
224                     }
225                 }
226                 ArrayList<Operation> operations = new ArrayList<>();
227                 operations.add(selectOperation);
228                 try {
229                     List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
230                     if (results != null && !results.isEmpty()) {
231                         OperationResult selectResult = results.get(0);
232                         if (selectResult.getRows() != null && !selectResult.getRows().isEmpty()) {
233                             globalRow = TyperUtils.getTypedRowWrapper(
234                                     dbSchema, tableClass, selectResult.getRows().get(0));
235                         }
236                     }
237                 } catch (InterruptedException | ExecutionException e) {
238                     LOG.warn("Not able to fetch hardware_vtep table row from device {}",
239                             connectionInstance.getConnectionInfo(), e);
240                 }
241             }
242             LOG.trace("Fetched {} from hardware_vtep schema", globalRow);
243             if (globalRow != null && globalRow.getUuid() != null) {
244                 return Optional.of(globalRow);
245             }
246             return Optional.empty();
247         } catch (RuntimeException e) {
248             LOG.error("Failed to get the hwvtep row for iid {}", iid, e);
249             return Optional.empty();
250         }
251     }
252
253     @SuppressWarnings("checkstyle:IllegalCatch")
254     public List<TypedBaseTable> getHwvtepTableEntries(Class<? extends Identifiable> cls) {
255         try {
256             List<TypedBaseTable> tableRows = new ArrayList<>();
257             DatabaseSchema dbSchema = null;
258             TypedBaseTable globalRow = null;
259             Class<TypedBaseTable> tableClass = tableMap.get(cls);
260             try {
261                 dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
262             } catch (InterruptedException | ExecutionException e) {
263                 LOG.error("Not able to fetch schema for database {} from device {}",
264                         HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
265             }
266
267             if (dbSchema != null) {
268                 GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, tableClass);
269
270                 List<String> hwvtepTableColumn = new ArrayList<>();
271                 hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
272                 Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
273                 selectOperation.setColumns(hwvtepTableColumn);
274
275                 ArrayList<Operation> operations = Lists.newArrayList(selectOperation);
276                 try {
277                     List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
278                     if (results != null && !results.isEmpty()) {
279                         for (OperationResult selectResult : results) {
280                             if (selectResult.getRows() != null && !selectResult.getRows().isEmpty()) {
281                                 for (Row<GenericTableSchema> row : selectResult.getRows()) {
282                                     tableRows.add(TyperUtils.getTypedRowWrapper(dbSchema, tableClass, row));
283                                 }
284                             }
285                         }
286                     }
287                 } catch (InterruptedException | ExecutionException e) {
288                     LOG.error("Not able to fetch hardware_vtep table row from device {}",
289                             connectionInstance.getConnectionInfo(), e);
290                 }
291             }
292             return tableRows;
293         } catch (RuntimeException e) {
294             LOG.error("Failed to get the hwvtep ", e);
295         }
296         return Collections.emptyList();
297     }
298
299     public TableUpdates readAllTables() throws ExecutionException, InterruptedException {
300         Map<String, TableUpdate> tableUpdates =  new HashMap<>();
301         DatabaseSchema dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
302
303         List<Operation> operations = Arrays.asList(alltables).stream()
304                 .map(tableClass -> TyperUtils.getTableSchema(dbSchema, tableClass))
305                 .map(tableSchema -> buildSelectOperationFor(tableSchema))
306                 .collect(Collectors.toList());
307
308         List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
309         if (results != null && !results.isEmpty()) {
310             results.stream()
311                     .filter(result -> result.getRows() != null)
312                     .flatMap(result -> result.getRows().stream())
313                     .forEach(row -> {
314                         tableUpdates.compute(row.getTableSchema().getName(), (tableName, tableUpdate) -> {
315                             if (tableUpdate == null) {
316                                 tableUpdate = new TableUpdate();
317                             }
318                             tableUpdate.addRow(getRowUuid(row), null, row);
319                             return tableUpdate;
320                         });
321                     });
322         }
323         return new TableUpdates(tableUpdates);
324     }
325
326     private Select<GenericTableSchema> buildSelectOperationFor(GenericTableSchema tableSchema) {
327         Select<GenericTableSchema> selectOpearation = op.select(tableSchema);
328         selectOpearation.setColumns(new ArrayList<>(tableSchema.getColumns()));
329         return selectOpearation;
330     }
331
332     private UUID getRowUuid(Row<GenericTableSchema> row) {
333         return row.getColumns().stream()
334                 .filter(column -> column.getSchema().getName().equals("_uuid"))
335                 .map(column -> (UUID) column.getData())
336                 .findFirst().orElse(new UUID("test"));
337     }
338 }