NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / ipv6service / impl / src / main / java / org / opendaylight / netvirt / ipv6service / Ipv6ServiceInterfaceEventListener.java
1 /*
2  * Copyright (c) 2016, 2017 Red Hat, 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 package org.opendaylight.netvirt.ipv6service;
9
10 import java.util.Collections;
11 import java.util.List;
12 import javax.annotation.PreDestroy;
13 import javax.inject.Inject;
14 import javax.inject.Singleton;
15 import org.opendaylight.genius.mdsalutil.MDSALUtil;
16 import org.opendaylight.genius.mdsalutil.NwConstants;
17 import org.opendaylight.genius.utils.SystemPropertyReader;
18 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
19 import org.opendaylight.infrautils.utils.concurrent.Executors;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceConstants;
23 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
24 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredAsyncDataTreeChangeListener;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.opendaylight.yangtools.yang.common.Uint64;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 @Singleton
36 public class Ipv6ServiceInterfaceEventListener
37         extends AbstractClusteredAsyncDataTreeChangeListener<Interface> {
38     private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceInterfaceEventListener.class);
39     private final DataBroker dataBroker;
40     private final IfMgr ifMgr;
41     private final Ipv6ServiceUtils ipv6ServiceUtils;
42     private final JobCoordinator jobCoordinator;
43     private final Ipv6ServiceEosHandler ipv6ServiceEosHandler;
44
45     /**
46      * Intialize the member variables.
47      * @param broker the data broker instance.
48      */
49     @Inject
50     public Ipv6ServiceInterfaceEventListener(DataBroker broker, IfMgr ifMgr, Ipv6ServiceUtils ipv6ServiceUtils,
51             final JobCoordinator jobCoordinator, Ipv6ServiceEosHandler ipv6ServiceEosHandler) {
52         super(broker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(InterfacesState.class)
53                         .child(Interface.class),
54                 Executors.newListeningSingleThreadExecutor("Ipv6ServiceInterfaceEventListener", LOG));
55         this.dataBroker = broker;
56         this.ifMgr = ifMgr;
57         this.ipv6ServiceUtils = ipv6ServiceUtils;
58         this.jobCoordinator = jobCoordinator;
59         this.ipv6ServiceEosHandler = ipv6ServiceEosHandler;
60     }
61
62     public void init() {
63         LOG.info("{} init", getClass().getSimpleName());
64     }
65
66     @Override
67     @PreDestroy
68     public void close() {
69         super.close();
70         Executors.shutdownAndAwaitTermination(getExecutorService());
71     }
72
73     @Override
74     public void remove(InstanceIdentifier<Interface> key, Interface del) {
75         LOG.debug("Port removed {}, {}", key, del);
76         if (!L2vlan.class.equals(del.getType())) {
77             return;
78         }
79
80         // In ipv6service, we are only interested in the notification for NeutronPort, so we skip other notifications
81         List<String> ofportIds = del.getLowerLayerIf();
82         if (ofportIds == null || ofportIds.isEmpty() || !isNeutronPort(del.getName())) {
83             return;
84         }
85
86         if (!ipv6ServiceEosHandler.isClusterOwner()) {
87             LOG.trace("Not a cluster Owner, skipping further IPv6 processing on this node.");
88             return;
89         }
90         Uuid portId = new Uuid(del.getName());
91         VirtualPort port = ifMgr.obtainV6Interface(portId);
92         if (port == null) {
93             LOG.info("Port {} does not include IPv6Address, skipping.", portId);
94             return;
95         }
96
97         if (port.getServiceBindingStatus()) {
98             jobCoordinator.enqueueJob("IPv6-" + String.valueOf(portId), () -> {
99                 // Unbind Service
100                 ipv6ServiceUtils.unbindIpv6Service(portId.getValue());
101                 port.setServiceBindingStatus(false);
102                 return Collections.emptyList();
103             }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
104         }
105
106         VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
107         ifMgr.handleInterfaceStateEvent(port, ipv6ServiceUtils.getDpIdFromInterfaceState(del), routerPort,
108                 Ipv6ServiceConstants.DEL_FLOW);
109     }
110
111     @Override
112     public void update(InstanceIdentifier<Interface> key, Interface before, Interface after) {
113         if (before.getType() == null && L2vlan.class.equals(after.getType())) {
114             add(key, after);
115         }
116     }
117
118     private boolean isNeutronPort(String name) {
119         try {
120             new Uuid(name);
121             return true;
122         } catch (IllegalArgumentException e) {
123             LOG.debug("Port {} is not a Neutron Port, skipping.", name);
124         }
125         return false;
126     }
127
128     @Override
129     public void add(InstanceIdentifier<Interface> key, Interface add) {
130         List<String> ofportIds = add.getLowerLayerIf();
131
132         if (!L2vlan.class.equals(add.getType())) {
133             return;
134         }
135
136         // When a port is created, we receive multiple notifications.
137         // In ipv6service, we are only interested in the notification for NeutronPort, so we skip other notifications
138         if (ofportIds == null || ofportIds.isEmpty() || !isNeutronPort(add.getName())) {
139             return;
140         }
141
142         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface;
143         iface = ipv6ServiceUtils.getInterface(add.getName());
144         if (null != iface) {
145             LOG.debug("Port {} is a Neutron port", iface.getName());
146             NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
147             Uint64 dpId = Ipv6ServiceUtils.getDpnIdFromNodeConnectorId(nodeConnectorId);
148
149             if (!dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
150                 Uuid portId = new Uuid(iface.getName());
151                 VirtualPort port = ifMgr.obtainV6Interface(portId);
152                 if (port == null) {
153                     LOG.info("Port {} does not include IPv6Address, skipping.", portId);
154                     return;
155                 }
156
157                 Long ofPort = MDSALUtil.getOfPortNumberFromPortName(nodeConnectorId);
158                 ifMgr.updateDpnInfo(portId, dpId, ofPort);
159
160                 if (!ipv6ServiceEosHandler.isClusterOwner()) {
161                     LOG.trace("Not a cluster Owner, skipping further IPv6 processing on this node.");
162                     return;
163                 }
164
165                 VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
166                 if (routerPort == null) {
167                     LOG.info("Port {} is not associated to a Router, skipping.", portId);
168                     return;
169                 }
170                 ifMgr.handleInterfaceStateEvent(port, dpId, routerPort, Ipv6ServiceConstants.ADD_FLOW);
171
172                 if (!port.getServiceBindingStatus()) {
173                     jobCoordinator.enqueueJob("IPv6-" + String.valueOf(portId), () -> {
174                         // Bind Service
175                         Long elanTag = ifMgr.getNetworkElanTag(routerPort.getNetworkID());
176                         ipv6ServiceUtils.bindIpv6Service(portId.getValue(), elanTag, NwConstants.IPV6_TABLE);
177                         port.setServiceBindingStatus(true);
178                         return Collections.emptyList();
179                     }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
180                 }
181             }
182         }
183     }
184 }