blob: 808f2e04f8cd6574a6f15de16988670639b98b4f [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present 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
Daniel Park23193902016-03-24 18:17:19 +090018import com.google.common.collect.ImmutableList;
sangho0c2a3da2016-02-16 13:39:07 +090019import com.google.common.collect.ImmutableMap;
Daniel Park5df65182016-01-09 00:12:03 +090020import com.google.common.collect.Maps;
sanghoshin94872a12015-10-16 18:04:34 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.packet.Ethernet;
sanghoshin94872a12015-10-16 18:04:34 +090028import org.onlab.packet.Ip4Address;
sanghoshin94872a12015-10-16 18:04:34 +090029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
danielbb83ebc2015-10-29 15:13:06 +090031import org.onosproject.dhcp.DhcpService;
sanghoshin65723ae2015-11-17 22:07:21 +090032import org.onosproject.event.AbstractEvent;
sanghoshin94872a12015-10-16 18:04:34 +090033import org.onosproject.net.Device;
sanghoshin46c6e3e2015-12-18 18:42:17 +090034import org.onosproject.net.DeviceId;
sanghoshin94872a12015-10-16 18:04:34 +090035import org.onosproject.net.Port;
Daniel Park23193902016-03-24 18:17:19 +090036import org.onosproject.net.config.ConfigFactory;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigListener;
39import org.onosproject.net.config.NetworkConfigRegistry;
40import org.onosproject.net.config.NetworkConfigService;
sanghoshin94872a12015-10-16 18:04:34 +090041import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
43import org.onosproject.net.device.DeviceService;
sanghoshinf25d2e02015-11-11 23:07:17 +090044import org.onosproject.net.driver.DriverService;
sanghoshin94872a12015-10-16 18:04:34 +090045import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghoshin65723ae2015-11-17 22:07:21 +090046import org.onosproject.net.host.HostEvent;
47import org.onosproject.net.host.HostListener;
48import org.onosproject.net.host.HostService;
sanghoshin94872a12015-10-16 18:04:34 +090049import org.onosproject.net.packet.InboundPacket;
50import org.onosproject.net.packet.PacketContext;
51import org.onosproject.net.packet.PacketProcessor;
52import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090053import org.onosproject.openstackinterface.OpenstackInterfaceService;
54import org.onosproject.openstackinterface.OpenstackNetwork;
55import org.onosproject.openstackinterface.OpenstackPort;
56import org.onosproject.openstackinterface.OpenstackSecurityGroup;
57import org.onosproject.openstackinterface.OpenstackSubnet;
sangho0c2a3da2016-02-16 13:39:07 +090058import org.onosproject.openstacknetworking.OpenstackPortInfo;
sangho48907542016-03-28 16:07:07 +090059import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
60import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
sangho0c2a3da2016-02-16 13:39:07 +090061import 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;
sanghoshin94872a12015-10-16 18:04:34 +090067import java.util.concurrent.ExecutorService;
68import java.util.concurrent.Executors;
sanghoshin46297d22015-11-03 17:51:24 +090069
sanghoshinf6735b22015-12-17 18:23:53 +090070import static org.onlab.util.Tools.groupedThreads;
sanghoshin94872a12015-10-16 18:04:34 +090071
sanghoshin94872a12015-10-16 18:04:34 +090072@Service
73@Component(immediate = true)
74/**
sanghoshin46297d22015-11-03 17:51:24 +090075 * Populates forwarding rules for VMs created by Openstack.
sanghoshin94872a12015-10-16 18:04:34 +090076 */
77public class OpenstackSwitchingManager implements OpenstackSwitchingService {
78
Daniel Park23193902016-03-24 18:17:19 +090079 private final Logger log = LoggerFactory.getLogger(getClass());
sanghoshin94872a12015-10-16 18:04:34 +090080
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected CoreService coreService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PacketService packetService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin65723ae2015-11-17 22:07:21 +090091 protected HostService hostService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin94872a12015-10-16 18:04:34 +090094 protected FlowObjectiveService flowObjectiveService;
95
danielbb83ebc2015-10-29 15:13:06 +090096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +090097 protected DhcpService dhcpService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +0900100 protected DriverService driverService;
sanghoshin94872a12015-10-16 18:04:34 +0900101
Daniel Park81a61a12016-02-26 08:24:44 +0900102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho48907542016-03-28 16:07:07 +0900103 protected NetworkConfigRegistry networkConfig;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +0900106 protected OpenstackInterfaceService openstackService;
Daniel Park3a06c522016-01-28 20:51:12 +0900107
Daniel Park23193902016-03-24 18:17:19 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected NetworkConfigService configService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected NetworkConfigRegistry configRegistry;
113
sanghoshin46c6e3e2015-12-18 18:42:17 +0900114 public static final String PORTNAME_PREFIX_VM = "tap";
sangho3623cb62016-01-15 22:06:38 +0900115 public static final String PORTNAME_PREFIX_ROUTER = "qr-";
sanghoshin46c6e3e2015-12-18 18:42:17 +0900116 public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
117 public static final String PORTNAME = "portName";
Daniel Park3a06c522016-01-28 20:51:12 +0900118 private static final String ROUTER_INTERFACE = "network:router_interface";
sangho3623cb62016-01-15 22:06:38 +0900119 public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
Daniel Park23193902016-03-24 18:17:19 +0900120 public static final String DNS_SERVER_IP = "8.8.8.8";
121 private static final String FORWARD_SLASH = "/";
122
sangho3623cb62016-01-15 22:06:38 +0900123
sanghoshin94872a12015-10-16 18:04:34 +0900124 private ApplicationId appId;
sangho90088532016-02-25 18:06:12 +0900125
126 private OpenstackArpHandler arpHandler;
127 private OpenstackSecurityGroupRulePopulator sgRulePopulator;
danielbb83ebc2015-10-29 15:13:06 +0900128
Daniel Park23193902016-03-24 18:17:19 +0900129 private ExecutorService deviceEventExecutorService =
sanghoshinf6735b22015-12-17 18:23:53 +0900130 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
sanghoshin94872a12015-10-16 18:04:34 +0900131
Daniel Park23193902016-03-24 18:17:19 +0900132 private ExecutorService configEventExecutorService =
133 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
134
sanghoshin94872a12015-10-16 18:04:34 +0900135 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
136 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sanghoshin65723ae2015-11-17 22:07:21 +0900137 private InternalHostListener internalHostListener = new InternalHostListener();
sangho0c2a3da2016-02-16 13:39:07 +0900138
Daniel Park23193902016-03-24 18:17:19 +0900139 private final Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
sangho90088532016-02-25 18:06:12 +0900140 private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
Daniel Park5df65182016-01-09 00:12:03 +0900141
Daniel Park23193902016-03-24 18:17:19 +0900142 private final ConfigFactory configFactory =
sangho48907542016-03-28 16:07:07 +0900143 new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
144 "config") {
Daniel Park23193902016-03-24 18:17:19 +0900145 @Override
sangho48907542016-03-28 16:07:07 +0900146 public OpenstackNetworkingConfig createConfig() {
147 return new OpenstackNetworkingConfig();
Daniel Park23193902016-03-24 18:17:19 +0900148 }
149 };
150 private final NetworkConfigListener configListener = new InternalConfigListener();
151
sangho48907542016-03-28 16:07:07 +0900152 private OpenstackNetworkingConfig config;
Daniel Park23193902016-03-24 18:17:19 +0900153
sanghoshin94872a12015-10-16 18:04:34 +0900154 @Activate
155 protected void activate() {
156 appId = coreService
157 .registerApplication("org.onosproject.openstackswitching");
sanghoshinf25d2e02015-11-11 23:07:17 +0900158
sanghoshin94872a12015-10-16 18:04:34 +0900159 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
160 deviceService.addListener(internalDeviceListener);
sanghoshin65723ae2015-11-17 22:07:21 +0900161 hostService.addListener(internalHostListener);
Daniel Park23193902016-03-24 18:17:19 +0900162 configRegistry.registerConfigFactory(configFactory);
163 configService.addListener(configListener);
danielbb83ebc2015-10-29 15:13:06 +0900164
sangho48907542016-03-28 16:07:07 +0900165 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
166 sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
167
168 networkConfig.registerConfigFactory(configFactory);
169 networkConfig.addListener(configListener);
170
Daniel Park23193902016-03-24 18:17:19 +0900171 readConfiguration();
sanghoshin46297d22015-11-03 17:51:24 +0900172
sanghoshin94872a12015-10-16 18:04:34 +0900173 log.info("Started");
174 }
175
176 @Deactivate
177 protected void deactivate() {
178 packetService.removeProcessor(internalPacketProcessor);
179 deviceService.removeListener(internalDeviceListener);
180
Daniel Park23193902016-03-24 18:17:19 +0900181 deviceEventExecutorService.shutdown();
182 configEventExecutorService.shutdown();
183 hostService.removeListener(internalHostListener);
184 configService.removeListener(configListener);
185 configRegistry.unregisterConfigFactory(configFactory);
sanghoshin94872a12015-10-16 18:04:34 +0900186
187 log.info("Stopped");
188 }
189
190 @Override
191 public void createPorts(OpenstackPort openstackPort) {
Daniel Park3a06c522016-01-28 20:51:12 +0900192
193 if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
Daniel Park23193902016-03-24 18:17:19 +0900194 && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)
195 && !openstackPort.fixedIps().isEmpty()) {
Daniel Park3a06c522016-01-28 20:51:12 +0900196 registerDhcpInfo(openstackPort);
sanghof2ca7e5c2015-12-23 16:02:43 +0900197 }
sanghoshin94872a12015-10-16 18:04:34 +0900198 }
199
200 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900201 public void removePort(String uuid) {
sangho3623cb62016-01-15 22:06:38 +0900202 // When VMs are remvoed, the flow rules for the VMs are removed using ONOS port update event.
203 // But, when router is removed, no ONOS port event occurs and we need to use Neutron port event.
204 // Here we should not touch any rules for VMs.
205 log.debug("port {} was removed", uuid);
sanghoshin94872a12015-10-16 18:04:34 +0900206
sangho3623cb62016-01-15 22:06:38 +0900207 String routerPortName = PORTNAME_PREFIX_ROUTER + uuid.substring(0, 11);
208 OpenstackPortInfo routerPortInfo = openstackPortInfoMap.get(routerPortName);
209 if (routerPortInfo != null) {
210 dhcpService.removeStaticMapping(routerPortInfo.mac());
sangho93447f12016-02-24 00:33:22 +0900211 deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
Daniel Park23193902016-03-24 18:17:19 +0900212 String pName = port.annotations().value(PORTNAME);
sangho93447f12016-02-24 00:33:22 +0900213 if (pName.equals(routerPortName)) {
214 OpenstackSwitchingRulePopulator rulePopulator =
215 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900216 deviceService, openstackService, driverService, config);
sangho3623cb62016-01-15 22:06:38 +0900217
sangho93447f12016-02-24 00:33:22 +0900218 rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
219 openstackPortInfoMap.remove(routerPortName);
220 return;
221 }
222 });
sangho3623cb62016-01-15 22:06:38 +0900223 }
sanghoshin94872a12015-10-16 18:04:34 +0900224 }
225
226 @Override
sanghoshin65723ae2015-11-17 22:07:21 +0900227 public void updatePort(OpenstackPort openstackPort) {
sangho90088532016-02-25 18:06:12 +0900228 if (openstackPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
229 String portName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
230 OpenstackPortInfo osPortInfo = openstackPortInfoMap.get(portName);
231 if (osPortInfo != null) {
232 // Remove all security group rules based on the ones stored in security group map.
233 osPortInfo.securityGroups().stream().forEach(
234 sgId -> sgRulePopulator.removeSecurityGroupRules(osPortInfo.deviceId(), sgId,
235 osPortInfo.ip(), openstackPortInfoMap, securityGroupMap));
236 // Add all security group rules based on the updated security group.
237 openstackPort.securityGroups().stream().forEach(
238 sgId -> sgRulePopulator.populateSecurityGroupRules(osPortInfo.deviceId(), sgId,
239 osPortInfo.ip(), openstackPortInfoMap));
240 updatePortMap(osPortInfo.deviceId(), portName, openstackService.networks(),
241 openstackService.subnets(), openstackPort);
242 }
243 }
sanghoshin94872a12015-10-16 18:04:34 +0900244 }
245
246 @Override
247 public void createNetwork(OpenstackNetwork openstackNetwork) {
Daniel Park81a61a12016-02-26 08:24:44 +0900248 //TODO
sanghoshin94872a12015-10-16 18:04:34 +0900249 }
250
danielbb83ebc2015-10-29 15:13:06 +0900251 @Override
252 public void createSubnet(OpenstackSubnet openstackSubnet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900253 //TODO
danielbb83ebc2015-10-29 15:13:06 +0900254 }
255
sanghoshin46297d22015-11-03 17:51:24 +0900256 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900257 public Map<String, OpenstackPortInfo> openstackPortInfo() {
258 return ImmutableMap.copyOf(this.openstackPortInfoMap);
Daniel Park3a06c522016-01-28 20:51:12 +0900259 }
260
Daniel Park5df65182016-01-09 00:12:03 +0900261 private void processPortUpdated(Device device, Port port) {
sangho90088532016-02-25 18:06:12 +0900262 String portName = port.annotations().value(PORTNAME);
263 synchronized (openstackPortInfoMap) {
264 if (portName.startsWith(PORTNAME_PREFIX_VM)) {
265 if (port.isEnabled()) {
266 OpenstackSwitchingRulePopulator rulePopulator =
267 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900268 deviceService, openstackService, driverService, config);
Daniel Park3a06c522016-01-28 20:51:12 +0900269
sangho90088532016-02-25 18:06:12 +0900270 rulePopulator.populateSwitchingRules(device, port);
271 OpenstackPort openstackPort = rulePopulator.openstackPort(port);
272 Ip4Address vmIp = (Ip4Address) openstackPort.fixedIps().values().stream()
273 .findAny().orElseGet(null);
274 openstackPort.securityGroups().stream().forEach(
275 sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(), sgId, vmIp,
276 openstackPortInfoMap));
277 updatePortMap(device.id(), port.annotations().value(PORTNAME),
278 openstackService.networks(), openstackService.subnets(), openstackPort);
Daniel Park3a06c522016-01-28 20:51:12 +0900279
sangho90088532016-02-25 18:06:12 +0900280 //In case portupdate event is driven by vm shutoff from openstack
281 } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
Daniel Park23193902016-03-24 18:17:19 +0900282 log.debug("Flowrules according to the port {} were removed", port.number());
sangho90088532016-02-25 18:06:12 +0900283 OpenstackSwitchingRulePopulator rulePopulator =
284 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900285 deviceService, openstackService, driverService, config);
sangho90088532016-02-25 18:06:12 +0900286 rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
287 openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
288 sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
289 openstackPortInfoMap.get(portName).ip(), openstackPortInfoMap, securityGroupMap));
290 dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
291 openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
292 }
Daniel Park5df65182016-01-09 00:12:03 +0900293 }
sanghoshin94872a12015-10-16 18:04:34 +0900294 }
295 }
296
Daniel Park23193902016-03-24 18:17:19 +0900297 private void processPortRemoved(Port port) {
danielbb83ebc2015-10-29 15:13:06 +0900298 log.debug("port {} is removed", port.toString());
sanghoshin94872a12015-10-16 18:04:34 +0900299 }
300
sanghoshin075e3e72015-11-25 16:34:29 +0900301 private void initializeFlowRules() {
302 OpenstackSwitchingRulePopulator rulePopulator =
303 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900304 deviceService, openstackService, driverService, config);
sanghoshin075e3e72015-11-25 16:34:29 +0900305
sangho0c2a3da2016-02-16 13:39:07 +0900306 Collection<OpenstackNetwork> networks = openstackService.networks();
307 Collection<OpenstackSubnet> subnets = openstackService.subnets();
sanghoshin46c6e3e2015-12-18 18:42:17 +0900308
sanghoshin075e3e72015-11-25 16:34:29 +0900309 deviceService.getDevices().forEach(device -> {
sangho90088532016-02-25 18:06:12 +0900310 log.debug("device {} num of ports {} ", device.id(),
311 deviceService.getPorts(device.id()).size());
312 deviceService.getPorts(device.id()).stream()
313 .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
314 port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
315 .forEach(vmPort -> {
316 OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
317 if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
318 rulePopulator.populateSwitchingRules(device, vmPort);
319 Ip4Address vmIp = (Ip4Address) osPort.fixedIps().values().stream()
320 .findAny().orElseGet(null);
321 osPort.securityGroups().stream().forEach(
322 sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(),
323 sgId, vmIp, openstackPortInfoMap));
324 updatePortMap(device.id(), vmPort.annotations().value(PORTNAME), networks,
325 subnets, osPort);
326 registerDhcpInfo(osPort);
327 } else {
328 log.warn("No openstackPort information for port {}", vmPort);
329 }
330 }
331 );
sanghoshin075e3e72015-11-25 16:34:29 +0900332 }
333 );
334 }
335
sangho90088532016-02-25 18:06:12 +0900336 private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
Daniel Park3a06c522016-01-28 20:51:12 +0900337 Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
Daniel Park81a61a12016-02-26 08:24:44 +0900338 long vni;
339 OpenstackNetwork openstackNetwork = networks.stream()
sanghoshin46c6e3e2015-12-18 18:42:17 +0900340 .filter(n -> n.id().equals(openstackPort.networkId()))
Daniel Park81a61a12016-02-26 08:24:44 +0900341 .findAny().orElse(null);
342 if (openstackNetwork != null) {
343 vni = Long.parseLong(openstackNetwork.segmentId());
344 } else {
345 log.debug("updatePortMap failed because there's no OpenstackNetwork matches {}", openstackPort.networkId());
346 return;
347 }
348
sanghoshin46c6e3e2015-12-18 18:42:17 +0900349
Daniel Park3a06c522016-01-28 20:51:12 +0900350 OpenstackSubnet openstackSubnet = subnets.stream()
351 .filter(n -> n.networkId().equals(openstackPort.networkId()))
352 .findFirst().get();
353
354 Ip4Address gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
355
sanghoshin46c6e3e2015-12-18 18:42:17 +0900356 OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
357 .setDeviceId(deviceId)
358 .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
sangho3623cb62016-01-15 22:06:38 +0900359 .setHostMac(openstackPort.macAddress())
Daniel Park3a06c522016-01-28 20:51:12 +0900360 .setVni(vni)
sangho90088532016-02-25 18:06:12 +0900361 .setGatewayIP(gatewayIPAddress)
Daniel Park81a61a12016-02-26 08:24:44 +0900362 .setNetworkId(openstackPort.networkId())
sangho90088532016-02-25 18:06:12 +0900363 .setSecurityGroups(openstackPort.securityGroups());
sanghoshin46c6e3e2015-12-18 18:42:17 +0900364
sangho90088532016-02-25 18:06:12 +0900365 openstackPortInfoMap.put(portName, portBuilder.build());
366
367 openstackPort.securityGroups().stream().forEach(sgId -> {
368 if (!securityGroupMap.containsKey(sgId)) {
369 securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
370 }
371 });
sanghoshin46c6e3e2015-12-18 18:42:17 +0900372 }
373
sanghoshin46297d22015-11-03 17:51:24 +0900374 private void registerDhcpInfo(OpenstackPort openstackPort) {
Daniel Park23193902016-03-24 18:17:19 +0900375 Ip4Address ip4Address, subnetMask, gatewayIPAddress, dhcpServer, domainServer;
sanghoshin46297d22015-11-03 17:51:24 +0900376 OpenstackSubnet openstackSubnet;
377
Daniel Park5df65182016-01-09 00:12:03 +0900378 ip4Address = (Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null);
sanghoshin46297d22015-11-03 17:51:24 +0900379
sangho0c2a3da2016-02-16 13:39:07 +0900380 openstackSubnet = openstackService.subnets().stream()
sanghoshin46297d22015-11-03 17:51:24 +0900381 .filter(n -> n.networkId().equals(openstackPort.networkId()))
382 .findFirst().get();
383
384 subnetMask = Ip4Address.valueOf(buildSubnetMask(openstackSubnet.cidr()));
385 gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
386 dhcpServer = gatewayIPAddress;
387 // TODO: supports multiple DNS servers
388 if (openstackSubnet.dnsNameservers().isEmpty()) {
Daniel Park23193902016-03-24 18:17:19 +0900389 domainServer = Ip4Address.valueOf(DNS_SERVER_IP);
sanghoshin46297d22015-11-03 17:51:24 +0900390 } else {
391 domainServer = openstackSubnet.dnsNameservers().get(0);
392 }
Daniel Park23193902016-03-24 18:17:19 +0900393 List<Ip4Address> options = ImmutableList.of(subnetMask, dhcpServer, gatewayIPAddress, domainServer);
sanghoshin46297d22015-11-03 17:51:24 +0900394
395 dhcpService.setStaticMapping(openstackPort.macAddress(), ip4Address, true, options);
396 }
397
398 private byte[] buildSubnetMask(String cidr) {
399 int prefix;
Daniel Park23193902016-03-24 18:17:19 +0900400 String[] parts = cidr.split(FORWARD_SLASH);
sanghoshin46297d22015-11-03 17:51:24 +0900401 prefix = Integer.parseInt(parts[1]);
402 int mask = 0xffffffff << (32 - prefix);
403 byte[] bytes = new byte[]{(byte) (mask >>> 24),
404 (byte) (mask >> 16 & 0xff), (byte) (mask >> 8 & 0xff), (byte) (mask & 0xff)};
405
406 return bytes;
407 }
408
sanghoshin94872a12015-10-16 18:04:34 +0900409
sanghoshin94872a12015-10-16 18:04:34 +0900410
411 private class InternalPacketProcessor implements PacketProcessor {
412
413 @Override
414 public void process(PacketContext context) {
sanghoshin94872a12015-10-16 18:04:34 +0900415 if (context.isHandled()) {
416 return;
417 }
418
419 InboundPacket pkt = context.inPacket();
420 Ethernet ethernet = pkt.parsed();
421
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800422 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park3a06c522016-01-28 20:51:12 +0900423 arpHandler.processPacketIn(pkt, openstackPortInfoMap.values());
sanghoshin94872a12015-10-16 18:04:34 +0900424 }
425 }
426 }
427
sanghoshin65723ae2015-11-17 22:07:21 +0900428 private class InternalHostListener implements HostListener {
429
430 @Override
431 public void event(HostEvent hostEvent) {
Daniel Park23193902016-03-24 18:17:19 +0900432 deviceEventExecutorService.execute(new InternalEventHandler(hostEvent));
sanghoshin65723ae2015-11-17 22:07:21 +0900433 }
434 }
435
sanghoshin94872a12015-10-16 18:04:34 +0900436 private class InternalDeviceListener implements DeviceListener {
437
438 @Override
sanghoshin46297d22015-11-03 17:51:24 +0900439 public void event(DeviceEvent deviceEvent) {
Daniel Park23193902016-03-24 18:17:19 +0900440 deviceEventExecutorService.execute(new InternalEventHandler(deviceEvent));
sanghoshin94872a12015-10-16 18:04:34 +0900441 }
442 }
443
444 private class InternalEventHandler implements Runnable {
445
sanghoshin65723ae2015-11-17 22:07:21 +0900446 volatile AbstractEvent event;
sanghoshin94872a12015-10-16 18:04:34 +0900447
sanghoshin65723ae2015-11-17 22:07:21 +0900448 InternalEventHandler(AbstractEvent event) {
449 this.event = event;
sanghoshin94872a12015-10-16 18:04:34 +0900450 }
451
452 @Override
453 public void run() {
sanghoshin46297d22015-11-03 17:51:24 +0900454
sanghoshin65723ae2015-11-17 22:07:21 +0900455 if (event instanceof DeviceEvent) {
456 DeviceEvent deviceEvent = (DeviceEvent) event;
sanghoshin46297d22015-11-03 17:51:24 +0900457
sanghoshin65723ae2015-11-17 22:07:21 +0900458 switch (deviceEvent.type()) {
459 case DEVICE_ADDED:
Daniel Park23193902016-03-24 18:17:19 +0900460 log.debug("device {} is added", deviceEvent.subject().id());
sanghoshin65723ae2015-11-17 22:07:21 +0900461 break;
sanghoshin65723ae2015-11-17 22:07:21 +0900462 case DEVICE_AVAILABILITY_CHANGED:
Daniel Park23193902016-03-24 18:17:19 +0900463 Device device = deviceEvent.subject();
sanghoshin65723ae2015-11-17 22:07:21 +0900464 if (deviceService.isAvailable(device.id())) {
Daniel Park23193902016-03-24 18:17:19 +0900465 log.debug("device {} is added", device.id());
sanghoshin65723ae2015-11-17 22:07:21 +0900466 }
467 break;
468 case PORT_ADDED:
Daniel Park23193902016-03-24 18:17:19 +0900469 processPortUpdated(deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900470 break;
471 case PORT_UPDATED:
Daniel Park23193902016-03-24 18:17:19 +0900472 processPortUpdated(deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900473 break;
474 case PORT_REMOVED:
Daniel Park23193902016-03-24 18:17:19 +0900475 processPortRemoved(deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900476 break;
477 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900478 log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900479 break;
480 }
481 } else if (event instanceof HostEvent) {
482 HostEvent hostEvent = (HostEvent) event;
483
484 switch (hostEvent.type()) {
485 case HOST_REMOVED:
Daniel Park23193902016-03-24 18:17:19 +0900486 log.debug("host {} was removed", hostEvent.subject().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900487 break;
488 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900489 log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900490 break;
491 }
sanghoshin94872a12015-10-16 18:04:34 +0900492 }
493 }
494 }
Daniel Park23193902016-03-24 18:17:19 +0900495
496 private void readConfiguration() {
sangho48907542016-03-28 16:07:07 +0900497 config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
Daniel Park23193902016-03-24 18:17:19 +0900498 if (config == null) {
499 log.error("No configuration found");
500 return;
501 }
502
503 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
504 sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
505
506 initializeFlowRules();
507 }
508
509 private class InternalConfigListener implements NetworkConfigListener {
510
511 @Override
512 public void event(NetworkConfigEvent event) {
sangho48907542016-03-28 16:07:07 +0900513 if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
Daniel Park23193902016-03-24 18:17:19 +0900514 return;
515 }
516
517 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
518 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
519 configEventExecutorService.execute(OpenstackSwitchingManager.this::readConfiguration);
520
Daniel Park23193902016-03-24 18:17:19 +0900521 }
522 }
523 }
Jonathan Hart51539b82015-10-29 09:53:04 -0700524}