Add INFO.yaml for GBP
[groupbasedpolicy.git] / neutron-vpp-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / vpp / mapper / processors / PortHandler.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.processors;
10
11 import java.util.Collections;
12 import java.util.List;
13
14 import javax.annotation.Nonnull;
15 import javax.annotation.Nullable;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
23 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
25 import org.opendaylight.groupbasedpolicy.util.SyncedChain;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.Mappings;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.GbpByNeutronMappings;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.BaseEndpointsByPorts;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPortKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.ExcludeFromPolicy;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.ExcludeFromPolicyBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCaseBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.VhostUserCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.portsecurity.rev150712.PortSecurityExtension;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import com.google.common.annotations.VisibleForTesting;
68 import com.google.common.base.Optional;
69 import com.google.common.base.Preconditions;
70 import com.google.common.base.Strings;
71
72 public class PortHandler implements TransactionChainListener {
73
74     private static final Logger LOG = LoggerFactory.getLogger(PortHandler.class);
75
76     private static final String COMPUTE_OWNER = "compute";
77     private static final String DHCP_OWNER = "dhcp";
78     static final String ROUTER_OWNER = "network:router_interface";
79     private static final String[] SUPPORTED_DEVICE_OWNERS = {COMPUTE_OWNER, DHCP_OWNER, ROUTER_OWNER};
80     private static final String VHOST_USER = "vhostuser";
81     private static final String UNBOUND = "unbound";
82     private static final String VPP_INTERFACE_NAME_PREFIX = "neutron_port_";
83     private static final String TAP_PORT_NAME_PREFIX = "tap";
84     private static final String RT_PORT_NAME_PREFIX = "qr-";
85     private static final String VHOST_SOCKET_KEY = "vhostuser_socket";
86     static final String DEFAULT_NODE = "default";
87
88     private final NodeId routingNode;
89     private SyncedChain syncedChain;
90     private DataBroker dataBroker;
91
92     PortHandler(DataBroker dataBroker, NodeId routingNodeId) {
93         this.dataBroker = dataBroker;
94         this.routingNode = routingNodeId;
95         this.syncedChain = new SyncedChain(Preconditions.checkNotNull(dataBroker.createTransactionChain(this)));
96     }
97
98     void processCreated(Port port) {
99         Optional<BaseEndpointByPort> optBaseEpByPort =
100                 syncedChain.readFromDs(LogicalDatastoreType.OPERATIONAL, createBaseEpByPortIid(port.getUuid()));
101         if (!optBaseEpByPort.isPresent()) {
102             return;
103         }
104         processCreatedData(port, optBaseEpByPort.get());
105     }
106
107     void processCreated(BaseEndpointByPort bebp) {
108         Optional<Port> optPort =
109                 syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, createPortIid(bebp.getPortId()));
110         if (!optPort.isPresent()) {
111             return;
112         }
113         processCreatedData(optPort.get(), bebp);
114     }
115
116     @VisibleForTesting
117     void processCreatedData(Port port, BaseEndpointByPort bebp) {
118         if (isValidVhostUser(port)
119                 // this is a hack for vpp router port
120                 // Openstack does not send binding details yet
121                 || isValidVppRouterPort(port)) {
122             VppEndpoint vppEp = buildVppEndpoint(port, bebp);
123             if (vppEp == null) {
124                 LOG.warn("Cannot create vpp-endpoint from neutron port {}", port);
125                 return;
126             }
127             writeVppEndpoint(createVppEndpointIid(vppEp.getKey()), vppEp);
128             LOG.debug("Created vpp-endpoint {}", vppEp);
129         }
130     }
131
132     private boolean isValidVhostUser(Port port) {
133         PortBindingExtension portBindingExt = port.getAugmentation(PortBindingExtension.class);
134         if (portBindingExt != null) {
135             String vifType = portBindingExt.getVifType();
136             String deviceOwner = port.getDeviceOwner();
137             if (vifType != null && deviceOwner != null) {
138                 if (vifType.contains(VHOST_USER)) {
139                     for (String supportedDeviceOwner : SUPPORTED_DEVICE_OWNERS) {
140                         if (deviceOwner.contains(supportedDeviceOwner)) {
141                             return true;
142                         }
143                     }
144                 }
145             }
146         }
147         return false;
148     }
149
150     void processUpdated(Port original, Port delta) {
151         if (!isUpdateNeeded(original, delta)) {
152             LOG.trace("Port update skipped, port didn`t change. before {}, after: {}", original, delta);
153             return;
154         }
155
156         LOG.trace("Updating port before: {}, after: {}", original, delta);
157         if (isValidVhostUser(original)) {
158             Optional<BaseEndpointByPort> optBebp =
159                     syncedChain.readFromDs(LogicalDatastoreType.OPERATIONAL, createBaseEpByPortIid(original.getUuid()));
160             if (!optBebp.isPresent()) {
161                 return;
162             }
163             LOG.trace("Updating port - deleting old port {}", optBebp.get().getPortId());
164             processDeleted(optBebp.get());
165         }
166         LOG.trace("Updating port - creating new port {}", delta.getUuid());
167         processCreated(delta);
168     }
169
170     private boolean isUpdateNeeded(final Port oldPort, final Port newPort) {
171         // TODO fix this to better support update of ports for VPP
172         final PortBindingExtension oldPortAugmentation = oldPort.getAugmentation(PortBindingExtension.class);
173         final PortBindingExtension newPortAugmentation = newPort.getAugmentation(PortBindingExtension.class);
174
175         if (newPortAugmentation == null) {
176             LOG.trace("Port {} is no longer a vhost type port, updating port...");
177             return true;
178         }
179
180         final String oldDeviceOwner = oldPort.getDeviceOwner();
181         final String oldVifType = oldPortAugmentation.getVifType();
182         final String newDeviceOwner = newPort.getDeviceOwner();
183         final String newVifType = newPortAugmentation.getVifType();
184
185         // TODO potential bug here
186         // Temporary change for Openstack Mitaka: If old neutron-binding:vif-type is vhost, new one
187         // is unbound and
188         // device owner is ROUTER_OWNER, skip update. Openstack (or ml2) sometimes sends router
189         // update messages in
190         // incorrect order which causes unwanted port removal
191         if (oldVifType.equals(VHOST_USER) && newVifType.equals(UNBOUND) && oldDeviceOwner != null
192                 && ROUTER_OWNER.equals(oldDeviceOwner) && ROUTER_OWNER.equals(newDeviceOwner)) {
193             LOG.warn(
194                     "Port vif-type was updated from vhost to unbound. This update is currently disabled and will be skipped");
195             return false;
196         }
197
198         if (newVifType != null && !newVifType.equals(oldVifType)) {
199             LOG.trace("Vif type changed, old: {} new {}", oldVifType, newVifType);
200             return true;
201         }
202
203         final List<VifDetails> vifDetails = oldPortAugmentation.getVifDetails();
204
205         if (!oldPortAugmentation.getHostId().equals(newPortAugmentation.getHostId())
206                 || nullToEmpty(vifDetails).size() != nullToEmpty(newPortAugmentation.getVifDetails()).size()) {
207             return true;
208         }
209
210         for (VifDetails vifDetail : nullToEmpty(vifDetails)) {
211             // check if vhostuser_socket, vhostuser_mode and port_filter are changed
212             if (!newPortAugmentation.getVifDetails().contains(vifDetail))
213                 return true;
214         }
215         return false;
216     }
217
218     void processDeleted(BaseEndpointByPort bebp) {
219         LOG.trace("Deleting vpp-endpoint by BaseEndpointByPort {}", bebp);
220         VppEndpointKey vppEpKey = new VppEndpointKey(bebp.getAddress(), bebp.getAddressType(), bebp.getContextId(),
221                 bebp.getContextType());
222         InstanceIdentifier<VppEndpoint> vppEpIid = createVppEndpointIid(vppEpKey);
223         Optional<VppEndpoint> readVppEp = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, vppEpIid);
224         if (readVppEp.isPresent()) {
225             writeVppEndpoint(vppEpIid, null);
226             LOG.debug("Deleted vpp-endpoint {}", vppEpKey);
227         }
228     }
229
230     private synchronized void writeVppEndpoint(InstanceIdentifier<VppEndpoint> vppEpIid, VppEndpoint vppEp) {
231         WriteTransaction wTx = syncedChain.newWriteOnlyTransaction();
232         if (vppEp != null) {
233             wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEp, true);
234         } else {
235             wTx.delete(LogicalDatastoreType.CONFIGURATION, vppEpIid);
236         }
237         syncedChain.submitNow(wTx);
238     }
239
240     @VisibleForTesting
241     VppEndpoint buildVppEndpoint(Port port, BaseEndpointByPort bebp) {
242         PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
243         ExcludeFromPolicy excludeFromPolicy = new ExcludeFromPolicyBuilder().setExcludeFromPolicy(true).build();
244         VppEndpointBuilder vppEpBuilder = new VppEndpointBuilder().setDescription("neutron port")
245             .setContextId(bebp.getContextId())
246             .setContextType(bebp.getContextType())
247             .setAddress(bebp.getAddress())
248             .setAddressType(bebp.getAddressType())
249             .setVppInterfaceName(VPP_INTERFACE_NAME_PREFIX + bebp.getPortId().getValue())
250             .setVppNodeId(new NodeId(portBinding.getHostId()));
251
252         if (port.getDeviceOwner().contains(COMPUTE_OWNER)) {
253             vppEpBuilder.setInterfaceTypeChoice(
254                     new VhostUserCaseBuilder().setSocket(getSocketFromPortBinding(portBinding)).build());
255             Optional<PortSecurityExtension> portSecurity =
256                     Optional.fromNullable(port.getAugmentation(PortSecurityExtension.class));
257             if (portSecurity.isPresent() && !portSecurity.get().isPortSecurityEnabled()) {
258                 vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);
259             }
260
261         } else if (port.getDeviceOwner().contains(DHCP_OWNER) && port.getMacAddress() != null) {
262             IpAddress dhcpServerIpAddress = port.getFixedIps().stream().findFirst().isPresent() ?
263                 port.getFixedIps().stream().findFirst().get().getIpAddress() : null;
264             TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))
265                 .setName(createPortName(port.getUuid()))
266                 .setDhcpServerAddress(dhcpServerIpAddress)
267                 .build();
268             vppEpBuilder.setInterfaceTypeChoice(tapCase);
269
270         } else if (isValidQRouterPort(port)) {
271             TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))
272                 .setName(createQRouterPortName(port.getUuid()))
273                 .build();
274             vppEpBuilder.setInterfaceTypeChoice(tapCase);
275             vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);
276
277         } else if (isValidVppRouterPort(port)) {
278             if (!DEFAULT_NODE.equals(routingNode.getValue())) {
279                 LOG.warn(
280                         "Host-id changed by ODL for port {}. This is a supplementary workaround for choosing a routing node.",
281                         port);
282                 vppEpBuilder.setVppNodeId(routingNode);
283             } else if (port.getDeviceId() != null) {
284                 LOG.debug("Resolving host-id for unbound router port {}", port.getUuid());
285                 Optional<Ports> optPorts = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION,
286                         InstanceIdentifier.builder(Neutron.class).child(Ports.class).build());
287                 if (optPorts.isPresent() && optPorts.get().getPort() != null) {
288                     java.util.Optional<Port> optPortOnTheSameNode = optPorts.get()
289                         .getPort()
290                         .stream()
291                         .filter(p -> !p.getUuid().equals(port.getUuid()))
292                         .filter(p -> p.getAugmentation(PortBindingExtension.class) != null)
293                         .filter(p -> p.getDeviceOwner().contains(DHCP_OWNER))
294                         .findFirst();
295                     if (optPortOnTheSameNode.isPresent()) {
296                         PortBindingExtension binding =
297                                 optPortOnTheSameNode.get().getAugmentation(PortBindingExtension.class);
298                         if (binding != null && binding.getHostId() != null) {
299                             vppEpBuilder.setVppNodeId(new NodeId(binding.getHostId()));
300                         } else {
301                             LOG.warn("Cannot resolve location of router-port {}", port.getUuid());
302                             return null;
303                         }
304                     }
305                 }
306             }
307             vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);
308             vppEpBuilder.setInterfaceTypeChoice(getLoopbackCase(port));
309         }
310         return vppEpBuilder.build();
311     }
312
313     private String getSocketFromPortBinding(@Nonnull PortBindingExtension portBindingExtension) {
314         List<VifDetails> vifDetails = nullToEmpty(portBindingExtension.getVifDetails());
315
316         for (VifDetails detail : vifDetails) {
317             if (VHOST_SOCKET_KEY.equalsIgnoreCase(detail.getDetailsKey())) {
318                 return detail.getValue();
319             }
320         }
321         return null;
322     }
323
324     private LoopbackCase getLoopbackCase(Port port) {
325         LoopbackCaseBuilder loopbackCase =
326                 new LoopbackCaseBuilder().setPhysAddress(new PhysAddress(port.getMacAddress().getValue()));
327         Optional<FixedIps> fixedIpsOptional = resolveFirstFixedIps(port);
328         if (fixedIpsOptional.isPresent() && fixedIpsOptional.get().getIpAddress() != null) {
329             loopbackCase.setIpAddress(fixedIpsOptional.get().getIpAddress());
330             Optional<Subnet> subnetOptional = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION,
331                     InstanceIdentifier.builder(Neutron.class)
332                         .child(Subnets.class)
333                         .child(Subnet.class, new SubnetKey(fixedIpsOptional.get().getSubnetId()))
334                         .build());
335             if (subnetOptional.isPresent()) {
336                 Ipv4Prefix ipv4Prefix = subnetOptional.get().getCidr().getIpv4Prefix();
337                 loopbackCase.setIpPrefix(new IpPrefix(ipv4Prefix));
338             } else {
339                 LOG.warn("IpPrefix for loopback port: {} was not set.", port);
340             }
341             if (loopbackCase.getIpAddress() != null && loopbackCase.getIpPrefix() != null) {
342                 loopbackCase.setBvi(true);
343                 LOG.trace("Creating loopback BVI interface: {} for VPP router port: {}.", loopbackCase, port);
344             }
345
346         } else {
347             LOG.warn("IpAddress for loopback port: {} was not set.", port);
348         }
349         return loopbackCase.build();
350     }
351
352     /**
353      * If Qrouter (L3 Agent) is in use, any of Openstack neutron routers is not going be mapped
354      * to ODL neutron.
355      */
356     private boolean isValidQRouterPort(Port port) {
357         Optional<Router> optRouter = getRouterOptional(port);
358         return !optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) && port.getMacAddress() != null;
359     }
360
361     private boolean isValidVppRouterPort(Port port) {
362         Optional<Router> optRouter = getRouterOptional(port);
363         return optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) && port.getMacAddress() != null;
364     }
365
366     private Optional<Router> getRouterOptional(Port port) {
367         if (Strings.isNullOrEmpty(port.getDeviceId())) {
368             return Optional.absent();
369         }
370         RouterKey routerKey = null;
371         try {
372             routerKey = new RouterKey(new Uuid(port.getDeviceId()));
373         } catch (IllegalArgumentException e) {
374             // port.getDeviceId() may not match Uuid.PATTERN_CONSTANTS
375             return Optional.absent();
376         }
377         InstanceIdentifier<Router> routerIid =
378                 InstanceIdentifier.builder(Neutron.class).child(Routers.class).child(Router.class, routerKey).build();
379         Optional<Router> optRouter = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, routerIid);
380         return optRouter;
381     }
382
383     public static Optional<FixedIps> resolveFirstFixedIps(Port port) {
384         List<FixedIps> fixedIps = port.getFixedIps();
385         if (fixedIps != null && !fixedIps.isEmpty()) {
386             return Optional.of(fixedIps.get(0));
387         }
388         return Optional.absent();
389     }
390
391     private String createPortName(Uuid portUuid) {
392         String tapPortName;
393         String uuid = portUuid.getValue();
394         if (uuid != null && uuid.length() >= 12) {
395             tapPortName = TAP_PORT_NAME_PREFIX + uuid.substring(0, 11);
396         } else {
397             tapPortName = TAP_PORT_NAME_PREFIX + uuid;
398         }
399         return tapPortName;
400     }
401
402     private String createQRouterPortName(Uuid portUuid) {
403         String tapPortName;
404         String uuid = portUuid.getValue();
405         if (uuid != null && uuid.length() >= 12) {
406             tapPortName = RT_PORT_NAME_PREFIX + uuid.substring(0, 11);
407         } else {
408             tapPortName = RT_PORT_NAME_PREFIX + uuid;
409         }
410         return tapPortName;
411     }
412
413     private InstanceIdentifier<VppEndpoint> createVppEndpointIid(VppEndpointKey vppEpKey) {
414         return InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEpKey).build();
415     }
416
417     private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(Uuid uuid) {
418         return createBaseEpByPortIid(new UniqueId(uuid.getValue()));
419     }
420
421     private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(UniqueId uuid) {
422         return InstanceIdentifier.builder(Mappings.class)
423             .child(GbpByNeutronMappings.class)
424             .child(BaseEndpointsByPorts.class)
425             .child(BaseEndpointByPort.class, new BaseEndpointByPortKey(uuid))
426             .build();
427     }
428
429     InstanceIdentifier<Port> createWildcartedPortIid() {
430         return portsIid().child(Port.class).build();
431     }
432
433     private InstanceIdentifier<Port> createPortIid(UniqueId uuid) {
434         return portsIid().child(Port.class, new PortKey(new Uuid(uuid.getValue()))).build();
435     }
436
437     private InstanceIdentifierBuilder<Ports> portsIid() {
438         return InstanceIdentifier.builder(Neutron.class).child(Ports.class);
439     }
440
441     @Override
442     public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction,
443             Throwable cause) {
444         LOG.error("Transaction chain failed. {} \nTransaction which caused the chain to fail {}", cause.getMessage(),
445                 transaction, cause);
446         syncedChain.closeChain();
447         this.syncedChain = new SyncedChain(Preconditions.checkNotNull(dataBroker.createTransactionChain(this)));
448     }
449
450     @Override
451     public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
452         LOG.trace("Transaction chain was successful. {}", chain);
453     }
454
455     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
456         return list == null ? Collections.emptyList() : list;
457     }
458 }