blob: 52b04362495fd0455f2645334220c23774336d3e [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
Daniel Park3a06c522016-01-28 20:51:12 +09002 * Copyright 2015-2016 Open Networking Laboratory
sanghoshin94872a12015-10-16 18:04:34 +09003 *
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 */
sangho0c2a3da2016-02-16 13:39:07 +090016package org.onosproject.openstacknetworking.switching;
sanghoshin94872a12015-10-16 18:04:34 +090017
sangho0c2a3da2016-02-16 13:39:07 +090018import com.google.common.collect.ImmutableMap;
sanghoshin46297d22015-11-03 17:51:24 +090019import com.google.common.collect.ImmutableSet;
sanghoshin94872a12015-10-16 18:04:34 +090020import com.google.common.collect.Lists;
Daniel Park5df65182016-01-09 00:12:03 +090021import com.google.common.collect.Maps;
sanghoshin94872a12015-10-16 18:04:34 +090022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
28import org.onlab.packet.Ethernet;
sanghoshin94872a12015-10-16 18:04:34 +090029import org.onlab.packet.Ip4Address;
sanghoshin94872a12015-10-16 18:04:34 +090030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
danielbb83ebc2015-10-29 15:13:06 +090032import org.onosproject.dhcp.DhcpService;
sanghoshin65723ae2015-11-17 22:07:21 +090033import org.onosproject.event.AbstractEvent;
sanghoshin94872a12015-10-16 18:04:34 +090034import org.onosproject.net.Device;
sanghoshin46c6e3e2015-12-18 18:42:17 +090035import org.onosproject.net.DeviceId;
sanghoshin65723ae2015-11-17 22:07:21 +090036import org.onosproject.net.Host;
sanghoshin94872a12015-10-16 18:04:34 +090037import org.onosproject.net.Port;
sanghoshin46297d22015-11-03 17:51:24 +090038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigListener;
41import org.onosproject.net.config.NetworkConfigRegistry;
sanghoshin94872a12015-10-16 18:04:34 +090042import org.onosproject.net.device.DeviceEvent;
43import org.onosproject.net.device.DeviceListener;
44import org.onosproject.net.device.DeviceService;
sanghoshinf25d2e02015-11-11 23:07:17 +090045import org.onosproject.net.driver.DriverService;
sanghoshin94872a12015-10-16 18:04:34 +090046import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghoshin65723ae2015-11-17 22:07:21 +090047import org.onosproject.net.host.HostEvent;
48import org.onosproject.net.host.HostListener;
49import org.onosproject.net.host.HostService;
sanghoshin94872a12015-10-16 18:04:34 +090050import org.onosproject.net.packet.InboundPacket;
51import org.onosproject.net.packet.PacketContext;
52import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
sangho0c2a3da2016-02-16 13:39:07 +090054import org.onosproject.openstacknetworking.OpenstackNetwork;
55import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
56import org.onosproject.openstacknetworking.OpenstackNetworkingService;
57import org.onosproject.openstacknetworking.OpenstackPort;
58import org.onosproject.openstacknetworking.OpenstackPortInfo;
59import org.onosproject.openstacknetworking.OpenstackSecurityGroup;
60import org.onosproject.openstacknetworking.OpenstackSubnet;
61import org.onosproject.openstacknetworking.OpenstackSwitchingService;
sanghoshin94872a12015-10-16 18:04:34 +090062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
sanghoshin94872a12015-10-16 18:04:34 +090064import java.util.List;
sanghoshin46297d22015-11-03 17:51:24 +090065import java.util.Collection;
Daniel Park5df65182016-01-09 00:12:03 +090066import java.util.Map;
sanghoshin46297d22015-11-03 17:51:24 +090067import java.util.Set;
sanghoshin94872a12015-10-16 18:04:34 +090068import java.util.concurrent.ExecutorService;
69import java.util.concurrent.Executors;
sanghoshin46297d22015-11-03 17:51:24 +090070
71import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
sanghoshinf6735b22015-12-17 18:23:53 +090072import static org.onlab.util.Tools.groupedThreads;
sanghoshin94872a12015-10-16 18:04:34 +090073
sanghoshin94872a12015-10-16 18:04:34 +090074@Service
75@Component(immediate = true)
76/**
sanghoshin46297d22015-11-03 17:51:24 +090077 * Populates forwarding rules for VMs created by Openstack.
sanghoshin94872a12015-10-16 18:04:34 +090078 */
79public class OpenstackSwitchingManager implements OpenstackSwitchingService {
80
sangho0c2a3da2016-02-16 13:39:07 +090081 private final Logger log = LoggerFactory
82 .getLogger(getClass());
sanghoshin94872a12015-10-16 18:04:34 +090083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected CoreService coreService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected PacketService packetService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DeviceService deviceService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin65723ae2015-11-17 22:07:21 +090094 protected HostService hostService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin94872a12015-10-16 18:04:34 +090097 protected FlowObjectiveService flowObjectiveService;
98
danielbb83ebc2015-10-29 15:13:06 +090099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +0900100 protected DhcpService dhcpService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin46297d22015-11-03 17:51:24 +0900103 protected NetworkConfigRegistry cfgService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +0900106 protected DriverService driverService;
sanghoshin94872a12015-10-16 18:04:34 +0900107
Daniel Park3a06c522016-01-28 20:51:12 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho0c2a3da2016-02-16 13:39:07 +0900109 protected OpenstackNetworkingService openstackService;
Daniel Park3a06c522016-01-28 20:51:12 +0900110
sanghoshin46c6e3e2015-12-18 18:42:17 +0900111 public static final String PORTNAME_PREFIX_VM = "tap";
sangho3623cb62016-01-15 22:06:38 +0900112 public static final String PORTNAME_PREFIX_ROUTER = "qr-";
sanghoshin46c6e3e2015-12-18 18:42:17 +0900113 public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
114 public static final String PORTNAME = "portName";
Daniel Park3a06c522016-01-28 20:51:12 +0900115 private static final String ROUTER_INTERFACE = "network:router_interface";
sangho3623cb62016-01-15 22:06:38 +0900116 public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
117
sanghoshin94872a12015-10-16 18:04:34 +0900118 private ApplicationId appId;
sanghoshin46297d22015-11-03 17:51:24 +0900119 private boolean doNotPushFlows;
sanghoshinf25d2e02015-11-11 23:07:17 +0900120 private Ip4Address neutronServer;
121 private Ip4Address keystoneServer;
122 private String userName;
123 private String password;
Daniel Park3a06c522016-01-28 20:51:12 +0900124 private String physicalRouterMac;
sanghoshin94872a12015-10-16 18:04:34 +0900125 private OpenstackArpHandler arpHandler;
danielbb83ebc2015-10-29 15:13:06 +0900126
sanghoshinf6735b22015-12-17 18:23:53 +0900127 private ExecutorService deviceEventExcutorService =
128 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
129 private ExecutorService networkEventExcutorService =
130 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
sanghoshin94872a12015-10-16 18:04:34 +0900131
132 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
133 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sanghoshin46297d22015-11-03 17:51:24 +0900134 private InternalConfigListener internalConfigListener = new InternalConfigListener();
sanghoshin65723ae2015-11-17 22:07:21 +0900135 private InternalHostListener internalHostListener = new InternalHostListener();
sangho0c2a3da2016-02-16 13:39:07 +0900136
137
sanghoshin46297d22015-11-03 17:51:24 +0900138 private final Set<ConfigFactory> factories = ImmutableSet.of(
sangho0c2a3da2016-02-16 13:39:07 +0900139 new ConfigFactory<ApplicationId, OpenstackNetworkingConfig>(APP_SUBJECT_FACTORY,
140 OpenstackNetworkingConfig.class,
sanghoshin46297d22015-11-03 17:51:24 +0900141 "openstackswitching") {
142 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900143 public OpenstackNetworkingConfig createConfig() {
144 return new OpenstackNetworkingConfig();
sanghoshin46297d22015-11-03 17:51:24 +0900145 }
146 }
147 );
sanghoshin94872a12015-10-16 18:04:34 +0900148
sangho0c2a3da2016-02-16 13:39:07 +0900149
Daniel Park5df65182016-01-09 00:12:03 +0900150 private Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
151
sanghoshin94872a12015-10-16 18:04:34 +0900152 @Activate
153 protected void activate() {
154 appId = coreService
155 .registerApplication("org.onosproject.openstackswitching");
sanghoshinf25d2e02015-11-11 23:07:17 +0900156
157 factories.forEach(cfgService::registerConfigFactory);
sanghoshin94872a12015-10-16 18:04:34 +0900158 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
159 deviceService.addListener(internalDeviceListener);
sanghoshin65723ae2015-11-17 22:07:21 +0900160 hostService.addListener(internalHostListener);
sanghoshin46297d22015-11-03 17:51:24 +0900161 cfgService.addListener(internalConfigListener);
danielbb83ebc2015-10-29 15:13:06 +0900162
sanghoshinf25d2e02015-11-11 23:07:17 +0900163 internalConfigListener.configureNetwork();
sanghoshin46297d22015-11-03 17:51:24 +0900164
sanghoshin94872a12015-10-16 18:04:34 +0900165 log.info("Started");
166 }
167
168 @Deactivate
169 protected void deactivate() {
170 packetService.removeProcessor(internalPacketProcessor);
171 deviceService.removeListener(internalDeviceListener);
sanghoshin46297d22015-11-03 17:51:24 +0900172 cfgService.removeListener(internalConfigListener);
sanghoshin65723ae2015-11-17 22:07:21 +0900173 factories.forEach(cfgService::unregisterConfigFactory);
sanghoshin94872a12015-10-16 18:04:34 +0900174
175 deviceEventExcutorService.shutdown();
176
177 log.info("Stopped");
178 }
179
180 @Override
181 public void createPorts(OpenstackPort openstackPort) {
Daniel Park3a06c522016-01-28 20:51:12 +0900182
183 if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
184 && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
185 if (!openstackPort.fixedIps().isEmpty()) {
186 registerDhcpInfo(openstackPort);
187 }
sanghof2ca7e5c2015-12-23 16:02:43 +0900188 }
sangho5db8e052016-01-29 16:08:23 +0900189
190 if (!openstackPort.securityGroups().isEmpty()) {
191 openstackPort.securityGroups().forEach(sgId -> {
sangho0c2a3da2016-02-16 13:39:07 +0900192 OpenstackSecurityGroup sg = openstackService.getSecurityGroup(sgId);
sangho5db8e052016-01-29 16:08:23 +0900193 log.debug("SecurityGroup : {}", sg.toString());
194 });
195 }
sanghoshin94872a12015-10-16 18:04:34 +0900196 }
197
198 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900199 public void removePort(String uuid) {
sangho3623cb62016-01-15 22:06:38 +0900200 // When VMs are remvoed, the flow rules for the VMs are removed using ONOS port update event.
201 // But, when router is removed, no ONOS port event occurs and we need to use Neutron port event.
202 // Here we should not touch any rules for VMs.
203 log.debug("port {} was removed", uuid);
sanghoshin94872a12015-10-16 18:04:34 +0900204
sangho3623cb62016-01-15 22:06:38 +0900205 String routerPortName = PORTNAME_PREFIX_ROUTER + uuid.substring(0, 11);
206 OpenstackPortInfo routerPortInfo = openstackPortInfoMap.get(routerPortName);
207 if (routerPortInfo != null) {
208 dhcpService.removeStaticMapping(routerPortInfo.mac());
209 if (!doNotPushFlows) {
210 deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
211 String pName = port.annotations().value("portName");
212 if (pName.equals(routerPortName)) {
213 OpenstackSwitchingRulePopulator rulePopulator =
214 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
sangho0c2a3da2016-02-16 13:39:07 +0900215 deviceService, openstackService, driverService);
sangho3623cb62016-01-15 22:06:38 +0900216
217 rulePopulator.removeSwitchingRules(doNotPushFlows, port, openstackPortInfoMap);
218 openstackPortInfoMap.remove(routerPortName);
219 return;
220 }
221 });
222 }
223 }
sanghoshin94872a12015-10-16 18:04:34 +0900224 }
225
226 @Override
sanghoshin65723ae2015-11-17 22:07:21 +0900227 public void updatePort(OpenstackPort openstackPort) {
sanghoshin94872a12015-10-16 18:04:34 +0900228 }
229
230 @Override
231 public void createNetwork(OpenstackNetwork openstackNetwork) {
sanghoshin94872a12015-10-16 18:04:34 +0900232 }
233
danielbb83ebc2015-10-29 15:13:06 +0900234 @Override
235 public void createSubnet(OpenstackSubnet openstackSubnet) {
danielbb83ebc2015-10-29 15:13:06 +0900236 }
237
sanghoshin46297d22015-11-03 17:51:24 +0900238 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900239 public Map<String, OpenstackPortInfo> openstackPortInfo() {
240 return ImmutableMap.copyOf(this.openstackPortInfoMap);
Daniel Park3a06c522016-01-28 20:51:12 +0900241 }
242
sanghoshin94872a12015-10-16 18:04:34 +0900243 private void processDeviceAdded(Device device) {
danielbb83ebc2015-10-29 15:13:06 +0900244 log.debug("device {} is added", device.id());
sanghoshin94872a12015-10-16 18:04:34 +0900245 }
246
Daniel Park5df65182016-01-09 00:12:03 +0900247 private void processPortUpdated(Device device, Port port) {
sanghoshin46c6e3e2015-12-18 18:42:17 +0900248 if (!port.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL) && !doNotPushFlows) {
249 if (port.isEnabled() || port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER)) {
Daniel Park5df65182016-01-09 00:12:03 +0900250 OpenstackSwitchingRulePopulator rulePopulator =
251 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
sangho0c2a3da2016-02-16 13:39:07 +0900252 deviceService, openstackService, driverService);
Daniel Park3a06c522016-01-28 20:51:12 +0900253
sangho3623cb62016-01-15 22:06:38 +0900254 rulePopulator.populateSwitchingRules(doNotPushFlows, device, port);
sangho0c2a3da2016-02-16 13:39:07 +0900255 updatePortMap(device.id(), port, openstackService.networks(), openstackService.subnets(),
Daniel Park3a06c522016-01-28 20:51:12 +0900256 rulePopulator.openstackPort(port));
257
sanghoshin46c6e3e2015-12-18 18:42:17 +0900258 //In case portupdate event is driven by vm shutoff from openstack
259 } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(port.annotations().value(PORTNAME))) {
Daniel Park5df65182016-01-09 00:12:03 +0900260 log.debug("Flowrules according to the port {} were removed", port.number().toString());
261 OpenstackSwitchingRulePopulator rulePopulator =
262 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
sangho0c2a3da2016-02-16 13:39:07 +0900263 deviceService, openstackService, driverService);
sangho3623cb62016-01-15 22:06:38 +0900264
265 rulePopulator.removeSwitchingRules(doNotPushFlows, port, openstackPortInfoMap);
266 dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
sanghoshin46c6e3e2015-12-18 18:42:17 +0900267 openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
Daniel Park5df65182016-01-09 00:12:03 +0900268 }
sanghoshin94872a12015-10-16 18:04:34 +0900269 }
270 }
271
272 private void processPortRemoved(Device device, Port port) {
danielbb83ebc2015-10-29 15:13:06 +0900273 log.debug("port {} is removed", port.toString());
sanghoshin94872a12015-10-16 18:04:34 +0900274 }
275
sanghoshin075e3e72015-11-25 16:34:29 +0900276 private void initializeFlowRules() {
277 OpenstackSwitchingRulePopulator rulePopulator =
278 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
sangho0c2a3da2016-02-16 13:39:07 +0900279 deviceService, openstackService, driverService);
sanghoshin075e3e72015-11-25 16:34:29 +0900280
sangho0c2a3da2016-02-16 13:39:07 +0900281 Collection<OpenstackNetwork> networks = openstackService.networks();
282 Collection<OpenstackSubnet> subnets = openstackService.subnets();
sanghoshin46c6e3e2015-12-18 18:42:17 +0900283
sanghoshin075e3e72015-11-25 16:34:29 +0900284 deviceService.getDevices().forEach(device -> {
285 log.debug("device {} num of ports {} ", device.id(),
286 deviceService.getPorts(device.id()).size());
287 deviceService.getPorts(device.id()).stream()
sanghoshin46c6e3e2015-12-18 18:42:17 +0900288 .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
289 port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
sanghoshin075e3e72015-11-25 16:34:29 +0900290 .forEach(vmPort -> {
291 OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
sangho3623cb62016-01-15 22:06:38 +0900292 if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
Hyunsun Moonbe5c24c2015-12-10 22:26:35 -0800293 if (!doNotPushFlows) {
sangho3623cb62016-01-15 22:06:38 +0900294 rulePopulator.populateSwitchingRules(doNotPushFlows, device, vmPort);
Daniel Park3a06c522016-01-28 20:51:12 +0900295 updatePortMap(device.id(), vmPort, networks, subnets, osPort);
Hyunsun Moonbe5c24c2015-12-10 22:26:35 -0800296 }
sanghoshin075e3e72015-11-25 16:34:29 +0900297 registerDhcpInfo(osPort);
298 } else {
299 log.warn("No openstackPort information for port {}", vmPort);
300 }
301 }
302 );
303 }
304 );
305 }
306
sanghoshin46c6e3e2015-12-18 18:42:17 +0900307 private void updatePortMap(DeviceId deviceId, Port port, Collection<OpenstackNetwork> networks,
Daniel Park3a06c522016-01-28 20:51:12 +0900308 Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
sanghoshin46c6e3e2015-12-18 18:42:17 +0900309 long vni = Long.parseLong(networks.stream()
310 .filter(n -> n.id().equals(openstackPort.networkId()))
311 .findAny().orElse(null).segmentId());
312
Daniel Park3a06c522016-01-28 20:51:12 +0900313 OpenstackSubnet openstackSubnet = subnets.stream()
314 .filter(n -> n.networkId().equals(openstackPort.networkId()))
315 .findFirst().get();
316
317 Ip4Address gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
318
sanghoshin46c6e3e2015-12-18 18:42:17 +0900319 OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
320 .setDeviceId(deviceId)
321 .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
sangho3623cb62016-01-15 22:06:38 +0900322 .setHostMac(openstackPort.macAddress())
Daniel Park3a06c522016-01-28 20:51:12 +0900323 .setVni(vni)
324 .setGatewayIP(gatewayIPAddress);
sanghoshin46c6e3e2015-12-18 18:42:17 +0900325
326 openstackPortInfoMap.putIfAbsent(port.annotations().value(PORTNAME),
327 portBuilder.build());
328 }
329
sanghoshin65723ae2015-11-17 22:07:21 +0900330 private void processHostRemoved(Host host) {
331 log.debug("host {} was removed", host.toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900332 }
333
sanghoshin46297d22015-11-03 17:51:24 +0900334 private void registerDhcpInfo(OpenstackPort openstackPort) {
335 Ip4Address ip4Address;
336 Ip4Address subnetMask;
sanghoshin46297d22015-11-03 17:51:24 +0900337 Ip4Address gatewayIPAddress;
sanghoshin46c6e3e2015-12-18 18:42:17 +0900338 Ip4Address dhcpServer;
sanghoshin46297d22015-11-03 17:51:24 +0900339 Ip4Address domainServer;
340 OpenstackSubnet openstackSubnet;
341
Daniel Park5df65182016-01-09 00:12:03 +0900342 ip4Address = (Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null);
sanghoshin46297d22015-11-03 17:51:24 +0900343
sangho0c2a3da2016-02-16 13:39:07 +0900344 openstackSubnet = openstackService.subnets().stream()
sanghoshin46297d22015-11-03 17:51:24 +0900345 .filter(n -> n.networkId().equals(openstackPort.networkId()))
346 .findFirst().get();
347
348 subnetMask = Ip4Address.valueOf(buildSubnetMask(openstackSubnet.cidr()));
349 gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
350 dhcpServer = gatewayIPAddress;
351 // TODO: supports multiple DNS servers
352 if (openstackSubnet.dnsNameservers().isEmpty()) {
353 domainServer = Ip4Address.valueOf("8.8.8.8");
354 } else {
355 domainServer = openstackSubnet.dnsNameservers().get(0);
356 }
357 List<Ip4Address> options = Lists.newArrayList();
358 options.add(subnetMask);
359 options.add(dhcpServer);
360 options.add(gatewayIPAddress);
361 options.add(domainServer);
362
363 dhcpService.setStaticMapping(openstackPort.macAddress(), ip4Address, true, options);
364 }
365
366 private byte[] buildSubnetMask(String cidr) {
367 int prefix;
368 String[] parts = cidr.split("/");
369 prefix = Integer.parseInt(parts[1]);
370 int mask = 0xffffffff << (32 - prefix);
371 byte[] bytes = new byte[]{(byte) (mask >>> 24),
372 (byte) (mask >> 16 & 0xff), (byte) (mask >> 8 & 0xff), (byte) (mask & 0xff)};
373
374 return bytes;
375 }
376
sanghoshin94872a12015-10-16 18:04:34 +0900377
sanghoshin94872a12015-10-16 18:04:34 +0900378
379 private class InternalPacketProcessor implements PacketProcessor {
380
381 @Override
382 public void process(PacketContext context) {
sanghoshin94872a12015-10-16 18:04:34 +0900383 if (context.isHandled()) {
384 return;
385 }
386
387 InboundPacket pkt = context.inPacket();
388 Ethernet ethernet = pkt.parsed();
389
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800390 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park3a06c522016-01-28 20:51:12 +0900391 arpHandler.processPacketIn(pkt, openstackPortInfoMap.values());
sanghoshin94872a12015-10-16 18:04:34 +0900392 }
393 }
394 }
395
sanghoshin65723ae2015-11-17 22:07:21 +0900396 private class InternalHostListener implements HostListener {
397
398 @Override
399 public void event(HostEvent hostEvent) {
400 deviceEventExcutorService.execute(new InternalEventHandler(hostEvent));
401 }
402 }
403
sanghoshin94872a12015-10-16 18:04:34 +0900404 private class InternalDeviceListener implements DeviceListener {
405
406 @Override
sanghoshin46297d22015-11-03 17:51:24 +0900407 public void event(DeviceEvent deviceEvent) {
408 deviceEventExcutorService.execute(new InternalEventHandler(deviceEvent));
sanghoshin94872a12015-10-16 18:04:34 +0900409 }
410 }
411
412 private class InternalEventHandler implements Runnable {
413
sanghoshin65723ae2015-11-17 22:07:21 +0900414 volatile AbstractEvent event;
sanghoshin94872a12015-10-16 18:04:34 +0900415
sanghoshin65723ae2015-11-17 22:07:21 +0900416 InternalEventHandler(AbstractEvent event) {
417 this.event = event;
sanghoshin94872a12015-10-16 18:04:34 +0900418 }
419
420 @Override
421 public void run() {
sanghoshin46297d22015-11-03 17:51:24 +0900422
sanghoshin65723ae2015-11-17 22:07:21 +0900423 if (event instanceof DeviceEvent) {
424 DeviceEvent deviceEvent = (DeviceEvent) event;
sanghoshin46297d22015-11-03 17:51:24 +0900425
sanghoshin65723ae2015-11-17 22:07:21 +0900426 switch (deviceEvent.type()) {
427 case DEVICE_ADDED:
428 processDeviceAdded((Device) deviceEvent.subject());
429 break;
sanghoshin65723ae2015-11-17 22:07:21 +0900430 case DEVICE_AVAILABILITY_CHANGED:
431 Device device = (Device) deviceEvent.subject();
432 if (deviceService.isAvailable(device.id())) {
433 processDeviceAdded(device);
434 }
435 break;
436 case PORT_ADDED:
Daniel Park5df65182016-01-09 00:12:03 +0900437 processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900438 break;
439 case PORT_UPDATED:
Daniel Park5df65182016-01-09 00:12:03 +0900440 processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900441 break;
442 case PORT_REMOVED:
443 processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
444 break;
445 default:
446 break;
447 }
448 } else if (event instanceof HostEvent) {
449 HostEvent hostEvent = (HostEvent) event;
450
451 switch (hostEvent.type()) {
452 case HOST_REMOVED:
453 processHostRemoved((Host) hostEvent.subject());
454 break;
455 default:
456 break;
457 }
sanghoshin94872a12015-10-16 18:04:34 +0900458 }
459 }
460 }
461
sanghoshin46297d22015-11-03 17:51:24 +0900462 private class InternalConfigListener implements NetworkConfigListener {
463
sanghoshinf25d2e02015-11-11 23:07:17 +0900464 public void configureNetwork() {
sangho0c2a3da2016-02-16 13:39:07 +0900465 OpenstackNetworkingConfig cfg =
466 cfgService.getConfig(appId, OpenstackNetworkingConfig.class);
sanghoshinf25d2e02015-11-11 23:07:17 +0900467 if (cfg == null) {
468 log.error("There is no openstack server information in config.");
469 return;
470 }
sangho0c2a3da2016-02-16 13:39:07 +0900471
sanghoshinf25d2e02015-11-11 23:07:17 +0900472 doNotPushFlows = cfg.doNotPushFlows();
Daniel Park3a06c522016-01-28 20:51:12 +0900473 physicalRouterMac = cfg.physicalRouterMac();
sangho0c2a3da2016-02-16 13:39:07 +0900474 openstackService.setConfigurations(cfg.neutronServer(), cfg.keystoneServer(),
475 cfg.userName(), cfg.password());
476 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
sanghoshin075e3e72015-11-25 16:34:29 +0900477 initializeFlowRules();
sanghoshinf25d2e02015-11-11 23:07:17 +0900478 }
479
sanghoshin46297d22015-11-03 17:51:24 +0900480 @Override
481 public void event(NetworkConfigEvent event) {
482 if (((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
483 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) &&
sangho0c2a3da2016-02-16 13:39:07 +0900484 event.configClass().equals(OpenstackNetworkingConfig.class)) {
485
486 log.info("Network configuration changed");
487 networkEventExcutorService.execute(this::configureNetwork);
sanghoshin46297d22015-11-03 17:51:24 +0900488 }
489 }
sanghoshinf25d2e02015-11-11 23:07:17 +0900490 }
Jonathan Hart51539b82015-10-29 09:53:04 -0700491}