2 * Copyright (c) 2015, 2017 China Telecom Beijing Research Institute and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
11 import org.apache.commons.lang3.tuple.Pair;
12 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
13 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
14 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
18 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
19 import org.opendaylight.yangtools.yang.binding.DataObject;
20 import org.opendaylight.yangtools.yang.binding.Identifiable;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Objects;
32 public class TransactCommandAggregator implements TransactCommand {
33 private static final Logger LOG = LoggerFactory.getLogger(TransactCommandAggregator.class);
35 private List<TransactCommand> commands = new ArrayList<>();
36 private final HwvtepOperationalState operationalState;
37 /* stores the modified and deleted data for each child type of each node id
38 Map<nodeid , Pair < updated, deleted >
39 each updated/ deleted contains Map < child type, List<ChildData>>
40 child type is the child of hwvtep Global augmentation
42 private final Map<InstanceIdentifier<Node>,
43 Pair<Map<Class<? extends Identifiable>, List<Identifiable>>,
44 Map<Class<? extends Identifiable>, List<Identifiable>>>> modifiedData = new HashMap<>();
47 public TransactCommandAggregator(HwvtepOperationalState state, Collection<DataTreeModification<Node>> changes) {
48 this.operationalState = state;
49 onDataTreeChanged(changes);
50 commands.add(new PhysicalSwitchUpdateCommand(state,changes));
51 commands.add(new PhysicalSwitchRemoveCommand(state,changes));
52 commands.add(new LogicalSwitchUpdateCommand(state,changes));
53 commands.add(new LogicalSwitchRemoveCommand(state,changes));
54 commands.add(new PhysicalPortUpdateCommand(state,changes));
55 commands.add(new PhysicalPortRemoveCommand(state,changes));
56 commands.add(new McastMacsRemoteUpdateCommand(state,changes));
57 commands.add(new McastMacsRemoteRemoveCommand(state,changes));
58 commands.add(new McastMacsLocalUpdateCommand(state,changes));
59 commands.add(new McastMacsLocalRemoveCommand(state,changes));
60 commands.add(new UcastMacsRemoteUpdateCommand(state,changes));
61 commands.add(new UcastMacsRemoteRemoveCommand(state,changes));
62 commands.add(new UcastMacsLocalUpdateCommand(state,changes));
63 commands.add(new UcastMacsLocalRemoveCommand(state,changes));
64 commands.add(new TunnelUpdateCommand(state,changes));
65 commands.add(new TunnelRemoveCommand(state,changes));
66 commands.add(new LogicalRouterUpdateCommand(state,changes));
67 commands.add(new LogicalRouterRemoveCommand(state,changes));
71 public void execute(TransactionBuilder transaction) {
72 for (TransactCommand command:commands) {
74 command.execute(transaction);
75 } catch (NullPointerException e) {
76 LOG.error("Execution of command {} failed with the following exception."
77 + " Continuing the execution of remaining commands", command, e);
83 public void onConfigUpdate(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data,
84 InstanceIdentifier key,
85 Object... extraData) {
89 public void doDeviceTransaction(TransactionBuilder transaction, InstanceIdentifier nodeIid, Identifiable data,
90 InstanceIdentifier key,
91 Object... extraData) {
94 private void onDataTreeChanged(final Collection<DataTreeModification<Node>> changes) {
95 boolean readOperationalNodes = false;
96 for (DataTreeModification<Node> change : changes) {
97 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
98 final DataObjectModification<Node> mod = change.getRootNode();
99 final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData = new HashMap<>();
100 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData = new HashMap<>();
101 extractDataChanged(key, mod, updatedData, deletedData);
102 modifiedData.put(key, Pair.of(updatedData, deletedData));
103 operationalState.setModifiedData(modifiedData);
104 if (!isMacOnlyUpdate(updatedData, deletedData)) {
105 readOperationalNodes = true;
108 if (readOperationalNodes) {
109 operationalState.readOperationalNodes();
113 private boolean isMacOnlyUpdate(final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
114 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
115 return (updatedData.containsKey(RemoteUcastMacs.class) && updatedData.size() == 1)
116 || (deletedData.containsKey(RemoteUcastMacs.class) && deletedData.size() == 1);
119 private void extractDataChanged(final InstanceIdentifier<Node> key,
120 final DataObjectModification<Node> mod,
121 final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
122 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
124 extractDataChanged(mod.getModifiedChildren(), updatedData, deletedData);
125 DataObjectModification<HwvtepGlobalAugmentation> aug = mod.getModifiedAugmentation(
126 HwvtepGlobalAugmentation.class);
127 if (aug != null && getModificationType(aug) != null) {
128 extractDataChanged(aug.getModifiedChildren(), updatedData, deletedData);
130 DataObjectModification<PhysicalSwitchAugmentation> psAug = mod.getModifiedAugmentation(
131 PhysicalSwitchAugmentation.class);
132 if (psAug != null && getModificationType(psAug) != null) {
133 extractDataChanged(psAug.getModifiedChildren(), updatedData, deletedData);
137 private void extractDataChanged(final Collection<DataObjectModification<? extends DataObject>> children,
138 final Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
139 final Map<Class<? extends Identifiable>, List<Identifiable>> deletedData) {
140 if (children == null) {
143 for (DataObjectModification<? extends DataObject> child : children) {
144 DataObjectModification.ModificationType type = getModificationType(child);
148 InstanceIdentifier instanceIdentifier = null;
149 Class<? extends Identifiable> childClass = (Class<? extends Identifiable>) child.getDataType();
150 InstanceIdentifier.PathArgument pathArgument = child.getIdentifier();
153 case SUBTREE_MODIFIED:
154 DataObject dataAfter = child.getDataAfter();
155 if (!(dataAfter instanceof Identifiable)) {
158 DataObject before = child.getDataBefore();
159 if (Objects.equals(dataAfter, before)) {
161 in cluster reboot scenarios,
162 application rewrites the data tx.put( logicalswitchiid, logicalswitch )
163 that time it fires the update again ignoring such updates here
167 Identifiable identifiable = (Identifiable) dataAfter;
168 addToUpdatedData(updatedData, childClass, identifiable);
171 DataObject dataBefore = child.getDataBefore();
172 if (!(dataBefore instanceof Identifiable)) {
175 addToUpdatedData(deletedData, childClass, (Identifiable)dataBefore);
181 private void addToUpdatedData(Map<Class<? extends Identifiable>, List<Identifiable>> updatedData,
182 Class<? extends Identifiable> childClass, Identifiable identifiable) {
183 updatedData.computeIfAbsent(childClass, (cls) -> new ArrayList<>());
184 updatedData.get(childClass).add(identifiable);
187 private DataObjectModification.ModificationType getModificationType(
188 DataObjectModification<? extends DataObject> mod) {
190 return mod.getModificationType();
191 } catch (IllegalStateException e) {
192 //not sure why this getter throws this exception, could be some mdsal bug
193 LOG.warn("Failed to get the modification type for mod {}", mod);