Handling RACE conditions in bind/unbind service
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / InterfacemgrProvider.java
1 /*
2  * Copyright (c) 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 package org.opendaylight.genius.interfacemanager;
9
10
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.ListenableFuture;
13
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.Callable;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
31 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
32 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
33 import org.opendaylight.genius.interfacemanager.exceptions.InterfaceAlreadyExistsException;
34 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
35 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo.InterfaceAdminState;
36 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
37 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.BatchingUtils;
38 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.IfmClusterUtils;
39 import org.opendaylight.genius.interfacemanager.rpcservice.InterfaceManagerRpcService;
40 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
41 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils.ServiceMode;
42 import org.opendaylight.genius.interfacemanager.statusanddiag.InterfaceStatusMonitor;
43 import org.opendaylight.genius.mdsalutil.ActionInfo;
44 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
45 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternalBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceOutput;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
86 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
87 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
88 import org.opendaylight.yangtools.yang.common.RpcResult;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91
92 @Singleton
93 public class InterfacemgrProvider implements AutoCloseable, IInterfaceManager {
94
95     private static final Logger LOG = LoggerFactory.getLogger(InterfacemgrProvider.class);
96     private static final InterfaceStatusMonitor interfaceStatusMonitor = InterfaceStatusMonitor.getInstance();
97     private final DataBroker dataBroker;
98     private final IdManagerService idManager;
99     private final InterfaceManagerRpcService interfaceManagerRpcService;
100     private final EntityOwnershipService entityOwnershipService;
101     private final MdsalUtils mdsalUtils;
102     private final SouthboundUtils southboundUtils;
103
104     @Inject
105     public InterfacemgrProvider(final DataBroker dataBroker, final EntityOwnershipService entityOwnershipService,
106                                 final IdManagerService idManager,
107                                 final InterfaceManagerRpcService interfaceManagerRpcService){
108         this.dataBroker = dataBroker;
109         this.entityOwnershipService = entityOwnershipService;
110         this.idManager = idManager;
111         this.interfaceManagerRpcService = interfaceManagerRpcService;
112         this.mdsalUtils = new MdsalUtils(dataBroker);
113         this.southboundUtils = new SouthboundUtils(mdsalUtils);
114     }
115
116     @PostConstruct
117     public void start() throws Exception {
118         try {
119             createIdPool();
120             IfmClusterUtils.registerEntityForOwnership(this, this.entityOwnershipService);
121             BatchingUtils.registerWithBatchManager( this.dataBroker);
122             interfaceStatusMonitor.reportStatus("OPERATIONAL");
123         } catch (Exception e) {
124             interfaceStatusMonitor.reportStatus("ERROR");
125             throw e;
126         }
127         LOG.info("InterfacemgrProvider Started");
128     }
129
130     @Override
131     @PreDestroy
132     public void close() throws Exception {
133         LOG.info("InterfacemgrProvider Closed");
134     }
135
136     public EntityOwnershipService getEntityOwnershipService() {
137         return entityOwnershipService;
138     }
139
140     public DataBroker getDataBroker(){
141         return this.dataBroker;
142     }
143
144     private void createIdPool() {
145         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
146                 .setPoolName(IfmConstants.IFM_IDPOOL_NAME)
147                 .setLow(IfmConstants.IFM_ID_POOL_START)
148                 .setHigh(IfmConstants.IFM_ID_POOL_END)
149                 .build();
150         //TODO: Error handling
151         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
152         try {
153             if (result != null && result.get().isSuccessful()) {
154                 LOG.debug("Created IdPool for InterfaceMgr");
155             }
156         } catch (InterruptedException | ExecutionException e) {
157             LOG.error("Failed to create idPool for InterfaceMgr", e);
158         }
159     }
160
161     @Override
162     public Long getPortForInterface(String ifName) {
163         GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(ifName).build();
164         Future<RpcResult<GetPortFromInterfaceOutput>> output = interfaceManagerRpcService.getPortFromInterface(input);
165         try {
166             RpcResult<GetPortFromInterfaceOutput> port = output.get();
167             if (port.isSuccessful()) {
168                 return port.getResult().getPortno();
169             }
170         } catch (NullPointerException | InterruptedException | ExecutionException e) {
171             LOG.warn("Exception when getting port for interface", e);
172         }
173         return null;
174     }
175
176     @Override
177     public Long getPortForInterface(Interface intf) {
178         GetPortFromInterfaceInput input = new GetPortFromInterfaceInputBuilder().setIntfName(intf.getName()).build();
179         Future<RpcResult<GetPortFromInterfaceOutput>> output = interfaceManagerRpcService.getPortFromInterface(input);
180         try {
181             RpcResult<GetPortFromInterfaceOutput> port = output.get();
182             if (port.isSuccessful()) {
183                 return port.getResult().getPortno();
184             }
185         } catch (NullPointerException | InterruptedException | ExecutionException e) {
186             LOG.warn("Exception when getting port for interface", e);
187         }
188         return null;
189     }
190
191     @Override
192     public InterfaceInfo getInterfaceInfo(String interfaceName) {
193
194         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
195                 ifState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
196
197         if (ifState == null) {
198             LOG.error("Interface {} is not present", interfaceName);
199             return null;
200         }
201
202         Integer lportTag = ifState.getIfIndex();
203         Interface intf = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName), dataBroker);
204         if (intf == null) {
205             LOG.error("Interface {} doesn't exist in config datastore", interfaceName);
206             return null;
207         }
208
209         NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(intf.getName(), dataBroker);
210         InterfaceInfo.InterfaceType interfaceType = IfmUtil.getInterfaceType(intf);
211         InterfaceInfo interfaceInfo = new InterfaceInfo(interfaceName);
212         BigInteger dpId = org.opendaylight.genius.interfacemanager.globals.IfmConstants.INVALID_DPID;
213         Integer portNo = org.opendaylight.genius.interfacemanager.globals.IfmConstants.INVALID_PORT_NO;
214         if (ncId != null) {
215             dpId = IfmUtil.getDpnFromNodeConnectorId(ncId);
216             portNo = Integer.parseInt(IfmUtil.getPortNoFromNodeConnectorId(ncId));
217         }
218         if (interfaceType == InterfaceInfo.InterfaceType.VLAN_INTERFACE) {
219             interfaceInfo = IfmUtil.getVlanInterfaceInfo(interfaceName, intf, dpId);
220         } else if (interfaceType == InterfaceInfo.InterfaceType.VXLAN_TRUNK_INTERFACE ||
221                 interfaceType == InterfaceInfo.InterfaceType.GRE_TRUNK_INTERFACE) {
222             // TODO : since there is no logical grouping for tunnel interfaces, there is no need
223             // for this code as of now. will be revisited once the support comes
224
225         } else {
226             LOG.error("Type of Interface {} is unknown", interfaceName);
227             return null;
228         }
229         InterfaceInfo.InterfaceOpState opState ;
230         if(ifState.getOperStatus() == OperStatus.Up)
231         {
232             opState = InterfaceInfo.InterfaceOpState.UP;
233         }
234         else if (ifState.getOperStatus() == OperStatus.Down)
235         {
236             opState = InterfaceInfo.InterfaceOpState.DOWN;
237         }
238         else
239         {
240             opState = InterfaceInfo.InterfaceOpState.UNKNOWN;
241         }
242         interfaceInfo.setDpId(dpId);
243         interfaceInfo.setPortNo(portNo);
244         interfaceInfo.setAdminState(intf.isEnabled() ? InterfaceAdminState.ENABLED : InterfaceAdminState.DISABLED);
245         interfaceInfo.setInterfaceName(interfaceName);
246         interfaceInfo.setInterfaceTag(lportTag);
247         interfaceInfo.setInterfaceType(interfaceType);
248         interfaceInfo.setGroupId(IfmUtil.getGroupId(lportTag, interfaceType));
249         interfaceInfo.setOpState(opState);
250         PhysAddress phyAddress = ifState.getPhysAddress();
251         if (phyAddress != null) {
252             interfaceInfo.setMacAddress(ifState.getPhysAddress().getValue());
253         }
254
255         return interfaceInfo;
256
257     }
258
259     @Override
260     public InterfaceInfo getInterfaceInfoFromOperationalDataStore(String interfaceName, InterfaceInfo.InterfaceType interfaceType) {
261         InterfaceInfo interfaceInfo = new InterfaceInfo(interfaceName);
262         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
263                 .getInterfaceStateFromOperDS(interfaceName, dataBroker);
264         if (ifState == null) {
265             LOG.error("Interface {} is not present", interfaceName);
266             return null;
267         }
268         Integer lportTag = ifState.getIfIndex();
269         NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(ifState);
270         if (ncId != null) {
271             interfaceInfo.setDpId(IfmUtil.getDpnFromNodeConnectorId(ncId));
272             interfaceInfo.setPortNo(Integer.parseInt(IfmUtil.getPortNoFromNodeConnectorId(ncId)));
273         }
274         InterfaceInfo.InterfaceOpState opState ;
275         if(ifState.getOperStatus() == OperStatus.Up)
276         {
277             opState = InterfaceInfo.InterfaceOpState.UP;
278         }
279         else if (ifState.getOperStatus() == OperStatus.Down)
280         {
281             opState = InterfaceInfo.InterfaceOpState.DOWN;
282         }
283         else
284         {
285             opState = InterfaceInfo.InterfaceOpState.UNKNOWN;
286         }
287         interfaceInfo.setAdminState(ifState.getAdminStatus() == AdminStatus.Up ? InterfaceAdminState.ENABLED : InterfaceAdminState.DISABLED);
288         interfaceInfo.setInterfaceName(interfaceName);
289         interfaceInfo.setInterfaceTag(lportTag);
290         interfaceInfo.setInterfaceType(interfaceType);
291         interfaceInfo.setGroupId(IfmUtil.getGroupId(lportTag, interfaceType));
292         interfaceInfo.setOpState(opState);
293         PhysAddress phyAddress = ifState.getPhysAddress();
294         if (phyAddress != null) {
295             interfaceInfo.setMacAddress(ifState.getPhysAddress().getValue());
296         }
297
298         return interfaceInfo;
299     }
300
301     @Override
302     public InterfaceInfo getInterfaceInfoFromOperationalDataStore(String interfaceName) {
303         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
304             ifState = InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
305         if (ifState == null) {
306             LOG.error("Interface {} is not present", interfaceName);
307             return null;
308         }
309
310         return populateInterfaceInfo(interfaceName, ifState);
311     }
312
313
314     public InterfaceInfo populateInterfaceInfo(String interfaceName, org.opendaylight.yang.gen.v1.urn.ietf.params.xml
315         .ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
316         Integer lportTag = ifState.getIfIndex();
317         InterfaceInfo interfaceInfo = new InterfaceInfo(interfaceName);
318         NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(ifState);
319         if (ncId != null) {
320             if (Tunnel.class.equals(ifState.getType())) {
321                 interfaceInfo.setPortName(interfaceName);
322             } else {
323                 Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
324                 ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
325                 interfaceInfo.setPortName(parentRefs.getParentInterface());
326             }
327             interfaceInfo.setDpId(IfmUtil.getDpnFromNodeConnectorId(ncId));
328             interfaceInfo.setPortNo(Integer.parseInt(IfmUtil.getPortNoFromNodeConnectorId(ncId)));
329         }
330         InterfaceInfo.InterfaceOpState opState ;
331         if (ifState.getOperStatus() == OperStatus.Up) {
332             opState = InterfaceInfo.InterfaceOpState.UP;
333         } else if (ifState.getOperStatus() == OperStatus.Down) {
334             opState = InterfaceInfo.InterfaceOpState.DOWN;
335         } else {
336             opState = InterfaceInfo.InterfaceOpState.UNKNOWN;
337         }
338         interfaceInfo.setAdminState((ifState.getAdminStatus() == AdminStatus.Up) ? InterfaceAdminState.ENABLED
339             : InterfaceAdminState.DISABLED);
340         interfaceInfo.setInterfaceName(interfaceName);
341         if (lportTag != null) {
342             interfaceInfo.setInterfaceTag(lportTag);
343         }
344         interfaceInfo.setOpState(opState);
345         PhysAddress phyAddress = ifState.getPhysAddress();
346         if (phyAddress != null) {
347             interfaceInfo.setMacAddress(ifState.getPhysAddress().getValue());
348         }
349         return interfaceInfo;
350     }
351
352
353     @Override
354     public InterfaceInfo getInterfaceInfoFromOperationalDSCache(String interfaceName) {
355         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
356             ifState = InterfaceManagerCommonUtils.getInterfaceStateFromCache(interfaceName);
357         if (ifState == null) {
358             LOG.warn("Interface {} is not present", interfaceName);
359             return null;
360         }
361         return populateInterfaceInfo(interfaceName, ifState);
362     }
363
364     @Override
365     public Interface getInterfaceInfoFromConfigDataStore(String interfaceName) {
366         Interface intf = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName), dataBroker);
367         return intf;
368     }
369
370     @Override
371     public void createVLANInterface(String interfaceName, String portName, BigInteger dpId, Integer vlanId,
372                                     String description, IfL2vlan.L2vlanMode l2vlanMode) throws InterfaceAlreadyExistsException {
373         createVLANInterface(interfaceName, portName, dpId, vlanId, description, l2vlanMode, false);
374     }
375     @Override
376     public void createVLANInterface(String interfaceName, String portName, BigInteger dpId, Integer vlanId,
377                                     String description, IfL2vlan.L2vlanMode l2vlanMode, boolean isExternal) throws InterfaceAlreadyExistsException {
378
379         LOG.info("Create VLAN interface : {}", interfaceName);
380         InstanceIdentifier<Interface> interfaceInstanceIdentifier = InterfaceManagerCommonUtils.getInterfaceIdentifier(new InterfaceKey(interfaceName));
381         Interface interfaceOptional = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName), dataBroker);
382         if (interfaceOptional != null) {
383             LOG.debug("VLAN interface is already exist", interfaceOptional.getDescription());
384             throw new InterfaceAlreadyExistsException(interfaceOptional.getName());
385         }
386         IfL2vlanBuilder l2vlanBuilder = new IfL2vlanBuilder().setL2vlanMode(l2vlanMode);
387         if (vlanId != null && vlanId > 0) {
388             l2vlanBuilder.setVlanId(new VlanId(vlanId));
389         }
390         ParentRefs parentRefs = new ParentRefsBuilder().setParentInterface(portName).build();
391         InterfaceBuilder interfaceBuilder = new InterfaceBuilder().setEnabled(true).setName(interfaceName).setType(L2vlan.class).
392                 addAugmentation(IfL2vlan.class, l2vlanBuilder.build()).addAugmentation(ParentRefs.class, parentRefs).
393                 setDescription(description);
394         if (isExternal) {
395             interfaceBuilder.addAugmentation(IfExternal.class, new IfExternalBuilder().setExternal(true).build());
396         }
397         WriteTransaction t = dataBroker.newWriteOnlyTransaction();
398         t.put(LogicalDatastoreType.CONFIGURATION, interfaceInstanceIdentifier, interfaceBuilder.build(), true);
399         t.submit();
400     }
401
402     private boolean isServiceBoundOnInterface(short servicePriority, String interfaceName,
403                                               Class<? extends ServiceModeBase> serviceMode) {
404         InstanceIdentifier<BoundServices> boundServicesIId =
405             IfmUtil.buildBoundServicesIId(servicePriority, interfaceName, serviceMode);
406         try {
407             return SingleTransactionDataBroker.syncReadOptional(dataBroker,
408                                                                 LogicalDatastoreType.CONFIGURATION, boundServicesIId)
409                                               .isPresent();
410         } catch (ReadFailedException e) {
411             LOG.warn("Error while reading [{}]", boundServicesIId, e);
412             return false;
413         }
414     }
415
416     @Override
417     public boolean isServiceBoundOnInterfaceForIngress(short servicePriority, String interfaceName) {
418         return isServiceBoundOnInterface(servicePriority, interfaceName, ServiceModeIngress.class);
419     }
420
421     @Override
422     public boolean isServiceBoundOnInterfaceForEgress(short servicePriority, String interfaceName) {
423         return isServiceBoundOnInterface(servicePriority, interfaceName, ServiceModeEgress.class);
424     }
425
426     @Override
427     public void bindService(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
428                             BoundServices serviceInfo) {
429         bindService(interfaceName, serviceMode, serviceInfo, /*WriteTransaction*/ null);
430     }
431
432     @Override
433     public void bindService(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
434                             BoundServices serviceInfo, WriteTransaction tx) {
435         WriteTransaction t = (tx != null) ? tx : dataBroker.newWriteOnlyTransaction();
436         IfmUtil.bindService(t, interfaceName, serviceInfo, serviceMode);
437         if (tx == null) {
438             t.submit();
439         }
440     }
441
442     @Override
443     public void unbindService(String interfaceName, Class<? extends ServiceModeBase> serviceMode, BoundServices serviceInfo) {
444         IfmUtil.unbindService(dataBroker, interfaceName,
445                 FlowBasedServicesUtils.buildServiceId(interfaceName, serviceInfo.getServicePriority(), serviceMode));
446     }
447
448     @Override
449     public BigInteger getDpnForInterface(String ifName) {
450         GetDpidFromInterfaceInput input = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
451         Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService.getDpidFromInterface(input);
452         try {
453             RpcResult<GetDpidFromInterfaceOutput> dpn = output.get();
454             if (dpn.isSuccessful()) {
455                 return dpn.getResult().getDpid();
456             }
457         } catch (NullPointerException | InterruptedException | ExecutionException e) {
458             LOG.warn("Exception when getting port for interface", e);
459         }
460         return null;
461     }
462
463     @Override
464     public String getEndpointIpForDpn(BigInteger dpnId) {
465         GetEndpointIpForDpnInput input = new GetEndpointIpForDpnInputBuilder().setDpid(dpnId).build();
466         Future<RpcResult<GetEndpointIpForDpnOutput>> output = interfaceManagerRpcService.getEndpointIpForDpn(input);
467         try {
468             RpcResult<GetEndpointIpForDpnOutput> ipForDpnOutputRpcResult = output.get();
469             if (ipForDpnOutputRpcResult.isSuccessful()) {
470                 List<IpAddress> localIps = ipForDpnOutputRpcResult.getResult().getLocalIps();
471                 if (!localIps.isEmpty()) {
472                     return localIps.get(0).getIpv4Address().getValue();
473                 }
474             }
475         } catch (NullPointerException | InterruptedException | ExecutionException e) {
476             LOG.warn("Exception when getting port for interface", e);
477         }
478         return null;
479     }
480
481     @Override
482     public List<ActionInfo> getInterfaceEgressActions(String ifName) {
483         return IfmUtil.getEgressActionInfosForInterface(ifName, 0, dataBroker, false);
484     }
485
486     @Override
487     public BigInteger getDpnForInterface(Interface intrf) {
488         return getDpnForInterface(intrf.getName());
489     }
490
491     @Override
492     public List<Interface> getVlanInterfaces() {
493         return InterfaceManagerCommonUtils.getAllVlanInterfacesFromCache();
494     }
495
496     @Override
497     public List<Interface> getVxlanInterfaces() {
498         return InterfaceManagerCommonUtils.getAllTunnelInterfacesFromCache();
499     }
500
501     @Override
502     public boolean isExternalInterface(String interfaceName) {
503         return isExternalInterface(getInterfaceInfoFromConfigDataStore(interfaceName));
504     }
505
506     private boolean isExternalInterface(Interface iface) {
507         if (iface == null) {
508             return false;
509         }
510
511         IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
512         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
513     }
514
515     @Override
516     public String getPortNameForInterface(NodeConnectorId nodeConnectorId, String interfaceName) {
517         return InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId, interfaceName);
518     }
519
520     @Override
521     public String getPortNameForInterface(String dpnId, String interfaceName) {
522         return InterfaceManagerCommonUtils.getPortNameForInterface(dpnId, interfaceName);
523     }
524
525     @Override
526     public String getParentRefNameForInterface(String interfaceName) {
527         String parentRefName = null;
528
529         // FIXME Note this utility isn't very good for scale/performance as it traverses all nodes,
530         // probably need to use a cache instead of these (iface_name->dpnId+tpName).
531         Node node = southboundUtils.getNodeByTerminationPointExternalId(interfaceName);
532         if (node != null) {
533             String dpnId = southboundUtils.getDataPathIdStr(node);
534             if (dpnId == null) {
535                 LOG.error("Got node {} when looking for TP with external ID {}, "
536                         + "but unexpectedly got NULL dpnId for this node", node, interfaceName);
537                 return null;
538             }
539             TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(node, interfaceName);
540             if (tp == null) {
541                 LOG.error("Got node {} when looking for TP with external ID {}, "
542                         + "but unexpectedly got a NULL TP from this node", node, interfaceName);
543                 return null;
544             }
545             OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
546             parentRefName = getPortNameForInterface(dpnId, ovsdbTp.getName());
547             LOG.debug("Building parent ref for neutron port {}, using parentRefName {} acquired by external ID",
548                     interfaceName, parentRefName);
549         } else {
550             LOG.debug("Skipping parent ref for neutron port {}, as there is no termination point that references "
551                     + "this neutron port yet.", interfaceName);
552         }
553
554         return parentRefName;
555     }
556
557     @Override
558     public void updateInterfaceParentRef(String interfaceName, String parentInterface) {
559         // This should generally be called by EOS Owner for INTERFACE_CONFIG_ENTITY - runOnlyInLeaderNode()
560         updateInterfaceParentRef(interfaceName, parentInterface, true);
561     }
562
563     @Override
564     public void updateInterfaceParentRef(String interfaceName, String parentInterface, boolean readInterfaceBeforeWrite) {
565         // This should generally be called by EOS Owner for INTERFACE_CONFIG_ENTITY - runOnlyInLeaderNode()
566         if (interfaceName == null) {
567             return;
568         }
569
570         DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
571         ParentRefUpdateWorker parentRefUpdateWorker =
572                 new ParentRefUpdateWorker(interfaceName, parentInterface, readInterfaceBeforeWrite);
573         jobCoordinator.enqueueJob(interfaceName, parentRefUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
574     }
575
576     public class ParentRefUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
577         String interfaceName;
578         String parentInterfaceName;
579         Boolean readInterfaceBeforeWrite;
580
581         public ParentRefUpdateWorker(String interfaceName, String parentInterfaceName, boolean readInterfaceBeforeWrite) {
582             this.interfaceName = interfaceName;
583             this.parentInterfaceName = parentInterfaceName;
584             this.readInterfaceBeforeWrite = readInterfaceBeforeWrite;
585         }
586
587         @Override
588         public List<ListenableFuture<Void>> call() throws Exception {
589             if (readInterfaceBeforeWrite) {
590                 Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
591                 if (iface == null) {
592                     LOG.debug("Interface doesn't exist in config DS - no need to update parentRef, skipping");
593                     return null;
594                 }
595             }
596             WriteTransaction t = dataBroker.newWriteOnlyTransaction();
597             IfmUtil.updateInterfaceParentRef(t, interfaceName, parentInterfaceName);
598             CheckedFuture<Void, TransactionCommitFailedException> submitFuture = t.submit();
599             List<ListenableFuture<Void>> futures = new ArrayList<>();
600             futures.add(submitFuture);
601             return futures;
602         }
603     }
604
605 }