2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.vpnservice.neutronvpn;
11 import com.google.common.base.Optional;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
18 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaces;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterfaceKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlanBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data
37 .PortFixedipToPortNameBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data
39 .PortNameToPortUuidBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
41 import org.opendaylight.yangtools.concepts.ListenerRegistration;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 import java.util.ArrayList;
47 import java.util.Iterator;
48 import java.util.List;
51 public class NeutronPortChangeListener extends AbstractDataChangeListener<Port> implements AutoCloseable {
52 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
54 private ListenerRegistration<DataChangeListener> listenerRegistration;
55 private final DataBroker broker;
56 private NeutronvpnManager nvpnManager;
59 public NeutronPortChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr) {
62 nvpnManager = nVpnMgr;
67 public void close() throws Exception {
68 if (listenerRegistration != null) {
70 listenerRegistration.close();
71 } catch (final Exception e) {
72 LOG.error("Error when cleaning up DataChangeListener.", e);
74 listenerRegistration = null;
76 LOG.info("N_Port listener Closed");
80 private void registerListener(final DataBroker db) {
82 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
83 InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class),
84 NeutronPortChangeListener.this, DataChangeScope.SUBTREE);
85 } catch (final Exception e) {
86 LOG.error("Neutron Manager Port DataChange listener registration fail!", e);
87 throw new IllegalStateException("Neutron Manager Port DataChange listener registration failed.", e);
92 protected void add(InstanceIdentifier<Port> identifier, Port input) {
93 if (LOG.isTraceEnabled()) {
94 LOG.trace("Adding Port : key: " + identifier + ", value=" + input);
96 handleNeutronPortCreated(input);
101 protected void remove(InstanceIdentifier<Port> identifier, Port input) {
102 if (LOG.isTraceEnabled()) {
103 LOG.trace("Removing Port : key: " + identifier + ", value=" + input);
105 handleNeutronPortDeleted(input);
110 protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
111 if (LOG.isTraceEnabled()) {
112 LOG.trace("Updating Port : key: " + identifier + ", original value=" + original + ", update value=" +
115 List<FixedIps> oldIPs = (original.getFixedIps() != null) ? original.getFixedIps() : new ArrayList<FixedIps>();
116 List<FixedIps> newIPs = (update.getFixedIps() != null) ? update.getFixedIps() : new ArrayList<FixedIps>();
118 if (!oldIPs.equals(newIPs)) {
119 Iterator<FixedIps> iterator = newIPs.iterator();
120 while (iterator.hasNext()) {
121 FixedIps ip = iterator.next();
122 if (oldIPs.remove(ip)) {
126 handleNeutronPortUpdated(original, update);
130 private void handleNeutronPortCreated(Port port) {
131 LOG.info("Of-port-interface creation");
132 int portVlanId = NeutronvpnUtils.getVlanFromNeutronPort(port);
133 // Create of-port interface for this neutron port
134 createOfPortInterface(port, portVlanId);
135 LOG.debug("Creating ELAN Interface");
136 createElanInterface(port);
137 LOG.debug("Add port to subnet");
138 // add port to local Subnets DS
139 Uuid vpnId = addPortToSubnets(port);
142 // create vpn-interface on this neutron port
143 LOG.debug("Adding VPN Interface");
144 nvpnManager.createVpnInterface(vpnId, port);
148 private void handleNeutronPortDeleted(Port port) {
149 LOG.debug("Of-port-interface removal");
150 LOG.debug("Remove port from subnet");
151 // remove port from local Subnets DS
152 Uuid vpnId = removePortFromSubnets(port);
155 // remove vpn-interface for this neutron port
156 LOG.debug("removing VPN Interface");
157 nvpnManager.deleteVpnInterface(port);
159 int portVlanId = NeutronvpnUtils.getVlanFromNeutronPort(port);
160 // Remove of-port interface for this neutron port
161 // ELAN interface is also implicitly deleted as part of this operation
162 deleteOfPortInterface(port, portVlanId);
166 private void handleNeutronPortUpdated(Port portoriginal, Port portupdate) {
167 LOG.debug("Add port to subnet");
168 // add port FixedIPs to local Subnets DS
169 Uuid vpnIdup = addPortToSubnets(portupdate);
171 if (vpnIdup != null) {
172 nvpnManager.createVpnInterface(vpnIdup, portupdate);
175 // remove port FixedIPs from local Subnets DS
176 Uuid vpnIdor = removePortFromSubnets(portoriginal);
178 if (vpnIdor != null) {
179 nvpnManager.deleteVpnInterface(portoriginal);
183 private void createOfPortInterface(Port port, int portVlanId) {
184 String name = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
185 //String ifname = new StringBuilder(name).append(":").append(Integer.toString(portVlanId)).toString();
186 //Network network = NeutronvpnUtils.getNeutronNetwork(broker, port.getNetworkId());
187 //Boolean isVlanTransparent = network.isVlanTransparent();
189 LOG.debug("Creating OFPort Interface {}", name);
190 InstanceIdentifier interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
192 Optional<Interface> optionalInf = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
193 interfaceIdentifier);
194 if (!optionalInf.isPresent()) {
195 // handle these for trunkport extensions : portVlanId, isVlanTransparent
196 IfL2vlan l2vlan = new IfL2vlanBuilder().setL2vlanMode(IfL2vlan.L2vlanMode.Trunk).build();
197 ParentRefs parentRefs = new ParentRefsBuilder().setParentInterface(name).build();
198 Interface inf = new InterfaceBuilder().setEnabled(true).setName(name).setType(L2vlan.class)
199 .addAugmentation(IfL2vlan.class, l2vlan).addAugmentation(ParentRefs.class, parentRefs).build();
200 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, interfaceIdentifier, inf);
202 LOG.error("Interface {} is already present", name);
204 } catch (Exception e) {
205 LOG.error("failed to create interface {} due to the exception {} ", name, e.getMessage());
208 InstanceIdentifier portIdentifier = NeutronvpnUtils.buildPortNameToPortUuidIdentifier(name);
209 PortNameToPortUuidBuilder builder = new PortNameToPortUuidBuilder().setPortName(name).setPortId(port.getUuid());
210 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, portIdentifier, builder.build());
211 LOG.debug("name-uuid map for port with name: {}, uuid: {} added to NeutronPortData DS", name, port.getUuid());
214 private void deleteOfPortInterface(Port port, int portVlanId) {
215 String name = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
216 //String ifname = new StringBuilder(name).append(":").append(Integer.toString(portVlanId)).toString();
217 LOG.debug("Removing OFPort Interface {}", name);
218 InstanceIdentifier interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
220 Optional<Interface> optionalInf = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
221 interfaceIdentifier);
222 if (optionalInf.isPresent()) {
223 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, interfaceIdentifier);
225 LOG.error("Interface {} is not present", name);
227 } catch (Exception e) {
228 LOG.error("Failed to delete interface {} due to the exception {}", name, e.getMessage());
231 InstanceIdentifier portIdentifier = NeutronvpnUtils.buildPortNameToPortUuidIdentifier(name);
232 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, portIdentifier);
233 LOG.debug("name-uuid map for port with name: {}, uuid: {} deleted from NeutronPortData DS", name, port
237 private void createElanInterface(Port port) {
238 String name = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
239 String elanInstanceName = port.getNetworkId().getValue();
240 List<PhysAddress> physAddresses = new ArrayList<>();
241 physAddresses.add(new PhysAddress(port.getMacAddress()));
243 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
244 .class, new ElanInterfaceKey(name)).build();
245 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
246 .setName(name).setStaticMacEntries(physAddresses).setKey(new ElanInterfaceKey(name)).build();
247 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, id, elanInterface);
248 LOG.debug("Creating new ELan Interface {}", elanInterface);
251 // adds port to subnet list and creates vpnInterface
252 private Uuid addPortToSubnets(Port port) {
253 Uuid subnetId = null;
255 String name = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
257 // find all subnets to which this port is associated
258 List<FixedIps> ips = port.getFixedIps();
259 for (FixedIps ip : ips) {
260 String ipValue = ip.getIpAddress().getIpv4Address().getValue();
262 InstanceIdentifier id = NeutronvpnUtils.buildFixedIpToPortNameIdentifier(ipValue);
263 PortFixedipToPortNameBuilder builder = new PortFixedipToPortNameBuilder().setPortFixedip(ipValue)
265 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, id, builder.build());
266 LOG.debug("fixedIp-name map for neutron port with fixedIp: {}, name: {} added to NeutronPortData DS",
269 subnetId = ip.getSubnetId();
270 Subnetmap subnetmap = nvpnManager.updateSubnetNode(subnetId, null, null, null, null, null, port.getUuid());
271 if (vpnId == null && subnetmap != null) {
272 vpnId = subnetmap.getVpnId();
278 private Uuid removePortFromSubnets(Port port) {
279 Uuid subnetId = null;
282 // find all Subnets to which this port is associated
283 List<FixedIps> ips = port.getFixedIps();
284 for (FixedIps ip : ips) {
285 String ipValue = ip.getIpAddress().getIpv4Address().getValue();
287 InstanceIdentifier id = NeutronvpnUtils.buildFixedIpToPortNameIdentifier(ipValue);
288 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
289 LOG.debug("fixedIp-name map for neutron port with fixedIp: {} deleted from NeutronPortData DS", ipValue);
291 subnetId = ip.getSubnetId();
292 Subnetmap subnetmap = nvpnManager.removeFromSubnetNode(subnetId, null, null, null, port.getUuid());
293 if (vpnId == null && subnetmap != null) {
294 vpnId = subnetmap.getVpnId();