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