blob: d881d81c8b84dff76f5cfbc7cb5d148e83770876 [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
2 * Copyright 2015 Open Networking Laboratory
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.openstackswitching;
17
sanghoshin46297d22015-11-03 17:51:24 +090018import com.google.common.collect.ImmutableSet;
sanghoshin94872a12015-10-16 18:04:34 +090019import com.google.common.collect.Lists;
sanghoshin94872a12015-10-16 18:04:34 +090020import 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.Ethernet;
sanghoshin94872a12015-10-16 18:04:34 +090027import org.onlab.packet.Ip4Address;
sanghoshin94872a12015-10-16 18:04:34 +090028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
danielbb83ebc2015-10-29 15:13:06 +090030import org.onosproject.dhcp.DhcpService;
sanghoshin94872a12015-10-16 18:04:34 +090031import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Port;
sanghoshin46297d22015-11-03 17:51:24 +090034import org.onosproject.net.config.ConfigFactory;
35import org.onosproject.net.config.NetworkConfigEvent;
36import org.onosproject.net.config.NetworkConfigListener;
37import org.onosproject.net.config.NetworkConfigRegistry;
sanghoshin94872a12015-10-16 18:04:34 +090038import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
40import org.onosproject.net.device.DeviceService;
sanghoshinf25d2e02015-11-11 23:07:17 +090041import org.onosproject.net.driver.DriverService;
sanghoshin94872a12015-10-16 18:04:34 +090042import org.onosproject.net.flowobjective.FlowObjectiveService;
43import org.onosproject.net.packet.InboundPacket;
44import org.onosproject.net.packet.PacketContext;
45import org.onosproject.net.packet.PacketProcessor;
46import org.onosproject.net.packet.PacketService;
47import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
sanghoshin94872a12015-10-16 18:04:34 +090049import java.util.List;
sanghoshin46297d22015-11-03 17:51:24 +090050import java.util.Collection;
51import java.util.Set;
sanghoshin94872a12015-10-16 18:04:34 +090052import java.util.concurrent.ExecutorService;
53import java.util.concurrent.Executors;
sanghoshin46297d22015-11-03 17:51:24 +090054import java.util.stream.Collectors;
55
56import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
sanghoshin94872a12015-10-16 18:04:34 +090057
58@SuppressWarnings("ALL")
59@Service
60@Component(immediate = true)
61/**
sanghoshin46297d22015-11-03 17:51:24 +090062 * Populates forwarding rules for VMs created by Openstack.
sanghoshin94872a12015-10-16 18:04:34 +090063 */
64public class OpenstackSwitchingManager implements OpenstackSwitchingService {
65
66 private static Logger log = LoggerFactory
67 .getLogger(OpenstackSwitchingManager.class);
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected CoreService coreService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected PacketService packetService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DeviceService deviceService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected FlowObjectiveService flowObjectiveService;
80
danielbb83ebc2015-10-29 15:13:06 +090081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +090082 protected DhcpService dhcpService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin46297d22015-11-03 17:51:24 +090085 protected NetworkConfigRegistry cfgService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +090088 protected DriverService driverService;
sanghoshin94872a12015-10-16 18:04:34 +090089
90 private ApplicationId appId;
sanghoshin46297d22015-11-03 17:51:24 +090091 private boolean doNotPushFlows;
sanghoshinf25d2e02015-11-11 23:07:17 +090092 private Ip4Address neutronServer;
93 private Ip4Address keystoneServer;
94 private String userName;
95 private String password;
sanghoshin94872a12015-10-16 18:04:34 +090096 private OpenstackArpHandler arpHandler;
sanghoshinf25d2e02015-11-11 23:07:17 +090097 private OpenstackRestHandler restHandler;
danielbb83ebc2015-10-29 15:13:06 +090098
sanghoshin94872a12015-10-16 18:04:34 +090099 private ExecutorService deviceEventExcutorService = Executors.newFixedThreadPool(10);
100
101 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
102 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sanghoshin46297d22015-11-03 17:51:24 +0900103 private InternalConfigListener internalConfigListener = new InternalConfigListener();
104 private final Set<ConfigFactory> factories = ImmutableSet.of(
105 new ConfigFactory<ApplicationId, OpenstackSwitchingConfig>(APP_SUBJECT_FACTORY,
106 OpenstackSwitchingConfig.class,
107 "openstackswitching") {
108 @Override
109 public OpenstackSwitchingConfig createConfig() {
110 return new OpenstackSwitchingConfig();
111 }
112 }
113 );
sanghoshin94872a12015-10-16 18:04:34 +0900114
115 @Activate
116 protected void activate() {
117 appId = coreService
118 .registerApplication("org.onosproject.openstackswitching");
sanghoshinf25d2e02015-11-11 23:07:17 +0900119
120 factories.forEach(cfgService::registerConfigFactory);
sanghoshin94872a12015-10-16 18:04:34 +0900121 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
122 deviceService.addListener(internalDeviceListener);
sanghoshin46297d22015-11-03 17:51:24 +0900123 cfgService.addListener(internalConfigListener);
danielbb83ebc2015-10-29 15:13:06 +0900124
sanghoshinf25d2e02015-11-11 23:07:17 +0900125 internalConfigListener.configureNetwork();
sanghoshin46297d22015-11-03 17:51:24 +0900126
sanghoshin94872a12015-10-16 18:04:34 +0900127 log.info("Started");
128 }
129
130 @Deactivate
131 protected void deactivate() {
132 packetService.removeProcessor(internalPacketProcessor);
133 deviceService.removeListener(internalDeviceListener);
sanghoshin46297d22015-11-03 17:51:24 +0900134 cfgService.removeListener(internalConfigListener);
sanghoshin94872a12015-10-16 18:04:34 +0900135
136 deviceEventExcutorService.shutdown();
137
138 log.info("Stopped");
139 }
140
141 @Override
142 public void createPorts(OpenstackPort openstackPort) {
sanghoshin46297d22015-11-03 17:51:24 +0900143 registerDhcpInfo(openstackPort);
sanghoshin94872a12015-10-16 18:04:34 +0900144 }
145
146 @Override
147 public void deletePorts() {
148
149 }
150
151 @Override
152 public void updatePorts() {
153
154 }
155
156 @Override
157 public void createNetwork(OpenstackNetwork openstackNetwork) {
sanghoshin94872a12015-10-16 18:04:34 +0900158 }
159
danielbb83ebc2015-10-29 15:13:06 +0900160 @Override
161 public void createSubnet(OpenstackSubnet openstackSubnet) {
danielbb83ebc2015-10-29 15:13:06 +0900162 }
163
sanghoshin46297d22015-11-03 17:51:24 +0900164 @Override
165 public Collection<OpenstackPort> ports(String networkId) {
sanghoshinf25d2e02015-11-11 23:07:17 +0900166 Collection<OpenstackPort> ports = restHandler.getPorts();
167 List<OpenstackPort> portList = ports.stream()
sanghoshin46297d22015-11-03 17:51:24 +0900168 .filter(p -> p.networkId().equals(networkId))
169 .collect(Collectors.toList());
170
171 return portList;
172 }
173
174 @Override
sanghoshinf25d2e02015-11-11 23:07:17 +0900175 public OpenstackPort port(Port port) {
176 Collection<OpenstackPort> ports = restHandler.getPorts();
177 String uuid = port.annotations().value("portName").substring(3);
178 return ports.stream()
sanghoshin46297d22015-11-03 17:51:24 +0900179 .filter(p -> p.id().startsWith(uuid))
sanghoshinf25d2e02015-11-11 23:07:17 +0900180 .findFirst().orElse(null);
181 }
182
183 @Override
184 public OpenstackPort port(String portId) {
185 Collection<OpenstackPort> ports = restHandler.getPorts();
186 return ports.stream()
187 .filter(p -> p.id().equals(portId))
188 .findFirst().orElse(null);
sanghoshin46297d22015-11-03 17:51:24 +0900189 }
190
191 @Override
192 public OpenstackNetwork network(String networkId) {
sanghoshinf25d2e02015-11-11 23:07:17 +0900193 Collection<OpenstackNetwork> networks = restHandler.getNetworks();
194 return networks.stream()
195 .filter(n -> n.id().equals(networkId))
196 .findFirst().orElse(null);
sanghoshin46297d22015-11-03 17:51:24 +0900197 }
198
sanghoshin94872a12015-10-16 18:04:34 +0900199 private void processDeviceAdded(Device device) {
danielbb83ebc2015-10-29 15:13:06 +0900200 log.debug("device {} is added", device.id());
sanghoshin94872a12015-10-16 18:04:34 +0900201 }
202
203 private void processPortAdded(Device device, Port port) {
sanghoshinf25d2e02015-11-11 23:07:17 +0900204 if (!port.annotations().value("portName").equals("vxlan")) {
205 OpenstackSwitchingRulePopulator rulePopulator =
206 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
207 deviceService, restHandler, driverService);
208 rulePopulator.populateSwitchingRules(device, port);
sanghoshin94872a12015-10-16 18:04:34 +0900209 }
210 }
211
212 private void processPortRemoved(Device device, Port port) {
sanghoshinf25d2e02015-11-11 23:07:17 +0900213 // TODO: Remove flow rules for the VM removed
danielbb83ebc2015-10-29 15:13:06 +0900214 log.debug("port {} is removed", port.toString());
sanghoshin94872a12015-10-16 18:04:34 +0900215 }
216
sanghoshin46297d22015-11-03 17:51:24 +0900217 private void registerDhcpInfo(OpenstackPort openstackPort) {
218 Ip4Address ip4Address;
219 Ip4Address subnetMask;
220 Ip4Address dhcpServer;
221 Ip4Address gatewayIPAddress;
222 Ip4Address domainServer;
223 OpenstackSubnet openstackSubnet;
224
225 ip4Address = (Ip4Address) openstackPort.fixedIps().values().toArray()[0];
226
sanghoshinf25d2e02015-11-11 23:07:17 +0900227 openstackSubnet = restHandler.getSubnets().stream()
sanghoshin46297d22015-11-03 17:51:24 +0900228 .filter(n -> n.networkId().equals(openstackPort.networkId()))
229 .findFirst().get();
230
231 subnetMask = Ip4Address.valueOf(buildSubnetMask(openstackSubnet.cidr()));
232 gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
233 dhcpServer = gatewayIPAddress;
234 // TODO: supports multiple DNS servers
235 if (openstackSubnet.dnsNameservers().isEmpty()) {
236 domainServer = Ip4Address.valueOf("8.8.8.8");
237 } else {
238 domainServer = openstackSubnet.dnsNameservers().get(0);
239 }
240 List<Ip4Address> options = Lists.newArrayList();
241 options.add(subnetMask);
242 options.add(dhcpServer);
243 options.add(gatewayIPAddress);
244 options.add(domainServer);
245
246 dhcpService.setStaticMapping(openstackPort.macAddress(), ip4Address, true, options);
247 }
248
249 private byte[] buildSubnetMask(String cidr) {
250 int prefix;
251 String[] parts = cidr.split("/");
252 prefix = Integer.parseInt(parts[1]);
253 int mask = 0xffffffff << (32 - prefix);
254 byte[] bytes = new byte[]{(byte) (mask >>> 24),
255 (byte) (mask >> 16 & 0xff), (byte) (mask >> 8 & 0xff), (byte) (mask & 0xff)};
256
257 return bytes;
258 }
259
sanghoshin94872a12015-10-16 18:04:34 +0900260
sanghoshin94872a12015-10-16 18:04:34 +0900261
262 private class InternalPacketProcessor implements PacketProcessor {
263
264 @Override
265 public void process(PacketContext context) {
266
267 if (context.isHandled()) {
268 return;
269 }
270
271 InboundPacket pkt = context.inPacket();
272 Ethernet ethernet = pkt.parsed();
273
274 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
275 arpHandler.processPacketIn(pkt);
sanghoshin94872a12015-10-16 18:04:34 +0900276 }
277 }
278 }
279
280 private class InternalDeviceListener implements DeviceListener {
281
282 @Override
sanghoshin46297d22015-11-03 17:51:24 +0900283 public void event(DeviceEvent deviceEvent) {
284 deviceEventExcutorService.execute(new InternalEventHandler(deviceEvent));
sanghoshin94872a12015-10-16 18:04:34 +0900285 }
286 }
287
288 private class InternalEventHandler implements Runnable {
289
290 volatile DeviceEvent deviceEvent;
291
292 InternalEventHandler(DeviceEvent deviceEvent) {
293 this.deviceEvent = deviceEvent;
294 }
295
296 @Override
297 public void run() {
sanghoshin46297d22015-11-03 17:51:24 +0900298
299 if (doNotPushFlows) {
300 return;
301 }
302
sanghoshin94872a12015-10-16 18:04:34 +0900303 switch (deviceEvent.type()) {
304 case DEVICE_ADDED:
305 processDeviceAdded((Device) deviceEvent.subject());
306 break;
307 case DEVICE_UPDATED:
308 Port port = (Port) deviceEvent.subject();
309 if (port.isEnabled()) {
310 processPortAdded((Device) deviceEvent.subject(), deviceEvent.port());
311 }
312 break;
313 case DEVICE_AVAILABILITY_CHANGED:
314 Device device = (Device) deviceEvent.subject();
315 if (deviceService.isAvailable(device.id())) {
316 processDeviceAdded(device);
317 }
318 break;
319 case PORT_ADDED:
320 processPortAdded((Device) deviceEvent.subject(), deviceEvent.port());
321 break;
322 case PORT_UPDATED:
323 processPortAdded((Device) deviceEvent.subject(), deviceEvent.port());
324 break;
325 case PORT_REMOVED:
326 processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
327 break;
328 default:
329 break;
330 }
331 }
332 }
333
sanghoshin46297d22015-11-03 17:51:24 +0900334 private class InternalConfigListener implements NetworkConfigListener {
335
sanghoshinf25d2e02015-11-11 23:07:17 +0900336 public void configureNetwork() {
337 OpenstackSwitchingConfig cfg =
338 cfgService.getConfig(appId, OpenstackSwitchingConfig.class);
339 if (cfg == null) {
340 log.error("There is no openstack server information in config.");
341 return;
342 }
343 doNotPushFlows = cfg.doNotPushFlows();
344 restHandler = new OpenstackRestHandler(cfg);
345 arpHandler = new OpenstackArpHandler(restHandler, packetService);
346 }
347
sanghoshin46297d22015-11-03 17:51:24 +0900348 @Override
349 public void event(NetworkConfigEvent event) {
350 if (((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
351 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) &&
352 event.configClass().equals(OpenstackSwitchingConfig.class)) {
sanghoshinf25d2e02015-11-11 23:07:17 +0900353 configureNetwork();
sanghoshin46297d22015-11-03 17:51:24 +0900354 }
355 }
sanghoshinf25d2e02015-11-11 23:07:17 +0900356
357 }
sanghoshin46297d22015-11-03 17:51:24 +0900358
sanghoshin94872a12015-10-16 18:04:34 +0900359 private final class PortInfo {
360 DeviceId deviceId;
361 String portName;
362 Ip4Address fixedIp;
363 Ip4Address hostIp;
364
365 private PortInfo(DeviceId deviceId, String portName, Ip4Address fixedIp,
366 Ip4Address hostIp) {
367 this.deviceId = deviceId;
368 this.portName = portName;
369 this.fixedIp = fixedIp;
370 this.hostIp = hostIp;
371 }
372 }
373
374}