Merge "L3: Add eth to br-ex"
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / translator / iaware / impl / NeutronPortChangeListener.java
1 /*
2  * Copyright (c) 2015 Brocade Communications 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 package org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.impl;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Set;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
24 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_AllowedAddressPairs;
25 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_ExtraDHCPOption;
26 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort_VIFDetail;
27 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
28 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
29 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
30 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
31 import org.opendaylight.ovsdb.openstack.netvirt.translator.iaware.INeutronPortAware;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
41 import org.opendaylight.yangtools.concepts.ListenerRegistration;
42 import org.opendaylight.yangtools.yang.binding.DataObject;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class NeutronPortChangeListener implements DataChangeListener, AutoCloseable{
48     private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
49
50     private ListenerRegistration<DataChangeListener> registration;
51     private DataBroker db;
52
53     public NeutronPortChangeListener(DataBroker db){
54         this.db = db;
55         InstanceIdentifier<Port> path = InstanceIdentifier
56                 .create(Neutron.class)
57                 .child(Ports.class)
58                 .child(Port.class);
59         LOG.debug("Register listener for Neutron Port model data changes");
60         registration =
61                 this.db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, path, this, DataChangeScope.ONE);
62
63     }
64
65     @Override
66     public void onDataChanged(
67             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes) {
68         LOG.trace("Data changes : {}",changes);
69
70         Object[] subscribers = NeutronIAwareUtil.getInstances(INeutronPortAware.class, this);
71         createPort(changes, subscribers);
72         updatePort(changes, subscribers);
73         deletePort(changes, subscribers);
74     }
75
76     private void createPort(
77             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
78             Object[] subscribers) {
79         for (Entry<InstanceIdentifier<?>, DataObject> newPort : changes.getCreatedData().entrySet()) {
80                 if(newPort.getValue() instanceof Port){
81                 NeutronPort port = fromMd((Port)newPort.getValue());
82                 for(Object entry: subscribers){
83                     INeutronPortAware subscriber = (INeutronPortAware)entry;
84                     subscriber.neutronPortCreated(port);
85                 }
86                 }
87         }
88     }
89
90     private void updatePort(
91             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
92             Object[] subscribers) {
93         Map<String, NeutronPort> originalPortMap = getChangedPorts(changes.getOriginalData());
94         for (Entry<InstanceIdentifier<?>, DataObject> updatePort : changes.getUpdatedData().entrySet()) {
95             if (updatePort.getValue() instanceof Port) {
96                 NeutronPort port = fromMd((Port)updatePort.getValue());
97                 NeutronPort originalPort = originalPortMap.get(port.getID());
98                 if (originalPort != null) {
99                     port.setOriginalPort(originalPort);
100                 } else {
101                     LOG.warn("Original Port data is missing");
102                 }
103                 for (Object entry: subscribers) {
104                     INeutronPortAware subscriber = (INeutronPortAware)entry;
105                     subscriber.neutronPortUpdated(port);
106                 }
107             }
108         }
109     }
110
111     private void deletePort(
112             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
113             Object[] subscribers) {
114         for (InstanceIdentifier<?> deletedPortPath : changes.getRemovedPaths()) {
115             if(deletedPortPath.getTargetType().equals(Port.class)){
116                 NeutronPort port = fromMd((Port)changes.getOriginalData().get(deletedPortPath));
117                 for(Object entry: subscribers){
118                     INeutronPortAware subscriber = (INeutronPortAware)entry;
119                     subscriber.neutronPortDeleted(port);
120                 }
121             }
122         }
123     }
124
125     /*
126      * This method is borrowed from NeutronPortInterface.java class of Neutron Northbound class.
127      * We will be utilizing similar code from other classes from the same package of neutron project.
128      */
129     private NeutronPort fromMd(Port port) {
130
131         NeutronPort result = new NeutronPort();
132         result.setAdminStateUp(port.isAdminStateUp());
133         if (port.getAllowedAddressPairs() != null) {
134             List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<>();
135             for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
136                 NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
137                 pair.setIpAddress(mdPair.getIpAddress());
138                 pair.setMacAddress(mdPair.getMacAddress());
139                 pair.setPortID(mdPair.getPortId());
140                 pairs.add(pair);
141             }
142             result.setAllowedAddressPairs(pairs);
143         }
144         result.setDeviceID(port.getDeviceId());
145         result.setDeviceOwner(port.getDeviceOwner());
146         if (port.getExtraDhcpOpts() != null) {
147             List<NeutronPort_ExtraDHCPOption> options = new ArrayList<>();
148             for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
149                 NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
150                 arg.setName(opt.getOptName());
151                 arg.setValue(opt.getOptValue());
152                 options.add(arg);
153             }
154             result.setExtraDHCPOptions(options);
155         }
156         if (port.getFixedIps() != null) {
157             List<Neutron_IPs> ips = new ArrayList<>();
158             for (FixedIps mdIP : port.getFixedIps()) {
159                 Neutron_IPs ip = new Neutron_IPs();
160                 ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
161                 ip.setSubnetUUID(mdIP.getSubnetId().getValue());
162                 ips.add(ip);
163             }
164             result.setFixedIPs(ips);
165         }
166         result.setMacAddress(port.getMacAddress());
167         result.setName(port.getName());
168         result.setNetworkUUID(String.valueOf(port.getNetworkId().getValue()));
169         if (port.getSecurityGroups() != null) {
170             Set<NeutronSecurityGroup> allGroups = new HashSet<>();
171             NeutronCRUDInterfaces interfaces = new NeutronCRUDInterfaces().fetchINeutronSecurityGroupCRUD(this);
172             INeutronSecurityGroupCRUD sgIf = interfaces.getSecurityGroupInterface();
173             for (Uuid sgUuid : port.getSecurityGroups()) {
174                 NeutronSecurityGroup secGroup = sgIf.getNeutronSecurityGroup(sgUuid.getValue());
175                 if (secGroup != null) {
176                     allGroups.add(sgIf.getNeutronSecurityGroup(sgUuid.getValue()));
177                 }
178             }
179             List<NeutronSecurityGroup> groups = new ArrayList<>();
180             groups.addAll(allGroups);
181             result.setSecurityGroups(groups);
182         }
183         result.setStatus(port.getStatus());
184         if (port.getTenantId() != null) {
185             result.setTenantID(String.valueOf(port.getTenantId().getValue()).replace("-", ""));
186         }
187         result.setPortUUID(String.valueOf(port.getUuid().getValue()));
188         addExtensions(port, result);
189         return result;
190     }
191
192     protected void addExtensions(Port port, NeutronPort result) {
193         PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
194         result.setBindinghostID(binding.getHostId());
195         if (binding.getVifDetails() != null) {
196             List<NeutronPort_VIFDetail> details = new ArrayList<>();
197             for (VifDetails vifDetail : binding.getVifDetails()) {
198                 NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
199                 detail.setPortFilter(vifDetail.isPortFilter());
200                 detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
201                 details.add(detail);
202             }
203             result.setVIFDetail(details);
204         }
205         result.setBindingvifType(binding.getVifType());
206         result.setBindingvnicType(binding.getVnicType());
207     }
208
209     private  Map<String,NeutronPort> getChangedPorts(Map<InstanceIdentifier<?>, DataObject> changedData) {
210         LOG.trace("getChangedPorts:" + changedData);
211         Map<String,NeutronPort> portMap = new HashMap<>();
212         for (Map.Entry<InstanceIdentifier<?>, DataObject> changed : changedData.entrySet()) {
213             if (changed.getValue() instanceof Port) {
214                 NeutronPort port = fromMd((Port)changed.getValue());
215                 portMap.put(port.getID(), port);
216             }
217         }
218         return portMap;
219     }
220
221     @Override
222     public void close() throws Exception {
223         registration.close();
224     }
225 }