Introduced InterfaceManager in VPP renderer
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / iface / InterfaceManager.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.vpp.iface;
10
11 import javax.annotation.Nonnull;
12
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
15 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand;
16 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand;
17 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder;
18 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint.InterfaceTypeChoice;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCase;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.google.common.base.Optional;
31 import com.google.common.base.Preconditions;
32 import com.google.common.base.Strings;
33 import com.google.common.eventbus.Subscribe;
34 import com.google.common.util.concurrent.FutureCallback;
35 import com.google.common.util.concurrent.Futures;
36
37 public class InterfaceManager implements AutoCloseable {
38
39     private static final Logger LOG = LoggerFactory.getLogger(InterfaceManager.class);
40     private final MountedDataBrokerProvider mountDataProvider;
41     private final VppEndpointLocationProvider vppEndpointLocationProvider;
42
43     public InterfaceManager(@Nonnull MountedDataBrokerProvider mountDataProvider, @Nonnull DataBroker dataProvider) {
44         this.mountDataProvider = Preconditions.checkNotNull(mountDataProvider);
45         this.vppEndpointLocationProvider = new VppEndpointLocationProvider(dataProvider);
46     }
47
48     @Subscribe
49     public void vppEndpointChanged(VppEndpointConfEvent event) {
50         switch (event.getDtoModificationType()) {
51             case CREATED:
52                 vppEndpointCreated(event.getAfter().get());
53                 break;
54             case UPDATED:
55                 vppEndpointDeleted(event.getBefore().get());
56                 vppEndpointCreated(event.getAfter().get());
57                 break;
58             case DELETED:
59                 vppEndpointDeleted(event.getBefore().get());
60                 break;
61         }
62     }
63
64     private void vppEndpointCreated(VppEndpoint vppEndpoint) {
65         Optional<ConfigCommand> potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.PUT);
66         if (!potentialIfaceCommand.isPresent()) {
67             return;
68         }
69         ConfigCommand ifaceWithoutBdCommand = potentialIfaceCommand.get();
70         InstanceIdentifier<?> vppNodeIid = vppEndpoint.getVppNodePath();
71         Optional<DataBroker> potentialVppDataProvider = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
72         if (!potentialVppDataProvider.isPresent()) {
73             LOG.debug("Cannot get data broker for mount point {}", vppNodeIid);
74             return;
75         }
76         DataBroker vppDataBroker = potentialVppDataProvider.get();
77         createIfaceOnVpp(ifaceWithoutBdCommand, vppDataBroker, vppEndpoint, vppNodeIid);
78     }
79
80     private void createIfaceOnVpp(ConfigCommand createIfaceWithoutBdCommand, DataBroker vppDataBroker,
81             VppEndpoint vppEndpoint, InstanceIdentifier<?> vppNodeIid) {
82         ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction();
83         createIfaceWithoutBdCommand.execute(rwTx);
84         Futures.addCallback(rwTx.submit(), new FutureCallback<Void>() {
85
86             @Override
87             public void onSuccess(Void result) {
88                 LOG.debug("Create interface on VPP command was successful:\nVPP: {}\nCommand: {}", vppNodeIid,
89                         createIfaceWithoutBdCommand);
90                 vppEndpointLocationProvider.createLocationForVppEndpoint(vppEndpoint);
91             }
92
93             @Override
94             public void onFailure(Throwable t) {
95                 LOG.error("Create interface on VPP command was NOT successful:\nVPP: {}\nCommand: {}", vppNodeIid,
96                         createIfaceWithoutBdCommand, t);
97             }
98         });
99     }
100
101     private void vppEndpointDeleted(VppEndpoint vppEndpoint) {
102         Optional<ConfigCommand> potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.DELETE);
103         if (!potentialIfaceCommand.isPresent()) {
104             return;
105         }
106         ConfigCommand ifaceWithoutBdCommand = potentialIfaceCommand.get();
107         InstanceIdentifier<?> vppNodeIid = vppEndpoint.getVppNodePath();
108         Optional<DataBroker> potentialVppDataProvider = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
109         if (!potentialVppDataProvider.isPresent()) {
110             LOG.debug("Cannot get data broker for mount point {}", vppNodeIid);
111             return;
112         }
113         DataBroker vppDataBroker = potentialVppDataProvider.get();
114         deleteIfaceOnVpp(ifaceWithoutBdCommand, vppDataBroker, vppEndpoint, vppNodeIid);
115     }
116
117     private void deleteIfaceOnVpp(ConfigCommand deleteIfaceWithoutBdCommand, DataBroker vppDataBroker,
118             VppEndpoint vppEndpoint, InstanceIdentifier<?> vppNodeIid) {
119         ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction();
120         deleteIfaceWithoutBdCommand.execute(rwTx);
121         Futures.addCallback(rwTx.submit(), new FutureCallback<Void>() {
122
123             @Override
124             public void onSuccess(Void result) {
125                 LOG.debug("Delete interface on VPP command was successful:\nVPP: {}\nCommand: {}", vppNodeIid,
126                         deleteIfaceWithoutBdCommand);
127                 vppEndpointLocationProvider.deleteLocationForVppEndpoint(vppEndpoint);
128             }
129
130             @Override
131             public void onFailure(Throwable t) {
132                 LOG.error("Delete interface on VPP command was NOT successful:\nVPP: {}\nCommand: {}", vppNodeIid,
133                         deleteIfaceWithoutBdCommand, t);
134             }
135         });
136     }
137
138     @Subscribe
139     public void vppNodeChanged(NodeOperEvent event) {
140         switch (event.getDtoModificationType()) {
141             case CREATED:
142                 if (event.isAfterConnected()) {
143                     // TODO read VppEndpoints or cache them during vppEndpointChanged()
144                 }
145                 break;
146             case UPDATED:
147                 if (!event.isBeforeConnected() && event.isAfterConnected()) {
148                     // TODO reconciliation - diff between disconnected snapshot and current snapshot
149                 }
150                 break;
151             case DELETED:
152                 if (event.isBeforeConnected()) {
153                     // TODO we could do snapshot of VppEndpoints 
154                     // which can be used for reconciliation
155                 }
156                 break;
157         }
158     }
159
160     private static Optional<ConfigCommand> createInterfaceWithoutBdCommand(@Nonnull VppEndpoint vppEp,
161             @Nonnull Operations operations) {
162         if (!hasNodeAndInterface(vppEp)) {
163             LOG.debug("Interface command is not created for {}", vppEp);
164             return Optional.absent();
165         }
166         VhostUserCommandBuilder builder = VhostUserCommand.builder();
167         builder.setName(vppEp.getVppInterfaceName());
168         InterfaceTypeChoice interfaceTypeChoice = vppEp.getInterfaceTypeChoice();
169         if (interfaceTypeChoice instanceof VhostUserCase) {
170             VhostUserCase vhostUserIface = (VhostUserCase) interfaceTypeChoice;
171             String socket = vhostUserIface.getSocket();
172             if (Strings.isNullOrEmpty(socket)) {
173                 LOG.debug("Vhost user interface command is not created because socket is missing. {}", vppEp);
174                 return Optional.absent();
175             }
176             builder.setSocket(socket);
177             builder.setRole(VhostUserRole.Client);
178         }
179         VhostUserCommand vhostUserCommand =
180                 builder.setOperation(operations).setDescription(vppEp.getDescription()).build();
181         return Optional.of(vhostUserCommand);
182     }
183
184     private static boolean hasNodeAndInterface(VppEndpoint vppEp) {
185         if (vppEp.getVppNodePath() == null) {
186             LOG.trace("vpp-node is missing. {}", vppEp);
187             return false;
188         }
189         if (Strings.isNullOrEmpty(vppEp.getVppInterfaceName())) {
190             LOG.trace("vpp-interface-name is missing. {}", vppEp);
191             return false;
192         }
193         return true;
194     }
195
196     @Override
197     public void close() throws Exception {
198         vppEndpointLocationProvider.close();
199     }
200
201 }