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