Merge "fix for indefinite wait on the resource lock"
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / InterfacemgrProvider.java
1 /*
2  * Copyright (c) 2016, 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.genius.interfacemanager;
9
10 import com.google.common.util.concurrent.CheckedFuture;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Optional;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import javax.annotation.PostConstruct;
23 import javax.annotation.PreDestroy;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
33 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
34 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
35 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
36 import org.opendaylight.genius.interfacemanager.exceptions.InterfaceAlreadyExistsException;
37 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
38 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo.InterfaceAdminState;
39 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
40 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.BatchingUtils;
41 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.IfmClusterUtils;
42 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.SouthboundUtils;
43 import org.opendaylight.genius.interfacemanager.rpcservice.InterfaceManagerRpcService;
44 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
45 import org.opendaylight.genius.interfacemanager.statusanddiag.InterfaceStatusMonitor;
46 import org.opendaylight.genius.mdsalutil.ActionInfo;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntry;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntry;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternalBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEndpointIpForDpnOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInputBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
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     private static final Logger LOG = LoggerFactory.getLogger(InterfacemgrProvider.class);
95     private static final InterfaceStatusMonitor INTERFACE_STATUS_MONITOR = InterfaceStatusMonitor.getInstance();
96     private final DataBroker dataBroker;
97     private final IdManagerService idManager;
98     private final InterfaceManagerRpcService interfaceManagerRpcService;
99     private final EntityOwnershipService entityOwnershipService;
100     private Map<String, OvsdbTerminationPointAugmentation> ifaceToTpMap;
101     private Map<String, InstanceIdentifier<Node>> ifaceToNodeIidMap;
102     private Map<InstanceIdentifier<Node>, OvsdbBridgeAugmentation> nodeIidToBridgeMap;
103
104     @Inject
105     public InterfacemgrProvider(final DataBroker dataBroker, final EntityOwnershipService entityOwnershipService,
106             final IdManagerService idManager, final InterfaceManagerRpcService interfaceManagerRpcService) {
107         this.dataBroker = dataBroker;
108         this.entityOwnershipService = entityOwnershipService;
109         this.idManager = idManager;
110         this.interfaceManagerRpcService = interfaceManagerRpcService;
111     }
112
113     @PostConstruct
114     @SuppressWarnings("checkstyle:IllegalCatch")
115     public void start() {
116         try {
117             INTERFACE_STATUS_MONITOR.registerMbean();
118             createIdPool();
119             IfmClusterUtils.registerEntityForOwnership(this, this.entityOwnershipService);
120             BatchingUtils.registerWithBatchManager(this.dataBroker);
121             this.ifaceToTpMap = new ConcurrentHashMap<>();
122             this.ifaceToNodeIidMap = new ConcurrentHashMap<>();
123             this.nodeIidToBridgeMap = new ConcurrentHashMap<>();
124
125             INTERFACE_STATUS_MONITOR.reportStatus("OPERATIONAL");
126         } catch (Exception e) {
127             INTERFACE_STATUS_MONITOR.reportStatus("ERROR");
128             throw e;
129         }
130         LOG.info("InterfacemgrProvider Started");
131     }
132
133     @Override
134     @PreDestroy
135     public void close() throws Exception {
136         LOG.info("InterfacemgrProvider Closed");
137     }
138
139     public EntityOwnershipService getEntityOwnershipService() {
140         return entityOwnershipService;
141     }
142
143     public DataBroker getDataBroker() {
144         return this.dataBroker;
145     }
146
147     private void createIdPool() {
148         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(IfmConstants.IFM_IDPOOL_NAME)
149                 .setLow(IfmConstants.IFM_ID_POOL_START).setHigh(IfmConstants.IFM_ID_POOL_END).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
195             .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
196                 .getInterfaceState(interfaceName, dataBroker);
197
198         if (ifState == null) {
199             LOG.error("Interface {} is not present", interfaceName);
200             return null;
201         }
202
203         Interface intf = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName),
204                 dataBroker);
205         if (intf == null) {
206             LOG.error("Interface {} doesn't exist in config datastore", interfaceName);
207             return null;
208         }
209
210         NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(intf.getName(), dataBroker);
211         InterfaceInfo.InterfaceType interfaceType = IfmUtil.getInterfaceType(intf);
212         InterfaceInfo interfaceInfo = new InterfaceInfo(interfaceName);
213         BigInteger dpId = org.opendaylight.genius.interfacemanager.globals.IfmConstants.INVALID_DPID;
214         Integer portNo = org.opendaylight.genius.interfacemanager.globals.IfmConstants.INVALID_PORT_NO;
215         if (ncId != null) {
216             dpId = IfmUtil.getDpnFromNodeConnectorId(ncId);
217             portNo = Integer.parseInt(IfmUtil.getPortNoFromNodeConnectorId(ncId));
218         }
219         if (interfaceType == InterfaceInfo.InterfaceType.VLAN_INTERFACE) {
220             interfaceInfo = IfmUtil.getVlanInterfaceInfo(interfaceName, intf, dpId);
221         } else if (interfaceType == InterfaceInfo.InterfaceType.UNKNOWN_INTERFACE) {
222             LOG.error("Type of Interface {} is unknown", interfaceName);
223             return null;
224         }
225         InterfaceInfo.InterfaceOpState opState;
226         if (ifState.getOperStatus() == OperStatus.Up) {
227             opState = InterfaceInfo.InterfaceOpState.UP;
228         } else if (ifState.getOperStatus() == OperStatus.Down) {
229             opState = InterfaceInfo.InterfaceOpState.DOWN;
230         } else {
231             opState = InterfaceInfo.InterfaceOpState.UNKNOWN;
232         }
233         interfaceInfo.setDpId(dpId);
234         interfaceInfo.setPortNo(portNo);
235         interfaceInfo.setAdminState(intf.isEnabled() ? InterfaceAdminState.ENABLED : InterfaceAdminState.DISABLED);
236         interfaceInfo.setInterfaceName(interfaceName);
237         Integer lportTag = ifState.getIfIndex();
238         interfaceInfo.setInterfaceTag(lportTag);
239         interfaceInfo.setInterfaceType(interfaceType);
240         interfaceInfo.setGroupId(IfmUtil.getGroupId(lportTag, interfaceType));
241         interfaceInfo.setOpState(opState);
242         PhysAddress phyAddress = ifState.getPhysAddress();
243         if (phyAddress != null) {
244             interfaceInfo.setMacAddress(ifState.getPhysAddress().getValue());
245         }
246
247         return interfaceInfo;
248
249     }
250
251     @Override
252     public InterfaceInfo getInterfaceInfoFromOperationalDataStore(String interfaceName,
253             InterfaceInfo.InterfaceType interfaceType) {
254         InterfaceInfo interfaceInfo = new InterfaceInfo(interfaceName);
255         org.opendaylight.yang.gen.v1.urn
256             .ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
257                 InterfaceManagerCommonUtils
258                 .getInterfaceState(interfaceName, dataBroker);
259         if (ifState == null) {
260             LOG.error("Interface {} is not present", interfaceName);
261             return null;
262         }
263         NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(ifState);
264         if (ncId != null) {
265             interfaceInfo.setDpId(IfmUtil.getDpnFromNodeConnectorId(ncId));
266             interfaceInfo.setPortNo(Integer.parseInt(IfmUtil.getPortNoFromNodeConnectorId(ncId)));
267         }
268         InterfaceInfo.InterfaceOpState opState;
269         if (ifState.getOperStatus() == OperStatus.Up) {
270             opState = InterfaceInfo.InterfaceOpState.UP;
271         } else if (ifState.getOperStatus() == OperStatus.Down) {
272             opState = InterfaceInfo.InterfaceOpState.DOWN;
273         } else {
274             opState = InterfaceInfo.InterfaceOpState.UNKNOWN;
275         }
276         interfaceInfo.setAdminState(ifState.getAdminStatus() == AdminStatus.Up ? InterfaceAdminState.ENABLED
277                 : InterfaceAdminState.DISABLED);
278         interfaceInfo.setInterfaceName(interfaceName);
279         Integer lportTag = ifState.getIfIndex();
280         interfaceInfo.setInterfaceTag(lportTag);
281         interfaceInfo.setInterfaceType(interfaceType);
282         interfaceInfo.setGroupId(IfmUtil.getGroupId(lportTag, interfaceType));
283         interfaceInfo.setOpState(opState);
284         PhysAddress phyAddress = ifState.getPhysAddress();
285         if (phyAddress != null) {
286             interfaceInfo.setMacAddress(ifState.getPhysAddress().getValue());
287         }
288         return interfaceInfo;
289     }
290
291     @Override
292     public InterfaceInfo getInterfaceInfoFromOperationalDataStore(String interfaceName) {
293         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
294             .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
295                 .getInterfaceState(interfaceName, dataBroker);
296         if (ifState == null) {
297             LOG.error("Interface {} is not present", interfaceName);
298             return null;
299         }
300
301         return populateInterfaceInfo(interfaceName, ifState);
302     }
303
304     public InterfaceInfo populateInterfaceInfo(String interfaceName,
305             org.opendaylight.yang.gen.v1.urn
306                 .ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
307         InterfaceInfo interfaceInfo = new InterfaceInfo(interfaceName);
308         NodeConnectorId ncId = IfmUtil.getNodeConnectorIdFromInterface(ifState);
309         if (ncId != null) {
310             if (Tunnel.class.equals(ifState.getType())) {
311                 interfaceInfo.setPortName(interfaceName);
312             } else {
313                 Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
314                 ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
315                 interfaceInfo.setPortName(parentRefs.getParentInterface());
316             }
317             interfaceInfo.setDpId(IfmUtil.getDpnFromNodeConnectorId(ncId));
318             interfaceInfo.setPortNo(Integer.parseInt(IfmUtil.getPortNoFromNodeConnectorId(ncId)));
319         }
320         InterfaceInfo.InterfaceOpState opState;
321         if (ifState.getOperStatus() == OperStatus.Up) {
322             opState = InterfaceInfo.InterfaceOpState.UP;
323         } else if (ifState.getOperStatus() == OperStatus.Down) {
324             opState = InterfaceInfo.InterfaceOpState.DOWN;
325         } else {
326             opState = InterfaceInfo.InterfaceOpState.UNKNOWN;
327         }
328         interfaceInfo.setAdminState(ifState.getAdminStatus() == AdminStatus.Up ? InterfaceAdminState.ENABLED
329                 : InterfaceAdminState.DISABLED);
330         interfaceInfo.setInterfaceName(interfaceName);
331         Integer lportTag = ifState.getIfIndex();
332         if (lportTag != null) {
333             interfaceInfo.setInterfaceTag(lportTag);
334         }
335         interfaceInfo.setOpState(opState);
336         PhysAddress phyAddress = ifState.getPhysAddress();
337         if (phyAddress != null) {
338             interfaceInfo.setMacAddress(ifState.getPhysAddress().getValue());
339         }
340         return interfaceInfo;
341     }
342
343     @Override
344     public InterfaceInfo getInterfaceInfoFromOperationalDSCache(String interfaceName) {
345         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
346             .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
347                 .getInterfaceStateFromCache(interfaceName);
348         if (ifState == null) {
349             LOG.warn("Interface {} is not present", interfaceName);
350             return null;
351         }
352         return populateInterfaceInfo(interfaceName, ifState);
353     }
354
355     @Override
356     public Interface getInterfaceInfoFromConfigDataStore(String interfaceName) {
357         Interface intf = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName),
358                 dataBroker);
359         return intf;
360     }
361
362     @Override
363     public void createVLANInterface(String interfaceName, String portName, BigInteger dpId, Integer vlanId,
364             String description, IfL2vlan.L2vlanMode l2vlanMode) throws InterfaceAlreadyExistsException {
365         createVLANInterface(interfaceName, portName, dpId, vlanId, description, l2vlanMode, false);
366     }
367
368     @Override
369     public void createVLANInterface(String interfaceName, String portName, BigInteger dpId, Integer vlanId,
370             String description, IfL2vlan.L2vlanMode l2vlanMode, boolean isExternal)
371             throws InterfaceAlreadyExistsException {
372
373         LOG.info("Create VLAN interface : {}", interfaceName);
374         Interface interfaceOptional = InterfaceManagerCommonUtils
375                 .getInterfaceFromConfigDS(new InterfaceKey(interfaceName), dataBroker);
376         if (interfaceOptional != null) {
377             LOG.debug("VLAN interface is already exist", interfaceOptional.getDescription());
378             throw new InterfaceAlreadyExistsException(interfaceOptional.getName());
379         }
380         IfL2vlanBuilder l2vlanBuilder = new IfL2vlanBuilder().setL2vlanMode(l2vlanMode);
381         if (vlanId != null && vlanId > 0) {
382             l2vlanBuilder.setVlanId(new VlanId(vlanId));
383         }
384         ParentRefs parentRefs = new ParentRefsBuilder().setParentInterface(portName).build();
385         InterfaceBuilder interfaceBuilder = new InterfaceBuilder().setEnabled(true).setName(interfaceName)
386                 .setType(L2vlan.class).addAugmentation(IfL2vlan.class, l2vlanBuilder.build())
387                 .addAugmentation(ParentRefs.class, parentRefs).setDescription(description);
388         if (isExternal) {
389             interfaceBuilder.addAugmentation(IfExternal.class, new IfExternalBuilder().setExternal(true).build());
390         }
391         InstanceIdentifier<Interface> interfaceInstanceIdentifier = InterfaceManagerCommonUtils
392                 .getInterfaceIdentifier(new InterfaceKey(interfaceName));
393         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
394         writeTransaction.put(LogicalDatastoreType.CONFIGURATION, interfaceInstanceIdentifier, interfaceBuilder.build(),
395                 true);
396         writeTransaction.submit();
397     }
398
399     private boolean isServiceBoundOnInterface(short servicePriority, String interfaceName,
400             Class<? extends ServiceModeBase> serviceMode) {
401         InstanceIdentifier<BoundServices> boundServicesIId = IfmUtil.buildBoundServicesIId(servicePriority,
402                 interfaceName, serviceMode);
403         try {
404             return SingleTransactionDataBroker
405                     .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, boundServicesIId).isPresent();
406         } catch (ReadFailedException e) {
407             LOG.warn("Error while reading [{}]", boundServicesIId, e);
408             return false;
409         }
410     }
411
412     @Override
413     public boolean isServiceBoundOnInterfaceForIngress(short servicePriority, String interfaceName) {
414         return isServiceBoundOnInterface(servicePriority, interfaceName, ServiceModeIngress.class);
415     }
416
417     @Override
418     public boolean isServiceBoundOnInterfaceForEgress(short servicePriority, String interfaceName) {
419         return isServiceBoundOnInterface(servicePriority, interfaceName, ServiceModeEgress.class);
420     }
421
422     @Override
423     public void bindService(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
424             BoundServices serviceInfo) {
425         bindService(interfaceName, serviceMode, serviceInfo, /* WriteTransaction */ null);
426     }
427
428     @Override
429     public void bindService(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
430             BoundServices serviceInfo, WriteTransaction tx) {
431         WriteTransaction writeTransaction = tx != null ? tx : dataBroker.newWriteOnlyTransaction();
432         IfmUtil.bindService(writeTransaction, interfaceName, serviceInfo, serviceMode);
433         if (tx == null) {
434             writeTransaction.submit();
435         }
436     }
437
438     @Override
439     public void unbindService(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
440             BoundServices serviceInfo) {
441         IfmUtil.unbindService(dataBroker, interfaceName,
442                 FlowBasedServicesUtils.buildServiceId(interfaceName, serviceInfo.getServicePriority(), serviceMode));
443     }
444
445     @Override
446     public BigInteger getDpnForInterface(Interface intrf) {
447         return getDpnForInterface(intrf.getName());
448     }
449
450     @Override
451     public BigInteger getDpnForInterface(String ifName) {
452         GetDpidFromInterfaceInput input = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
453         Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService.getDpidFromInterface(input);
454         try {
455             RpcResult<GetDpidFromInterfaceOutput> dpn = output.get();
456             if (dpn.isSuccessful()) {
457                 return dpn.getResult().getDpid();
458             }
459         } catch (NullPointerException | InterruptedException | ExecutionException e) {
460             LOG.warn("Exception when getting port for interface", e);
461         }
462         return null;
463     }
464
465     @Override
466     public String getEndpointIpForDpn(BigInteger dpnId) {
467         GetEndpointIpForDpnInput input = new GetEndpointIpForDpnInputBuilder().setDpid(dpnId).build();
468         Future<RpcResult<GetEndpointIpForDpnOutput>> output = interfaceManagerRpcService.getEndpointIpForDpn(input);
469         try {
470             RpcResult<GetEndpointIpForDpnOutput> ipForDpnOutputRpcResult = output.get();
471             if (ipForDpnOutputRpcResult.isSuccessful()) {
472                 List<IpAddress> localIps = ipForDpnOutputRpcResult.getResult().getLocalIps();
473                 if (!localIps.isEmpty()) {
474                     return localIps.get(0).getIpv4Address().getValue();
475                 }
476             }
477         } catch (NullPointerException | InterruptedException | ExecutionException e) {
478             LOG.warn("Exception when getting port for interface", e);
479         }
480         return null;
481     }
482
483     @Override
484     public List<ActionInfo> getInterfaceEgressActions(String ifName) {
485         return IfmUtil.getEgressActionInfosForInterface(ifName, 0, dataBroker, false);
486     }
487
488     @Override
489     public List<Interface> getVlanInterfaces() {
490         return InterfaceManagerCommonUtils.getAllVlanInterfacesFromCache();
491     }
492
493     @Override
494     public List<Interface> getVxlanInterfaces() {
495         return InterfaceManagerCommonUtils.getAllTunnelInterfacesFromCache();
496     }
497
498     @Override
499     public List<Interface> getChildInterfaces(String parentInterface) {
500         InterfaceParentEntry parentEntry = InterfaceMetaUtils.getInterfaceParentEntryFromConfigDS(parentInterface,
501                 dataBroker);
502         if (parentEntry == null) {
503             LOG.debug("No parent entry found for {}", parentInterface);
504             return Collections.emptyList();
505         }
506
507         List<InterfaceChildEntry> childEntries = parentEntry.getInterfaceChildEntry();
508         if (childEntries == null || childEntries.isEmpty()) {
509             LOG.debug("No child entries found for parent {}", parentInterface);
510             return Collections.emptyList();
511         }
512
513         List<Interface> childInterfaces = new ArrayList<>();
514         for (InterfaceChildEntry childEntry : childEntries) {
515             String interfaceName = childEntry.getChildInterface();
516             Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
517             if (iface != null) {
518                 childInterfaces.add(iface);
519             } else {
520                 LOG.debug("Child interface {} not found in config DS for parent interface {}", interfaceName,
521                         parentInterface);
522             }
523         }
524
525         LOG.trace("Found child interfaces {} for parent {}", childInterfaces, parentInterface);
526         return childInterfaces;
527     }
528
529     @Override
530     public boolean isExternalInterface(String interfaceName) {
531         return isExternalInterface(getInterfaceInfoFromConfigDataStore(interfaceName));
532     }
533
534     private boolean isExternalInterface(Interface iface) {
535         if (iface == null) {
536             return false;
537         }
538
539         IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
540         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
541     }
542
543     @Override
544     public String getPortNameForInterface(NodeConnectorId nodeConnectorId, String interfaceName) {
545         return InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId, interfaceName);
546     }
547
548     @Override
549     public String getPortNameForInterface(String dpnId, String interfaceName) {
550         return InterfaceManagerCommonUtils.getPortNameForInterface(dpnId, interfaceName);
551     }
552
553     @Override
554     public Map<String, OvsdbTerminationPointAugmentation> getTerminationPointCache() {
555         return new ConcurrentHashMap<>(this.ifaceToTpMap);
556     }
557
558     public void addTerminationPointForInterface(String interfaceName,
559             OvsdbTerminationPointAugmentation terminationPoint) {
560         LOG.debug("Adding TerminationPoint {} to cache for Interface {}", terminationPoint.getName(), interfaceName);
561         if (interfaceName != null && terminationPoint != null) {
562             ifaceToTpMap.put(interfaceName, terminationPoint);
563         }
564     }
565
566     public OvsdbTerminationPointAugmentation getTerminationPoint(String interfaceName) {
567         return ifaceToTpMap.get(interfaceName);
568     }
569
570     public void removeTerminationPointForInterface(String interfaceName) {
571         LOG.debug("Removing TerminationPoint from cache for Interface {}", interfaceName);
572         if (interfaceName != null) {
573             ifaceToTpMap.remove(interfaceName);
574         }
575     }
576
577     public void addNodeIidForInterface(String interfaceName, InstanceIdentifier<Node> nodeIid) {
578         if (interfaceName != null && nodeIid != null) {
579             ifaceToNodeIidMap.put(interfaceName, nodeIid);
580         }
581     }
582
583     public void removeNodeIidForInterface(String interfaceName) {
584         if (interfaceName != null) {
585             ifaceToNodeIidMap.remove(interfaceName);
586         }
587     }
588
589     public InstanceIdentifier<Node> getNodeIidForInterface(String interfaceName) {
590         if (interfaceName != null) {
591             return ifaceToNodeIidMap.get(interfaceName);
592         }
593         return null;
594     }
595
596     private OvsdbBridgeAugmentation getBridgeForInterface(String interfaceName,
597             InstanceIdentifier<Node> nodeInstanceId) {
598         InstanceIdentifier<Node> nodeIid = nodeInstanceId;
599         if (nodeIid == null) {
600             nodeIid = getNodeIidForInterface(interfaceName);
601         }
602         return getBridgeForNodeIid(nodeIid);
603     }
604
605     public String getDpidForInterface(String interfaceName) {
606         return getDpidForInterface(interfaceName, null);
607     }
608
609     public String getDpidForInterface(String interfaceName, InstanceIdentifier<Node> nodeInstanceId) {
610         OvsdbBridgeAugmentation bridge = getBridgeForInterface(interfaceName, nodeInstanceId);
611         if (bridge != null) {
612             BigInteger dpid = IfmUtil.getDpnId(bridge.getDatapathId());
613             if (dpid != null && dpid.longValue() != 0) {
614                 return String.valueOf(dpid);
615             }
616         }
617         return null;
618     }
619
620     public void addBridgeForNodeIid(InstanceIdentifier<Node> nodeIid, OvsdbBridgeAugmentation bridge) {
621         if (nodeIid != null && bridge != null) {
622             nodeIidToBridgeMap.put(nodeIid, bridge);
623         }
624     }
625
626     public void removeBridgeForNodeIid(InstanceIdentifier<Node> nodeIid) {
627         if (nodeIid != null) {
628             nodeIidToBridgeMap.remove(nodeIid);
629         }
630     }
631
632     public OvsdbBridgeAugmentation getBridgeForNodeIid(InstanceIdentifier<Node> nodeIid) {
633         if (nodeIid != null) {
634             return nodeIidToBridgeMap.get(nodeIid);
635         }
636         return null;
637     }
638
639     @Override
640     public String getParentRefNameForInterface(String interfaceName) {
641         String parentRefName = null;
642
643         String dpnId = getDpidForInterface(interfaceName, null);
644         OvsdbTerminationPointAugmentation ovsdbTp = getTerminationPoint(interfaceName);
645         if (ovsdbTp != null) {
646             if (dpnId == null) {
647                 LOG.error("Got NULL dpnId when looking for TP with external ID {}", interfaceName);
648                 return null;
649             }
650             parentRefName = getPortNameForInterface(dpnId, ovsdbTp.getName());
651             LOG.debug("Building parent ref for interface {}, using parentRefName {} acquired by external ID",
652                     interfaceName, parentRefName);
653         } else {
654             LOG.debug("Skipping parent ref for interface {}, as there is no termination point that references "
655                     + "this interface yet.", interfaceName);
656         }
657
658         return parentRefName;
659     }
660
661     @Override
662     public void updateInterfaceParentRef(String interfaceName, String parentInterface) {
663         // This should generally be called by EOS Owner for
664         // INTERFACE_CONFIG_ENTITY - runOnlyInLeaderNode()
665         updateInterfaceParentRef(interfaceName, parentInterface, true);
666     }
667
668     @Override
669     public void updateInterfaceParentRef(String interfaceName, String parentInterface,
670             boolean readInterfaceBeforeWrite) {
671         // This should generally be called by EOS Owner for
672         // INTERFACE_CONFIG_ENTITY - runOnlyInLeaderNode()
673         if (interfaceName == null) {
674             return;
675         }
676
677         DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
678         ParentRefUpdateWorker parentRefUpdateWorker = new ParentRefUpdateWorker(interfaceName, parentInterface,
679                 readInterfaceBeforeWrite);
680         jobCoordinator.enqueueJob(interfaceName, parentRefUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
681     }
682
683     public class ParentRefUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
684         String interfaceName;
685         String parentInterfaceName;
686         Boolean readInterfaceBeforeWrite;
687
688         public ParentRefUpdateWorker(String interfaceName, String parentInterfaceName,
689                 boolean readInterfaceBeforeWrite) {
690             this.interfaceName = interfaceName;
691             this.parentInterfaceName = parentInterfaceName;
692             this.readInterfaceBeforeWrite = readInterfaceBeforeWrite;
693         }
694
695         @Override
696         public List<ListenableFuture<Void>> call() throws Exception {
697             if (readInterfaceBeforeWrite) {
698                 Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName, dataBroker);
699                 if (iface == null) {
700                     LOG.debug("Interface doesn't exist in config DS - no need to update parentRef, skipping");
701                     return null;
702                 }
703             }
704             WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
705             IfmUtil.updateInterfaceParentRef(writeTransaction, interfaceName, parentInterfaceName);
706             CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTransaction.submit();
707             List<ListenableFuture<Void>> futures = new ArrayList<>();
708             futures.add(submitFuture);
709             return futures;
710         }
711     }
712
713     @Override
714     public OvsdbTerminationPointAugmentation getTerminationPointForInterface(String interfaceName) {
715         return getTerminationPoint(interfaceName);
716     }
717
718     @Override
719     public OvsdbBridgeAugmentation getOvsdbBridgeForInterface(String interfaceName) {
720         return getBridgeForInterface(interfaceName, null);
721     }
722
723     @Override
724     public OvsdbBridgeAugmentation getOvsdbBridgeForNodeIid(InstanceIdentifier<Node> nodeIid) {
725         return getBridgeForNodeIid(nodeIid);
726     }
727
728     @Override
729     /**
730      * Get all termination points on a given DPN.
731      * This API uses read on Operational DS. If there are perf issues in cluster
732      * setup, we can consider caching later.
733      *
734      * @param dpnId
735      *            Datapath Node Identifier
736      *
737      * @return If the data at the supplied path exists, returns a list of all termination point
738      *         Augmentations
739      */
740     public List<OvsdbTerminationPointAugmentation> getPortsOnBridge(BigInteger dpnId) {
741         List<OvsdbTerminationPointAugmentation> ports = new ArrayList<>();
742         List<TerminationPoint> portList = IfmUtil.getTerminationPointsOnBridge(dataBroker, dpnId);
743         for (TerminationPoint ovsPort : portList) {
744             if (ovsPort.getAugmentation(OvsdbTerminationPointAugmentation.class) != null) {
745                 ports.add(ovsPort.getAugmentation(OvsdbTerminationPointAugmentation.class));
746             }
747         }
748         LOG.debug("Found {} ports on bridge {}", ports.size(), dpnId);
749         return ports;
750     }
751
752     /**
753      * Get all termination points of type tunnel on a given DPN.
754      *
755      * @param dpnId
756      *            Datapath Node Identifier
757      *
758      * @return If the data at the supplied path exists, returns a list of all termination point
759      *         Augmentations of type tunnel
760      */
761     @Override
762     public List<OvsdbTerminationPointAugmentation> getTunnelPortsOnBridge(BigInteger dpnId) {
763         List<OvsdbTerminationPointAugmentation> tunnelPorts = new ArrayList<>();
764         List<TerminationPoint> portList = IfmUtil.getTerminationPointsOnBridge(dataBroker, dpnId);
765         for (TerminationPoint ovsPort : portList) {
766             OvsdbTerminationPointAugmentation portAug =
767                     ovsPort.getAugmentation(OvsdbTerminationPointAugmentation.class);
768             if (portAug != null && SouthboundUtils.isInterfaceTypeTunnel(portAug.getInterfaceType())) {
769                 tunnelPorts.add(portAug);
770             }
771         }
772
773         LOG.debug("Found {} tunnel ports on bridge {}", tunnelPorts.size(), dpnId);
774         return tunnelPorts;
775     }
776
777     /**
778      * Get all termination points by type on a given DPN.
779      *
780      * @param dpnId
781      *            Datapath Node Identifier
782      *
783      * @return If the data at the supplied path exists, returns a Map where key is interfaceType
784      *         and value is list of termination points of given type
785      */
786     @Override
787     public Map<Class<? extends InterfaceTypeBase>, List<OvsdbTerminationPointAugmentation>>
788         getPortsOnBridgeByType(BigInteger dpnId) {
789
790         Map<Class<? extends InterfaceTypeBase>, List<OvsdbTerminationPointAugmentation>> portMap;
791         portMap = new ConcurrentHashMap<>();
792         Optional<List<TerminationPoint>> portList =
793                 Optional.ofNullable(IfmUtil.getTerminationPointsOnBridge(dataBroker, dpnId));
794         portList.ifPresent(ovsPorts -> ovsPorts.parallelStream().forEach(ovsPort -> {
795             OvsdbTerminationPointAugmentation portAug =
796                             ovsPort.getAugmentation(OvsdbTerminationPointAugmentation.class);
797             if (portAug != null && portAug.getInterfaceType() != null) {
798                 if (portMap.get(portAug.getInterfaceType()) ==  null) {
799                     portMap.put(portAug.getInterfaceType(), new ArrayList<>());
800                 }
801                 portMap.get(portAug.getInterfaceType()).add(portAug);
802             }
803         }));
804
805         return portMap;
806     }
807
808     @Override
809     public long getLogicalTunnelSelectGroupId(int lportTag) {
810         return IfmUtil.getLogicalTunnelSelectGroupId(lportTag);
811     }
812
813 }