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