2 * Copyright (c) 2015 - 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.netvirt.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.binding.api.NotificationPublishService;
16 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
20 import org.opendaylight.genius.mdsalutil.MDSALUtil;
21 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortAddedToSubnetBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortRemovedFromSubnetBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.port.data
44 .PortFixedipToPortNameBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
46 import org.opendaylight.yangtools.concepts.ListenerRegistration;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 import java.util.ArrayList;
52 import java.util.Iterator;
53 import java.util.List;
56 public class NeutronPortChangeListener extends AbstractDataChangeListener<Port> implements AutoCloseable {
57 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
59 private ListenerRegistration<DataChangeListener> listenerRegistration;
60 private final DataBroker broker;
61 private NeutronvpnManager nvpnManager;
62 private NeutronvpnNatManager nvpnNatManager;
63 private LockManagerService lockManager;
64 private NotificationPublishService notificationPublishService;
65 private NotificationService notificationService;
68 public NeutronPortChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr,NeutronvpnNatManager nVpnNatMgr,
69 NotificationPublishService notiPublishService, NotificationService notiService) {
72 nvpnManager = nVpnMgr;
73 nvpnNatManager = nVpnNatMgr;
74 notificationPublishService = notiPublishService;
75 notificationService = notiService;
79 public void setLockManager(LockManagerService lockManager) {
80 this.lockManager = lockManager;
84 public void close() throws Exception {
85 if (listenerRegistration != null) {
87 listenerRegistration.close();
88 } catch (final Exception e) {
89 LOG.error("Error when cleaning up DataChangeListener.", e);
91 listenerRegistration = null;
93 LOG.info("N_Port listener Closed");
97 private void registerListener(final DataBroker db) {
99 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
100 InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class),
101 NeutronPortChangeListener.this, DataChangeScope.SUBTREE);
102 } catch (final Exception e) {
103 LOG.error("Neutron Manager Port DataChange listener registration fail!", e);
104 throw new IllegalStateException("Neutron Manager Port DataChange listener registration failed.", e);
109 protected void add(InstanceIdentifier<Port> identifier, Port input) {
110 if (LOG.isTraceEnabled()) {
111 LOG.trace("Adding Port : key: " + identifier + ", value=" + input);
113 Network network = NeutronvpnUtils.getNeutronNetwork(broker, input.getNetworkId());
114 if (network == null || NeutronvpnUtils.isNetworkTypeVlanOrGre(network)) {
115 //FIXME: This should be removed when support for VLAN and GRE network types is added
116 LOG.error("neutron vpn doesn't support vlan/gre network provider type for the port {} which is part of network {}.",
117 input.getName(), network);
120 /* check if router interface has been created */
121 if ((input.getDeviceOwner() != null) && (input.getDeviceId() != null)) {
122 if (input.getDeviceOwner().equals(NeutronvpnUtils.DEVICE_OWNER_ROUTER_INF)) {
123 handleRouterInterfaceAdded(input);
124 /* nothing else to do here */
128 handleNeutronPortCreated(input);
129 NeutronvpnUtils.addToPortCache(input);
134 protected void remove(InstanceIdentifier<Port> identifier, Port input) {
135 if (LOG.isTraceEnabled()) {
136 LOG.trace("Removing Port : key: " + identifier + ", value=" + input);
138 Network network = NeutronvpnUtils.getNeutronNetwork(broker, input.getNetworkId());
139 if (network == null || NeutronvpnUtils.isNetworkTypeVlanOrGre(network)) {
140 //FIXME: This should be removed when support for VLAN and GRE network types is added
141 LOG.error("neutron vpn doesn't support vlan/gre network provider type for the port {} which is part of network {}.",
142 input.getName(), network);
145 if ((input.getDeviceOwner() != null) && (input.getDeviceId() != null)) {
146 if (input.getDeviceOwner().equals(NeutronvpnUtils.DEVICE_OWNER_ROUTER_INF)) {
147 handleRouterInterfaceRemoved(input);
148 /* nothing else to do here */
152 handleNeutronPortDeleted(input);
153 NeutronvpnUtils.removeFromPortCache(input);
157 protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
158 if (LOG.isTraceEnabled()) {
159 LOG.trace("Updating Port : key: " + identifier + ", original value=" + original + ", update value=" +
163 Network network = NeutronvpnUtils.getNeutronNetwork(broker, update.getNetworkId());
164 if (network == null || NeutronvpnUtils.isNetworkTypeVlanOrGre(network)) {
165 LOG.error("neutron vpn doesn't support vlan/gre network provider type for the port {} which is part of network {}."
166 + " Skipping the processing of Port update DCN", update.getName(), network);
169 List<FixedIps> oldIPs = (original.getFixedIps() != null) ? original.getFixedIps() : new ArrayList<FixedIps>();
170 List<FixedIps> newIPs = (update.getFixedIps() != null) ? update.getFixedIps() : new ArrayList<FixedIps>();
172 /* check if router interface has been updated */
173 if ((update.getDeviceOwner() != null) && (update.getDeviceId() != null)) {
174 if (update.getDeviceOwner().equals(NeutronvpnUtils.DEVICE_OWNER_ROUTER_INF)) {
175 handleRouterInterfaceAdded(update);
176 /* nothing else to do here */
181 if (!oldIPs.equals(newIPs)) {
182 Iterator<FixedIps> iterator = newIPs.iterator();
183 while (iterator.hasNext()) {
184 FixedIps ip = iterator.next();
185 if (oldIPs.remove(ip)) {
189 handleNeutronPortUpdated(original, update);
190 NeutronvpnUtils.addToPortCache(update);
194 private void handleRouterInterfaceAdded(Port routerPort) {
195 if (routerPort.getDeviceId() != null) {
196 Uuid routerId = new Uuid(routerPort.getDeviceId());
197 Uuid infNetworkId = routerPort.getNetworkId();
198 Uuid existingVpnId = NeutronvpnUtils.getVpnForNetwork(broker, infNetworkId);
199 if (existingVpnId == null) {
200 for (FixedIps portIP : routerPort.getFixedIps()) {
201 if (portIP.getIpAddress().getIpv4Address() != null) {
202 Uuid vpnId = NeutronvpnUtils.getVpnForRouter(broker, routerId, true);
206 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId());
207 nvpnNatManager.handleSubnetsForExternalRouter(routerId, broker);
211 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {} already" +
212 " associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(), routerId
213 .getValue(), existingVpnId.getValue());
218 private void handleRouterInterfaceRemoved(Port routerPort) {
219 if (routerPort.getDeviceId() != null) {
220 Uuid routerId = new Uuid(routerPort.getDeviceId());
221 for (FixedIps portIP : routerPort.getFixedIps()) {
222 if (portIP.getIpAddress().getIpv4Address() != null) {
223 Uuid vpnId = NeutronvpnUtils.getVpnForRouter(broker, routerId, true);
227 nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId());
228 nvpnNatManager.handleSubnetsForExternalRouter(routerId, broker);
234 private void handleNeutronPortCreated(Port port) {
235 if (!NeutronUtils.isPortVnicTypeNormal(port)) {
236 LOG.info("Port {} is not a NORMAL VNIC Type port; OF Port interfaces are not created",
237 port.getUuid().getValue());
240 LOG.info("Of-port-interface creation");
241 // Create of-port interface for this neutron port
242 String portInterfaceName = createOfPortInterface(port);
243 LOG.debug("Creating ELAN Interface");
244 createElanInterface(port, portInterfaceName);
245 LOG.debug("Add port to subnet");
246 // add port to local Subnets DS
247 Uuid vpnId = addPortToSubnets(port);
250 // create vpn-interface on this neutron port
251 LOG.debug("Adding VPN Interface");
252 nvpnManager.createVpnInterface(vpnId, port);
253 Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
254 if(routerId != null) {
255 nvpnManager.addToNeutronRouterInterfacesMap(routerId, port.getUuid().getValue());
260 private void handleNeutronPortDeleted(Port port) {
261 LOG.debug("Of-port-interface removal");
262 LOG.debug("Remove port from subnet");
263 // remove port from local Subnets DS
264 Uuid vpnId = removePortFromSubnets(port);
267 // remove vpn-interface for this neutron port
268 LOG.debug("removing VPN Interface");
269 nvpnManager.deleteVpnInterface(port);
271 // Remove of-port interface for this neutron port
272 // ELAN interface is also implicitly deleted as part of this operation
273 deleteOfPortInterface(port);
275 Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnId).getRouterId();
276 if(routerId != null) {
277 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, port.getUuid().getValue());
282 private void handleNeutronPortUpdated(Port portoriginal, Port portupdate) {
283 LOG.debug("Add port to subnet");
284 // add port FixedIP to local Subnets DS
285 Uuid vpnIdup = addPortToSubnets(portupdate);
287 if (vpnIdup != null) {
288 nvpnManager.createVpnInterface(vpnIdup, portupdate);
289 Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnIdup).getRouterId();
290 if(routerId != null) {
291 nvpnManager.addToNeutronRouterInterfacesMap(routerId, portupdate.getUuid().getValue());
295 // remove port FixedIP from local Subnets DS
296 Uuid vpnIdor = removePortFromSubnets(portoriginal);
298 if (vpnIdor != null) {
299 nvpnManager.deleteVpnInterface(portoriginal);
300 Uuid routerId = NeutronvpnUtils.getVpnMap(broker, vpnIdor).getRouterId();
301 if(routerId != null) {
302 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portoriginal.getUuid().getValue());
307 private String createOfPortInterface(Port port) {
308 Interface inf = createInterface(port);
309 String infName = inf.getName();
311 LOG.debug("Creating OFPort Interface {}", infName);
312 InstanceIdentifier interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
314 Optional<Interface> optionalInf = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
315 interfaceIdentifier);
316 if (!optionalInf.isPresent()) {
317 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, interfaceIdentifier, inf);
319 LOG.error("Interface {} is already present", infName);
321 } catch (Exception e) {
322 LOG.error("failed to create interface {} due to the exception {} ", infName, e.getMessage());
327 private Interface createInterface(Port port) {
328 String parentRefName = NeutronvpnUtils.uuidToTapPortName(port.getUuid());
329 String interfaceName = port.getUuid().getValue();
330 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
331 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
332 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
333 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
334 ParentRefsBuilder parentRefsBuilder = new ParentRefsBuilder().setParentInterface(parentRefName);
335 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class).addAugmentation(IfL2vlan
336 .class, ifL2vlanBuilder.build()).addAugmentation(ParentRefs.class, parentRefsBuilder.build());
337 return interfaceBuilder.build();
340 private void deleteOfPortInterface(Port port) {
341 String name = port.getUuid().getValue();
342 LOG.debug("Removing OFPort Interface {}", name);
343 InstanceIdentifier interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
345 Optional<Interface> optionalInf = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
346 interfaceIdentifier);
347 if (optionalInf.isPresent()) {
348 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, interfaceIdentifier);
350 LOG.error("Interface {} is not present", name);
352 } catch (Exception e) {
353 LOG.error("Failed to delete interface {} due to the exception {}", name, e.getMessage());
357 private void createElanInterface(Port port, String name) {
358 String elanInstanceName = port.getNetworkId().getValue();
359 List<PhysAddress> physAddresses = new ArrayList<>();
360 physAddresses.add(new PhysAddress(port.getMacAddress().getValue()));
362 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
363 .class, new ElanInterfaceKey(name)).build();
364 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
365 .setName(name).setStaticMacEntries(physAddresses).setKey(new ElanInterfaceKey(name)).build();
366 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, id, elanInterface);
367 LOG.debug("Creating new ELan Interface {}", elanInterface);
370 // adds port to subnet list and creates vpnInterface
371 private Uuid addPortToSubnets(Port port) {
372 Uuid subnetId = null;
374 Subnetmap subnetmap = null;
375 String infName = port.getUuid().getValue();
376 boolean isLockAcquired = false;
377 String lockName = port.getUuid().getValue();
379 // find the subnet to which this port is associated
380 if(port.getFixedIps() == null || port.getFixedIps().isEmpty()) {
381 LOG.debug("port {} doesn't have ip", port.getName());
384 FixedIps ip = port.getFixedIps().get(0);
385 String ipValue = (ip.getIpAddress().getIpv4Address() != null ) ? ip.getIpAddress().getIpv4Address().getValue() :
386 ip.getIpAddress().getIpv6Address().getValue();
387 InstanceIdentifier id = NeutronvpnUtils.buildFixedIpToPortNameIdentifier(ipValue);
388 PortFixedipToPortNameBuilder builder = new PortFixedipToPortNameBuilder().setPortFixedip(ipValue)
389 .setPortName(infName);
390 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, id, builder.build());
391 LOG.debug("fixedIp-name map for neutron port with fixedIp: {}, name: {} added to NeutronPortData DS",
393 subnetId = ip.getSubnetId();
394 subnetmap = nvpnManager.updateSubnetNode(subnetId, null, null, null, null, null, port.getUuid());
395 if (subnetmap != null) {
396 vpnId = subnetmap.getVpnId();
400 isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
401 checkAndPublishPortAddNotification(subnetmap.getSubnetIp(), subnetId, port.getUuid());
402 LOG.debug("Port added to subnet notification sent");
403 } catch (Exception e) {
404 LOG.error("Port added to subnet notification failed", e);
406 if (isLockAcquired) {
407 NeutronvpnUtils.unlock(lockManager, lockName);
414 private Uuid removePortFromSubnets(Port port) {
415 Uuid subnetId = null;
417 Subnetmap subnetmap = null;
418 boolean isLockAcquired = false;
419 String lockName = port.getUuid().getValue();
421 // find the subnet to which this port is associated
422 FixedIps ip = port.getFixedIps().get(0);
423 String ipValue = ip.getIpAddress().getIpv4Address().getValue();
424 InstanceIdentifier id = NeutronvpnUtils.buildFixedIpToPortNameIdentifier(ipValue);
425 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
426 LOG.debug("fixedIp-name map for neutron port with fixedIp: {} deleted from NeutronPortData DS", ipValue);
427 subnetId = ip.getSubnetId();
428 subnetmap = nvpnManager.removeFromSubnetNode(subnetId, null, null, null, port.getUuid());
429 if (subnetmap != null) {
430 vpnId = subnetmap.getVpnId();
434 isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
435 checkAndPublishPortRemoveNotification(subnetmap.getSubnetIp(), subnetId, port.getUuid());
436 LOG.debug("Port removed from subnet notification sent");
437 } catch (Exception e) {
438 LOG.error("Port removed from subnet notification failed", e);
440 if (isLockAcquired) {
441 NeutronvpnUtils.unlock(lockManager, lockName);
448 private void checkAndPublishPortAddNotification(String subnetIp, Uuid subnetId, Uuid portId)throws InterruptedException{
449 PortAddedToSubnetBuilder builder = new PortAddedToSubnetBuilder();
451 LOG.info("publish notification called");
453 builder.setSubnetIp(subnetIp);
454 builder.setSubnetId(subnetId);
455 builder.setPortId(portId);
457 notificationPublishService.putNotification(builder.build());
460 private void checkAndPublishPortRemoveNotification(String subnetIp, Uuid subnetId, Uuid portId)throws InterruptedException{
461 PortRemovedFromSubnetBuilder builder = new PortRemovedFromSubnetBuilder();
463 LOG.info("publish notification called");
465 builder.setPortId(portId);
466 builder.setSubnetIp(subnetIp);
467 builder.setSubnetId(subnetId);
469 notificationPublishService.putNotification(builder.build());