blob: c7ae7cc5b535f5cbcc60e074cd2a220f64672f49 [file] [log] [blame]
Jian Liecae4382018-06-28 17:41:12 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.MacAddress;
28import org.onosproject.core.CoreService;
29import org.onosproject.event.ListenerRegistry;
30import org.onosproject.net.Host;
31import org.onosproject.net.host.HostEvent;
32import org.onosproject.net.host.HostListener;
33import org.onosproject.net.host.HostService;
34import org.onosproject.openstacknetworking.api.Constants;
35import org.onosproject.openstacknetworking.api.InstancePort;
36import org.onosproject.openstacknetworking.api.InstancePortAdminService;
37import org.onosproject.openstacknetworking.api.InstancePortEvent;
38import org.onosproject.openstacknetworking.api.InstancePortListener;
39import org.onosproject.openstacknetworking.api.InstancePortService;
40import org.onosproject.openstacknetworking.api.InstancePortStore;
41import org.onosproject.openstacknetworking.api.InstancePortStoreDelegate;
42import org.slf4j.Logger;
43
44import java.util.Set;
45import java.util.stream.Collectors;
46
47import static com.google.common.base.Preconditions.checkArgument;
48import static com.google.common.base.Preconditions.checkNotNull;
49import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
50import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
51import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
52import static org.slf4j.LoggerFactory.getLogger;
53
54/**
55 * Provides implementation of administering and interfacing instance ports.
56 * It also provides instance port events for the hosts mapped to OpenStack VM interface.
57 */
58@Service
59@Component(immediate = false)
60public class InstancePortManager
61 extends ListenerRegistry<InstancePortEvent, InstancePortListener>
62 implements InstancePortService, InstancePortAdminService {
63
64 protected final Logger log = getLogger(getClass());
65
66 private static final String MSG_INSTANCE_PORT = "Instance port %s %s";
67 private static final String MSG_CREATED = "created";
68 private static final String MSG_UPDATED = "updated";
69 private static final String MSG_REMOVED = "removed";
70
71 private static final String ERR_NULL_INSTANCE_PORT = "Instance port cannot be null";
72 private static final String ERR_NULL_INSTANCE_PORT_ID = "Instance port ID cannot be null";
73 private static final String ERR_NULL_MAC_ADDRESS = "MAC address cannot be null";
74 private static final String ERR_NULL_IP_ADDRESS = "IP address cannot be null";
75 private static final String ERR_NULL_NETWORK_ID = "Network ID cannot be null";
76
77 private static final String ERR_IN_USE = " still in use";
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CoreService coreService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected InstancePortStore instancePortStore;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected HostService hostService;
87
88 private final InstancePortStoreDelegate
89 delegate = new InternalInstancePortStoreDelegate();
90 private final InternalHostListener
91 hostListener = new InternalHostListener();
92
93 @Activate
94 protected void activate() {
95 coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
96 instancePortStore.setDelegate(delegate);
97 hostService.addListener(hostListener);
98 log.info("Started");
99 }
100
101 @Deactivate
102 protected void deactivate() {
103 hostService.removeListener(hostListener);
104 instancePortStore.unsetDelegate(delegate);
105 log.info("Stopped");
106 }
107
108 @Override
109 public void createInstancePort(InstancePort instancePort) {
110 checkNotNull(instancePort, ERR_NULL_INSTANCE_PORT);
111 checkArgument(!Strings.isNullOrEmpty(instancePort.portId()),
112 ERR_NULL_INSTANCE_PORT_ID);
113
114 instancePortStore.createInstancePort(instancePort);
115 log.info(String.format(MSG_INSTANCE_PORT, instancePort.portId(),
116 MSG_CREATED));
117 }
118
119 @Override
120 public void updateInstancePort(InstancePort instancePort) {
121 checkNotNull(instancePort, ERR_NULL_INSTANCE_PORT);
122 checkArgument(!Strings.isNullOrEmpty(instancePort.portId()),
123 ERR_NULL_INSTANCE_PORT_ID);
124
125 instancePortStore.updateInstancePort(instancePort);
126 log.info(String.format(MSG_INSTANCE_PORT, instancePort.portId(), MSG_UPDATED));
127 }
128
129 @Override
130 public void removeInstancePort(String portId) {
131 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_INSTANCE_PORT_ID);
132
133 synchronized (this) {
134 if (isInstancePortInUse(portId)) {
135 final String error =
136 String.format(MSG_INSTANCE_PORT, portId, ERR_IN_USE);
137 throw new IllegalStateException(error);
138 }
139 InstancePort instancePort = instancePortStore.removeInstancePort(portId);
140 if (instancePort != null) {
141 log.info(String.format(MSG_INSTANCE_PORT, instancePort.portId(), MSG_REMOVED));
142 }
143 }
144 }
145
146 @Override
147 public void clear() {
148 instancePortStore.clear();
149 }
150
151 @Override
152 public InstancePort instancePort(MacAddress macAddress) {
153 checkNotNull(macAddress, ERR_NULL_MAC_ADDRESS);
154
155 return instancePortStore.instancePorts().stream()
156 .filter(port -> port.macAddress().equals(macAddress))
157 .findFirst().orElse(null);
158 }
159
160 @Override
161 public InstancePort instancePort(IpAddress ipAddress, String osNetId) {
162 checkNotNull(ipAddress, ERR_NULL_IP_ADDRESS);
163 checkNotNull(osNetId, ERR_NULL_NETWORK_ID);
164
165 return instancePortStore.instancePorts().stream()
166 .filter(port -> port.networkId().equals(osNetId))
167 .filter(port -> port.ipAddress().equals(ipAddress))
168 .findFirst().orElse(null);
169 }
170
171 @Override
172 public InstancePort instancePort(String portId) {
173 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_INSTANCE_PORT_ID);
174
175 return instancePortStore.instancePort(portId);
176 }
177
178 @Override
179 public Set<InstancePort> instancePorts() {
180 Set<InstancePort> ports = instancePortStore.instancePorts();
181
182 return ImmutableSet.copyOf(ports);
183 }
184
185 @Override
186 public Set<InstancePort> instancePorts(String osNetId) {
187 checkNotNull(osNetId, ERR_NULL_NETWORK_ID);
188
189 Set<InstancePort> ports = instancePortStore.instancePorts().stream()
190 .filter(port -> port.networkId().equals(osNetId))
191 .collect(Collectors.toSet());
192
193 return ImmutableSet.copyOf(ports);
194 }
195
196 @Override
197 public void migrationPortAdded(InstancePort port) {
198 // TODO need to be removed
199 }
200
201 @Override
202 public void migrationPortRemoved(InstancePort port) {
203 // TODO need to be removed
204 }
205
206 private boolean isInstancePortInUse(String portId) {
207 // TODO add checking logic
208 return false;
209 }
210
211 private class InternalInstancePortStoreDelegate implements InstancePortStoreDelegate {
212
213 @Override
214 public void notify(InstancePortEvent event) {
215 if (event != null) {
216 log.trace("send instance port event {}", event);
217 process(event);
218 }
219 }
220 }
221
222 /**
223 * An internal listener that listens host event generated by HostLocationTracker
224 * in DistributedHostStore. The role of this listener is to convert host event
225 * to instance port event and post to the subscribers that have interested on
226 * this type of event.
227 */
228 private class InternalHostListener implements HostListener {
229
230 @Override
231 public boolean isRelevant(HostEvent event) {
232 Host host = event.subject();
233 if (!isValidHost(host)) {
234 log.debug("Invalid host detected, ignore it {}", host);
235 return false;
236 }
237 return true;
238 }
239
240 @Override
241 public void event(HostEvent event) {
242 InstancePort instPort = DefaultInstancePort.from(event.subject(), ACTIVE);
243
244 switch (event.type()) {
245 case HOST_UPDATED:
246 updateInstancePort(instPort);
247 break;
248 case HOST_ADDED:
249 createInstancePort(instPort);
250 break;
251 case HOST_REMOVED:
252 removeInstancePort(instPort.portId());
253 break;
254 case HOST_MOVED:
255 // TODO: require implementation for VM migration case
256 break;
257 default:
258 break;
259 }
260 }
261
262 private boolean isValidHost(Host host) {
263 return !host.ipAddresses().isEmpty() &&
264 host.annotations().value(ANNOTATION_NETWORK_ID) != null &&
265 host.annotations().value(ANNOTATION_PORT_ID) != null;
266 }
267 }
268}