ELAN FT Support for BE
[vpnservice.git] / mdsalutil / mdsalutil-impl / src / main / java / org / opendaylight / vpnservice / mdsalutil / internal / MDSALManager.java
1 /*
2  * Copyright (c) 2015 - 2016 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
9 package org.opendaylight.vpnservice.mdsalutil.internal;
10
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16
17 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
18 import org.opendaylight.vpnservice.mdsalutil.ActionType;
19 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
20 import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
21 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.opendaylight.vpnservice.mdsalutil.*;
48 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
49 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
50 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
51 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
52 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
53
54 import com.google.common.util.concurrent.CheckedFuture;
55 import com.google.common.util.concurrent.FutureCallback;
56 import com.google.common.util.concurrent.Futures;
57
58 public class MDSALManager implements AutoCloseable {
59
60     private static final Logger s_logger = LoggerFactory.getLogger(MDSALManager.class);
61
62     private DataBroker m_dataBroker;
63
64     private PacketProcessingService m_packetProcessingService;
65     private ConcurrentMap<FlowInfoKey, Runnable> flowMap = new ConcurrentHashMap<FlowInfoKey, Runnable>();
66     private ConcurrentMap<GroupInfoKey, Runnable> groupMap = new ConcurrentHashMap<GroupInfoKey, Runnable> ();
67
68     /**
69      * Writes the flows and Groups to the MD SAL DataStore
70      * which will be sent to the openflowplugin for installing flows/groups on the switch.
71      * Other modules of VPN service that wants to install flows / groups on the switch
72      * uses this utility
73      *
74      * @param db - dataBroker reference
75      * @param pktProcService- PacketProcessingService for sending the packet outs
76      */
77     public MDSALManager(final DataBroker db, PacketProcessingService pktProcService) {
78         m_dataBroker = db;
79         m_packetProcessingService = pktProcService;
80         s_logger.info( "MDSAL Manager Initialized ") ;
81     }
82
83     @Override
84     public void close() throws Exception {
85         s_logger.info("MDSAL Manager Closed");
86     }
87
88     public void installFlow(FlowEntity flowEntity) {
89
90         try {
91             s_logger.trace("InstallFlow for flowEntity {} ", flowEntity);
92
93             if (flowEntity.getCookie() == null) {
94                flowEntity.setCookie(new BigInteger("0110000", 16));
95             }
96
97             FlowKey flowKey = new FlowKey( new FlowId(flowEntity.getFlowId()) );
98
99             FlowBuilder flowbld = flowEntity.getFlowBuilder();
100
101             Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
102             InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
103                     .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
104                     .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class,flowKey).build();
105
106             WriteTransaction modification = m_dataBroker.newWriteOnlyTransaction();
107
108             modification.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
109
110             CheckedFuture<Void,TransactionCommitFailedException> submitFuture  = modification.submit();
111
112             Futures.addCallback(submitFuture, new FutureCallback<Void>() {
113
114                 @Override
115                 public void onSuccess(final Void result) {
116                     // Commited successfully
117                     s_logger.debug( "Install Flow -- Committedsuccessfully ") ;
118                 }
119
120                 @Override
121                 public void onFailure(final Throwable t) {
122                     // Transaction failed
123
124                     if(t instanceof OptimisticLockFailedException) {
125                         // Failed because of concurrent transaction modifying same data
126                         s_logger.error( "Install Flow -- Failed because of concurrent transaction modifying same data ") ;
127                     } else {
128                        // Some other type of TransactionCommitFailedException
129                         s_logger.error( "Install Flow -- Some other type of TransactionCommitFailedException " + t) ;
130                     }
131                 }
132             });
133         } catch (Exception e) {
134             s_logger.error("Could not install flow: {}", flowEntity, e);
135         }
136     }
137
138     public CheckedFuture<Void,TransactionCommitFailedException> installFlow(BigInteger dpId, Flow flow) {
139         FlowKey flowKey = new FlowKey( new FlowId(flow.getId()) );
140         Node nodeDpn = buildDpnNode(dpId);
141         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
142                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
143                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
144         WriteTransaction modification = m_dataBroker.newWriteOnlyTransaction();
145         modification.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
146         return modification.submit();
147     }
148
149     public void installGroup(GroupEntity groupEntity) {
150         try {
151             Group group = groupEntity.getGroupBuilder().build();
152
153             Node nodeDpn = buildDpnNode(groupEntity.getDpnId());
154
155             InstanceIdentifier<Group> groupInstanceId = InstanceIdentifier.builder(Nodes.class)
156                     .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
157                     .child(Group.class, new GroupKey(new GroupId(groupEntity.getGroupId()))).build();
158
159             WriteTransaction modification = m_dataBroker.newWriteOnlyTransaction();
160
161             modification.put(LogicalDatastoreType.CONFIGURATION, groupInstanceId, group, true);
162
163             CheckedFuture<Void,TransactionCommitFailedException> submitFuture  = modification.submit();
164
165             Futures.addCallback(submitFuture, new FutureCallback<Void>() {
166                 @Override
167                 public void onSuccess(final Void result) {
168                     // Commited successfully
169                     s_logger.debug( "Install Group -- Committedsuccessfully ") ;
170                 }
171
172                 @Override
173                 public void onFailure(final Throwable t) {
174                     // Transaction failed
175
176                     if(t instanceof OptimisticLockFailedException) {
177                         // Failed because of concurrent transaction modifying same data
178                         s_logger.error( "Install Group -- Failed because of concurrent transaction modifying same data ") ;
179                     } else {
180                        // Some other type of TransactionCommitFailedException
181                         s_logger.error( "Install Group -- Some other type of TransactionCommitFailedException " + t) ;
182                     }
183                 }
184              });
185            } catch (Exception e) {
186             s_logger.error("Could not install Group: {}", groupEntity, e);
187             throw e;
188         }
189     }
190
191     public void removeFlow(FlowEntity flowEntity) {
192         try {
193             s_logger.debug("Remove flow {}",flowEntity);
194             Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
195             FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
196             InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
197                     .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
198                     .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
199
200
201                 WriteTransaction modification = m_dataBroker.newWriteOnlyTransaction();
202                 modification.delete(LogicalDatastoreType.CONFIGURATION,flowInstanceId);
203
204                 CheckedFuture<Void,TransactionCommitFailedException> submitFuture  = modification.submit();
205
206                 Futures.addCallback(submitFuture, new FutureCallback<Void>() {
207                     @Override
208                     public void onSuccess(final Void result) {
209                         // Commited successfully
210                         s_logger.debug( "Delete Flow -- Committedsuccessfully ") ;
211                     }
212
213                     @Override
214                     public void onFailure(final Throwable t) {
215                         // Transaction failed
216                         if(t instanceof OptimisticLockFailedException) {
217                             // Failed because of concurrent transaction modifying same data
218                             s_logger.error( "Delete Flow -- Failed because of concurrent transaction modifying same data ") ;
219                         } else {
220                            // Some other type of TransactionCommitFailedException
221                             s_logger.error( "Delete Flow -- Some other type of TransactionCommitFailedException " + t) ;
222                         }
223                     }
224
225                 });
226         } catch (Exception e) {
227             s_logger.error("Could not remove Flow: {}", flowEntity, e);
228         }
229     }
230
231     public CheckedFuture<Void,TransactionCommitFailedException> removeFlowNew(BigInteger dpnId, Flow flowEntity) {
232         s_logger.debug("Remove flow {}",flowEntity);
233         Node nodeDpn = buildDpnNode(dpnId);
234         FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getId()));
235         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
236                     .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
237                     .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
238         WriteTransaction  modification = m_dataBroker.newWriteOnlyTransaction();
239         modification.delete(LogicalDatastoreType.CONFIGURATION,flowInstanceId );
240         return modification.submit();
241     }
242
243     public void removeGroup(GroupEntity groupEntity) {
244         try {
245             Node nodeDpn = buildDpnNode(groupEntity.getDpnId());
246             InstanceIdentifier<Group> groupInstanceId = InstanceIdentifier.builder(Nodes.class)
247                     .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
248                     .child(Group.class, new GroupKey(new GroupId(groupEntity.getGroupId()))).build();
249
250             WriteTransaction modification = m_dataBroker.newWriteOnlyTransaction();
251
252             modification.delete(LogicalDatastoreType.CONFIGURATION,groupInstanceId );
253
254             CheckedFuture<Void,TransactionCommitFailedException> submitFuture  = modification.submit();
255
256             Futures.addCallback(submitFuture, new FutureCallback<Void>() {
257                 @Override
258                 public void onSuccess(final Void result) {
259                     // Commited successfully
260                     s_logger.debug( "Install Group -- Committedsuccessfully ") ;
261                 }
262
263                 @Override
264                 public void onFailure(final Throwable t) {
265                     // Transaction failed
266                     if(t instanceof OptimisticLockFailedException) {
267                         // Failed because of concurrent transaction modifying same data
268                         s_logger.error( "Install Group -- Failed because of concurrent transaction modifying same data ") ;
269                     } else {
270                        // Some other type of TransactionCommitFailedException
271                         s_logger.error( "Install Group -- Some other type of TransactionCommitFailedException " + t) ;
272                     }
273                 }
274             });
275         } catch (Exception e) {
276             s_logger.error("Could not remove Group: {}", groupEntity, e);
277         }
278     }
279
280     public void modifyGroup(GroupEntity groupEntity) {
281
282         installGroup(groupEntity);
283     }
284
285     public void sendPacketOut(BigInteger dpnId, int groupId, byte[] payload) {
286
287         List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
288         actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
289
290         sendPacketOutWithActions(dpnId, groupId, payload, actionInfos);
291     }
292
293     public void sendPacketOutWithActions(BigInteger dpnId, long groupId, byte[] payload, List<ActionInfo> actionInfos) {
294
295         m_packetProcessingService.transmitPacket(MDSALUtil.getPacketOut(actionInfos, payload, dpnId,
296                 getNodeConnRef("openflow:" + dpnId, "0xfffffffd")));
297     }
298
299     public void sendARPPacketOutWithActions(BigInteger dpnId, byte[] payload, List<ActionInfo> actions) {
300         m_packetProcessingService.transmitPacket(MDSALUtil.getPacketOut(actions, payload, dpnId,
301                 getNodeConnRef("openflow:" + dpnId, "0xfffffffd")));
302     }
303
304     public InstanceIdentifier<Node> nodeToInstanceId(Node node) {
305         return InstanceIdentifier.builder(Nodes.class).child(Node.class, node.getKey()).toInstance();
306     }
307
308     private static NodeConnectorRef getNodeConnRef(final String nodeId, final String port) {
309         StringBuilder _stringBuilder = new StringBuilder(nodeId);
310         StringBuilder _append = _stringBuilder.append(":");
311         StringBuilder sBuild = _append.append(port);
312         String _string = sBuild.toString();
313         NodeConnectorId _nodeConnectorId = new NodeConnectorId(_string);
314         NodeConnectorKey _nodeConnectorKey = new NodeConnectorKey(_nodeConnectorId);
315         NodeConnectorKey nConKey = _nodeConnectorKey;
316         InstanceIdentifierBuilder<Nodes> _builder = InstanceIdentifier.<Nodes> builder(Nodes.class);
317         NodeId _nodeId = new NodeId(nodeId);
318         NodeKey _nodeKey = new NodeKey(_nodeId);
319         InstanceIdentifierBuilder<Node> _child = _builder.<Node, NodeKey> child(Node.class, _nodeKey);
320         InstanceIdentifierBuilder<NodeConnector> _child_1 = _child.<NodeConnector, NodeConnectorKey> child(
321                 NodeConnector.class, nConKey);
322         InstanceIdentifier<NodeConnector> path = _child_1.toInstance();
323         NodeConnectorRef _nodeConnectorRef = new NodeConnectorRef(path);
324         return _nodeConnectorRef;
325     }
326
327     private Node buildDpnNode(BigInteger dpnId) {
328         NodeId nodeId = new NodeId("openflow:" + dpnId);
329         Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
330
331         return nodeDpn;
332     }
333
334     public void syncSetUpFlow(FlowEntity flowEntity, long delay, boolean isRemove) {
335         s_logger.trace("syncSetUpFlow for flowEntity {} ", flowEntity);
336         if (flowEntity.getCookie() == null) {
337             flowEntity.setCookie(new BigInteger("0110000", 16));
338         }
339         Flow flow = flowEntity.getFlowBuilder().build();
340         String flowId = flowEntity.getFlowId();
341         BigInteger dpId = flowEntity.getDpnId();
342         short tableId = flowEntity.getTableId();
343         Match matches = flow.getMatch();
344         FlowKey flowKey = new FlowKey( new FlowId(flowId));
345         Node nodeDpn = buildDpnNode(dpId);
346         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
347                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
348                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
349         Runnable notifyTask = new NotifyTask();
350         FlowInfoKey flowInfoKey = new FlowInfoKey(dpId, tableId, matches, flowId);
351         synchronized (flowInfoKey.toString().intern()) {
352             flowMap.put(flowInfoKey, notifyTask);
353             if (isRemove) {
354                 MDSALUtil.syncDelete(m_dataBroker, LogicalDatastoreType.CONFIGURATION, flowInstanceId);
355             } else {
356                 MDSALUtil.syncWrite(m_dataBroker, LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow);
357             }
358             synchronized (notifyTask) {
359                 try {
360                     notifyTask.wait(delay);
361                 } catch (InterruptedException e){}
362             }
363         }
364     }
365
366     public void syncSetUpGroup(GroupEntity groupEntity, long delayTime, boolean isRemove) {
367         s_logger.trace("syncSetUpGroup for groupEntity {} ", groupEntity);
368         Group group = groupEntity.getGroupBuilder().build();
369         BigInteger dpId = groupEntity.getDpnId();
370         Node nodeDpn = buildDpnNode(dpId);
371         long groupId = groupEntity.getGroupId();
372         GroupKey groupKey = new GroupKey(new GroupId(groupId));
373         InstanceIdentifier<Group> groupInstanceId = InstanceIdentifier.builder(Nodes.class)
374                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
375                 .child(Group.class, groupKey).build();
376         Runnable notifyTask = new NotifyTask();
377         GroupInfoKey groupInfoKey = new GroupInfoKey(dpId, groupId);
378         synchronized (groupInfoKey.toString().intern()) {
379             s_logger.trace("syncsetupGroupKey groupKey {}", groupInfoKey);
380             groupMap.put(groupInfoKey, notifyTask);
381             if (isRemove) {
382                 MDSALUtil.syncDelete(m_dataBroker, LogicalDatastoreType.CONFIGURATION, groupInstanceId);
383             } else {
384                 MDSALUtil.syncWrite(m_dataBroker, LogicalDatastoreType.CONFIGURATION, groupInstanceId, group);
385             }
386             synchronized (notifyTask) {
387                 try {
388                     notifyTask.wait(delayTime);
389                 } catch (InterruptedException e){}
390             }
391         }
392     }
393
394 }