blob: 0181bde8b059080117dbc76fe8458f3fbd3557bf [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
sangho0c2a3da2016-02-16 13:39:07 +090018import com.google.common.collect.ImmutableMap;
Daniel Park5df65182016-01-09 00:12:03 +090019import com.google.common.collect.Maps;
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;
Hyunsun Moon04b1fe92016-05-18 21:28:06 -070028import org.onlab.packet.IpPrefix;
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;
Hyunsun Moon04b1fe92016-05-18 21:28:06 -070032import org.onosproject.dhcp.IpAssignment;
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;
sanghoshin94872a12015-10-16 18:04:34 +090036import org.onosproject.net.Port;
Daniel Park23193902016-03-24 18:17:19 +090037import org.onosproject.net.config.ConfigFactory;
38import org.onosproject.net.config.NetworkConfigEvent;
39import org.onosproject.net.config.NetworkConfigListener;
40import org.onosproject.net.config.NetworkConfigRegistry;
41import org.onosproject.net.config.NetworkConfigService;
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;
sangho93447f12016-02-24 00:33:22 +090054import org.onosproject.openstackinterface.OpenstackInterfaceService;
55import org.onosproject.openstackinterface.OpenstackNetwork;
56import org.onosproject.openstackinterface.OpenstackPort;
57import org.onosproject.openstackinterface.OpenstackSecurityGroup;
58import org.onosproject.openstackinterface.OpenstackSubnet;
sangho0c2a3da2016-02-16 13:39:07 +090059import org.onosproject.openstacknetworking.OpenstackPortInfo;
sangho48907542016-03-28 16:07:07 +090060import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
61import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
sangho0c2a3da2016-02-16 13:39:07 +090062import org.onosproject.openstacknetworking.OpenstackSwitchingService;
sanghoshin94872a12015-10-16 18:04:34 +090063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
Hyunsun Moon04b1fe92016-05-18 21:28:06 -070065
66import java.util.Date;
sanghoshin46297d22015-11-03 17:51:24 +090067import java.util.Collection;
Daniel Park5df65182016-01-09 00:12:03 +090068import java.util.Map;
sanghoshin94872a12015-10-16 18:04:34 +090069import java.util.concurrent.ExecutorService;
70import java.util.concurrent.Executors;
sanghoshin46297d22015-11-03 17:51:24 +090071
sanghoshinf6735b22015-12-17 18:23:53 +090072import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon04b1fe92016-05-18 21:28:06 -070073import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
74
75import static com.google.common.base.Preconditions.checkArgument;
76import static com.google.common.base.Preconditions.checkNotNull;
sanghoshin94872a12015-10-16 18:04:34 +090077
sanghoshin94872a12015-10-16 18:04:34 +090078@Service
79@Component(immediate = true)
80/**
sanghoshin46297d22015-11-03 17:51:24 +090081 * Populates forwarding rules for VMs created by Openstack.
sanghoshin94872a12015-10-16 18:04:34 +090082 */
83public class OpenstackSwitchingManager implements OpenstackSwitchingService {
84
Daniel Park23193902016-03-24 18:17:19 +090085 private final Logger log = LoggerFactory.getLogger(getClass());
sanghoshin94872a12015-10-16 18:04:34 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected CoreService coreService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected PacketService packetService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DeviceService deviceService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin65723ae2015-11-17 22:07:21 +090097 protected HostService hostService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshin94872a12015-10-16 18:04:34 +0900100 protected FlowObjectiveService flowObjectiveService;
101
danielbb83ebc2015-10-29 15:13:06 +0900102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghoshinf25d2e02015-11-11 23:07:17 +0900103 protected DhcpService dhcpService;
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 Park81a61a12016-02-26 08:24:44 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho48907542016-03-28 16:07:07 +0900109 protected NetworkConfigRegistry networkConfig;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +0900112 protected OpenstackInterfaceService openstackService;
Daniel Park3a06c522016-01-28 20:51:12 +0900113
Daniel Park23193902016-03-24 18:17:19 +0900114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected NetworkConfigService configService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected NetworkConfigRegistry configRegistry;
119
sanghoshin46c6e3e2015-12-18 18:42:17 +0900120 public static final String PORTNAME_PREFIX_VM = "tap";
sangho3623cb62016-01-15 22:06:38 +0900121 public static final String PORTNAME_PREFIX_ROUTER = "qr-";
sanghoshin46c6e3e2015-12-18 18:42:17 +0900122 public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
123 public static final String PORTNAME = "portName";
Daniel Park3a06c522016-01-28 20:51:12 +0900124 private static final String ROUTER_INTERFACE = "network:router_interface";
sangho3623cb62016-01-15 22:06:38 +0900125 public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700126 public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
Daniel Park23193902016-03-24 18:17:19 +0900127 private static final String FORWARD_SLASH = "/";
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700128 private static final int DHCP_INFINITE_LEASE = -1;
Daniel Park23193902016-03-24 18:17:19 +0900129
sangho3623cb62016-01-15 22:06:38 +0900130
sanghoshin94872a12015-10-16 18:04:34 +0900131 private ApplicationId appId;
sangho90088532016-02-25 18:06:12 +0900132
133 private OpenstackArpHandler arpHandler;
134 private OpenstackSecurityGroupRulePopulator sgRulePopulator;
danielbb83ebc2015-10-29 15:13:06 +0900135
Daniel Park23193902016-03-24 18:17:19 +0900136 private ExecutorService deviceEventExecutorService =
sanghoshinf6735b22015-12-17 18:23:53 +0900137 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
sanghoshin94872a12015-10-16 18:04:34 +0900138
Daniel Park23193902016-03-24 18:17:19 +0900139 private ExecutorService configEventExecutorService =
140 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
141
sanghoshin94872a12015-10-16 18:04:34 +0900142 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
143 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sanghoshin65723ae2015-11-17 22:07:21 +0900144 private InternalHostListener internalHostListener = new InternalHostListener();
sangho0c2a3da2016-02-16 13:39:07 +0900145
Daniel Park23193902016-03-24 18:17:19 +0900146 private final Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
sangho90088532016-02-25 18:06:12 +0900147 private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
Daniel Park5df65182016-01-09 00:12:03 +0900148
Daniel Park23193902016-03-24 18:17:19 +0900149 private final ConfigFactory configFactory =
sangho48907542016-03-28 16:07:07 +0900150 new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
151 "config") {
Daniel Park23193902016-03-24 18:17:19 +0900152 @Override
sangho48907542016-03-28 16:07:07 +0900153 public OpenstackNetworkingConfig createConfig() {
154 return new OpenstackNetworkingConfig();
Daniel Park23193902016-03-24 18:17:19 +0900155 }
156 };
157 private final NetworkConfigListener configListener = new InternalConfigListener();
158
sangho48907542016-03-28 16:07:07 +0900159 private OpenstackNetworkingConfig config;
Daniel Park23193902016-03-24 18:17:19 +0900160
sanghoshin94872a12015-10-16 18:04:34 +0900161 @Activate
162 protected void activate() {
163 appId = coreService
164 .registerApplication("org.onosproject.openstackswitching");
sanghoshinf25d2e02015-11-11 23:07:17 +0900165
sanghoshin94872a12015-10-16 18:04:34 +0900166 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
167 deviceService.addListener(internalDeviceListener);
sanghoshin65723ae2015-11-17 22:07:21 +0900168 hostService.addListener(internalHostListener);
Daniel Park23193902016-03-24 18:17:19 +0900169 configRegistry.registerConfigFactory(configFactory);
170 configService.addListener(configListener);
danielbb83ebc2015-10-29 15:13:06 +0900171
sangho48907542016-03-28 16:07:07 +0900172 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
173 sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
174
175 networkConfig.registerConfigFactory(configFactory);
176 networkConfig.addListener(configListener);
177
Daniel Park23193902016-03-24 18:17:19 +0900178 readConfiguration();
sanghoshin46297d22015-11-03 17:51:24 +0900179
sanghoshin94872a12015-10-16 18:04:34 +0900180 log.info("Started");
181 }
182
183 @Deactivate
184 protected void deactivate() {
185 packetService.removeProcessor(internalPacketProcessor);
186 deviceService.removeListener(internalDeviceListener);
187
Daniel Park23193902016-03-24 18:17:19 +0900188 deviceEventExecutorService.shutdown();
189 configEventExecutorService.shutdown();
190 hostService.removeListener(internalHostListener);
191 configService.removeListener(configListener);
192 configRegistry.unregisterConfigFactory(configFactory);
sanghoshin94872a12015-10-16 18:04:34 +0900193
194 log.info("Stopped");
195 }
196
197 @Override
198 public void createPorts(OpenstackPort openstackPort) {
Daniel Park3a06c522016-01-28 20:51:12 +0900199
200 if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
Daniel Park23193902016-03-24 18:17:19 +0900201 && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)
202 && !openstackPort.fixedIps().isEmpty()) {
Daniel Park3a06c522016-01-28 20:51:12 +0900203 registerDhcpInfo(openstackPort);
sanghof2ca7e5c2015-12-23 16:02:43 +0900204 }
sanghoshin94872a12015-10-16 18:04:34 +0900205 }
206
207 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900208 public void removePort(String uuid) {
sangho3623cb62016-01-15 22:06:38 +0900209 // When VMs are remvoed, the flow rules for the VMs are removed using ONOS port update event.
210 // But, when router is removed, no ONOS port event occurs and we need to use Neutron port event.
211 // Here we should not touch any rules for VMs.
212 log.debug("port {} was removed", uuid);
sanghoshin94872a12015-10-16 18:04:34 +0900213
sangho3623cb62016-01-15 22:06:38 +0900214 String routerPortName = PORTNAME_PREFIX_ROUTER + uuid.substring(0, 11);
215 OpenstackPortInfo routerPortInfo = openstackPortInfoMap.get(routerPortName);
216 if (routerPortInfo != null) {
217 dhcpService.removeStaticMapping(routerPortInfo.mac());
sangho93447f12016-02-24 00:33:22 +0900218 deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
Daniel Park23193902016-03-24 18:17:19 +0900219 String pName = port.annotations().value(PORTNAME);
sangho93447f12016-02-24 00:33:22 +0900220 if (pName.equals(routerPortName)) {
221 OpenstackSwitchingRulePopulator rulePopulator =
222 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900223 deviceService, openstackService, driverService, config);
sangho3623cb62016-01-15 22:06:38 +0900224
sangho93447f12016-02-24 00:33:22 +0900225 rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
226 openstackPortInfoMap.remove(routerPortName);
227 return;
228 }
229 });
sangho3623cb62016-01-15 22:06:38 +0900230 }
sanghoshin94872a12015-10-16 18:04:34 +0900231 }
232
233 @Override
sanghoshin65723ae2015-11-17 22:07:21 +0900234 public void updatePort(OpenstackPort openstackPort) {
sangho90088532016-02-25 18:06:12 +0900235 if (openstackPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
236 String portName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
237 OpenstackPortInfo osPortInfo = openstackPortInfoMap.get(portName);
238 if (osPortInfo != null) {
239 // Remove all security group rules based on the ones stored in security group map.
240 osPortInfo.securityGroups().stream().forEach(
241 sgId -> sgRulePopulator.removeSecurityGroupRules(osPortInfo.deviceId(), sgId,
242 osPortInfo.ip(), openstackPortInfoMap, securityGroupMap));
243 // Add all security group rules based on the updated security group.
244 openstackPort.securityGroups().stream().forEach(
245 sgId -> sgRulePopulator.populateSecurityGroupRules(osPortInfo.deviceId(), sgId,
246 osPortInfo.ip(), openstackPortInfoMap));
247 updatePortMap(osPortInfo.deviceId(), portName, openstackService.networks(),
248 openstackService.subnets(), openstackPort);
249 }
250 }
sanghoshin94872a12015-10-16 18:04:34 +0900251 }
252
253 @Override
254 public void createNetwork(OpenstackNetwork openstackNetwork) {
Daniel Park81a61a12016-02-26 08:24:44 +0900255 //TODO
sanghoshin94872a12015-10-16 18:04:34 +0900256 }
257
danielbb83ebc2015-10-29 15:13:06 +0900258 @Override
259 public void createSubnet(OpenstackSubnet openstackSubnet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900260 //TODO
danielbb83ebc2015-10-29 15:13:06 +0900261 }
262
sanghoshin46297d22015-11-03 17:51:24 +0900263 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900264 public Map<String, OpenstackPortInfo> openstackPortInfo() {
265 return ImmutableMap.copyOf(this.openstackPortInfoMap);
Daniel Park3a06c522016-01-28 20:51:12 +0900266 }
267
Daniel Park5df65182016-01-09 00:12:03 +0900268 private void processPortUpdated(Device device, Port port) {
sangho90088532016-02-25 18:06:12 +0900269 String portName = port.annotations().value(PORTNAME);
270 synchronized (openstackPortInfoMap) {
271 if (portName.startsWith(PORTNAME_PREFIX_VM)) {
272 if (port.isEnabled()) {
273 OpenstackSwitchingRulePopulator rulePopulator =
274 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900275 deviceService, openstackService, driverService, config);
Daniel Park3a06c522016-01-28 20:51:12 +0900276
sangho90088532016-02-25 18:06:12 +0900277 rulePopulator.populateSwitchingRules(device, port);
278 OpenstackPort openstackPort = rulePopulator.openstackPort(port);
279 Ip4Address vmIp = (Ip4Address) openstackPort.fixedIps().values().stream()
280 .findAny().orElseGet(null);
281 openstackPort.securityGroups().stream().forEach(
282 sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(), sgId, vmIp,
283 openstackPortInfoMap));
284 updatePortMap(device.id(), port.annotations().value(PORTNAME),
285 openstackService.networks(), openstackService.subnets(), openstackPort);
Daniel Park3a06c522016-01-28 20:51:12 +0900286
sangho90088532016-02-25 18:06:12 +0900287 //In case portupdate event is driven by vm shutoff from openstack
288 } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
Daniel Park23193902016-03-24 18:17:19 +0900289 log.debug("Flowrules according to the port {} were removed", port.number());
sangho90088532016-02-25 18:06:12 +0900290 OpenstackSwitchingRulePopulator rulePopulator =
291 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900292 deviceService, openstackService, driverService, config);
sangho90088532016-02-25 18:06:12 +0900293 rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
294 openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
295 sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
296 openstackPortInfoMap.get(portName).ip(), openstackPortInfoMap, securityGroupMap));
297 dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
298 openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
299 }
Daniel Park5df65182016-01-09 00:12:03 +0900300 }
sanghoshin94872a12015-10-16 18:04:34 +0900301 }
302 }
303
Daniel Park23193902016-03-24 18:17:19 +0900304 private void processPortRemoved(Port port) {
danielbb83ebc2015-10-29 15:13:06 +0900305 log.debug("port {} is removed", port.toString());
sanghoshin94872a12015-10-16 18:04:34 +0900306 }
307
sanghoshin075e3e72015-11-25 16:34:29 +0900308 private void initializeFlowRules() {
309 OpenstackSwitchingRulePopulator rulePopulator =
310 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900311 deviceService, openstackService, driverService, config);
sanghoshin075e3e72015-11-25 16:34:29 +0900312
sangho0c2a3da2016-02-16 13:39:07 +0900313 Collection<OpenstackNetwork> networks = openstackService.networks();
314 Collection<OpenstackSubnet> subnets = openstackService.subnets();
sanghoshin46c6e3e2015-12-18 18:42:17 +0900315
sanghoshin075e3e72015-11-25 16:34:29 +0900316 deviceService.getDevices().forEach(device -> {
sangho90088532016-02-25 18:06:12 +0900317 log.debug("device {} num of ports {} ", device.id(),
318 deviceService.getPorts(device.id()).size());
319 deviceService.getPorts(device.id()).stream()
320 .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
321 port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
322 .forEach(vmPort -> {
323 OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
324 if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
325 rulePopulator.populateSwitchingRules(device, vmPort);
326 Ip4Address vmIp = (Ip4Address) osPort.fixedIps().values().stream()
327 .findAny().orElseGet(null);
328 osPort.securityGroups().stream().forEach(
329 sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(),
330 sgId, vmIp, openstackPortInfoMap));
331 updatePortMap(device.id(), vmPort.annotations().value(PORTNAME), networks,
332 subnets, osPort);
333 registerDhcpInfo(osPort);
334 } else {
335 log.warn("No openstackPort information for port {}", vmPort);
336 }
337 }
338 );
sanghoshin075e3e72015-11-25 16:34:29 +0900339 }
340 );
341 }
342
sangho90088532016-02-25 18:06:12 +0900343 private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
Daniel Park3a06c522016-01-28 20:51:12 +0900344 Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
Daniel Park81a61a12016-02-26 08:24:44 +0900345 long vni;
346 OpenstackNetwork openstackNetwork = networks.stream()
sanghoshin46c6e3e2015-12-18 18:42:17 +0900347 .filter(n -> n.id().equals(openstackPort.networkId()))
Daniel Park81a61a12016-02-26 08:24:44 +0900348 .findAny().orElse(null);
349 if (openstackNetwork != null) {
350 vni = Long.parseLong(openstackNetwork.segmentId());
351 } else {
352 log.debug("updatePortMap failed because there's no OpenstackNetwork matches {}", openstackPort.networkId());
353 return;
354 }
355
sanghoshin46c6e3e2015-12-18 18:42:17 +0900356
Daniel Park3a06c522016-01-28 20:51:12 +0900357 OpenstackSubnet openstackSubnet = subnets.stream()
358 .filter(n -> n.networkId().equals(openstackPort.networkId()))
359 .findFirst().get();
360
361 Ip4Address gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
362
sanghoshin46c6e3e2015-12-18 18:42:17 +0900363 OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
364 .setDeviceId(deviceId)
365 .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
sangho3623cb62016-01-15 22:06:38 +0900366 .setHostMac(openstackPort.macAddress())
Daniel Park3a06c522016-01-28 20:51:12 +0900367 .setVni(vni)
sangho90088532016-02-25 18:06:12 +0900368 .setGatewayIP(gatewayIPAddress)
Daniel Park81a61a12016-02-26 08:24:44 +0900369 .setNetworkId(openstackPort.networkId())
sangho90088532016-02-25 18:06:12 +0900370 .setSecurityGroups(openstackPort.securityGroups());
sanghoshin46c6e3e2015-12-18 18:42:17 +0900371
sangho90088532016-02-25 18:06:12 +0900372 openstackPortInfoMap.put(portName, portBuilder.build());
373
374 openstackPort.securityGroups().stream().forEach(sgId -> {
375 if (!securityGroupMap.containsKey(sgId)) {
376 securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
377 }
378 });
sanghoshin46c6e3e2015-12-18 18:42:17 +0900379 }
380
sanghoshin46297d22015-11-03 17:51:24 +0900381 private void registerDhcpInfo(OpenstackPort openstackPort) {
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700382 checkNotNull(openstackPort);
383 checkArgument(!openstackPort.fixedIps().isEmpty());
sanghoshin46297d22015-11-03 17:51:24 +0900384
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700385 OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
sanghoshin46297d22015-11-03 17:51:24 +0900386 .filter(n -> n.networkId().equals(openstackPort.networkId()))
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700387 .findFirst().orElse(null);
388 if (openstackSubnet == null) {
389 log.warn("Failed to find subnet for {}", openstackPort);
390 return;
sanghoshin46297d22015-11-03 17:51:24 +0900391 }
sanghoshin46297d22015-11-03 17:51:24 +0900392
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700393 Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
394 IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
395 Ip4Address broadcast = Ip4Address.makeMaskedAddress(
396 ipAddress,
397 subnetPrefix.prefixLength());
398
399 // TODO: supports multiple DNS servers
400 Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
401 DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
402
403 IpAssignment ipAssignment = IpAssignment.builder()
404 .ipAddress(ipAddress)
405 .leasePeriod(DHCP_INFINITE_LEASE)
406 .timestamp(new Date())
407 .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
408 .broadcast(broadcast)
409 .domainServer(domainServer)
410 .assignmentStatus(Option_RangeNotEnforced)
411 .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
412 .build();
413
414 dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
sanghoshin46297d22015-11-03 17:51:24 +0900415 }
416
sanghoshin94872a12015-10-16 18:04:34 +0900417 private class InternalPacketProcessor implements PacketProcessor {
418
419 @Override
420 public void process(PacketContext context) {
sanghoshin94872a12015-10-16 18:04:34 +0900421 if (context.isHandled()) {
422 return;
423 }
424
425 InboundPacket pkt = context.inPacket();
426 Ethernet ethernet = pkt.parsed();
427
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800428 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park3a06c522016-01-28 20:51:12 +0900429 arpHandler.processPacketIn(pkt, openstackPortInfoMap.values());
sanghoshin94872a12015-10-16 18:04:34 +0900430 }
431 }
432 }
433
sanghoshin65723ae2015-11-17 22:07:21 +0900434 private class InternalHostListener implements HostListener {
435
436 @Override
437 public void event(HostEvent hostEvent) {
Daniel Park23193902016-03-24 18:17:19 +0900438 deviceEventExecutorService.execute(new InternalEventHandler(hostEvent));
sanghoshin65723ae2015-11-17 22:07:21 +0900439 }
440 }
441
sanghoshin94872a12015-10-16 18:04:34 +0900442 private class InternalDeviceListener implements DeviceListener {
443
444 @Override
sanghoshin46297d22015-11-03 17:51:24 +0900445 public void event(DeviceEvent deviceEvent) {
Daniel Park23193902016-03-24 18:17:19 +0900446 deviceEventExecutorService.execute(new InternalEventHandler(deviceEvent));
sanghoshin94872a12015-10-16 18:04:34 +0900447 }
448 }
449
450 private class InternalEventHandler implements Runnable {
451
sanghoshin65723ae2015-11-17 22:07:21 +0900452 volatile AbstractEvent event;
sanghoshin94872a12015-10-16 18:04:34 +0900453
sanghoshin65723ae2015-11-17 22:07:21 +0900454 InternalEventHandler(AbstractEvent event) {
455 this.event = event;
sanghoshin94872a12015-10-16 18:04:34 +0900456 }
457
458 @Override
459 public void run() {
sanghoshin46297d22015-11-03 17:51:24 +0900460
sanghoshin65723ae2015-11-17 22:07:21 +0900461 if (event instanceof DeviceEvent) {
462 DeviceEvent deviceEvent = (DeviceEvent) event;
sanghoshin46297d22015-11-03 17:51:24 +0900463
sanghoshin65723ae2015-11-17 22:07:21 +0900464 switch (deviceEvent.type()) {
465 case DEVICE_ADDED:
Daniel Park23193902016-03-24 18:17:19 +0900466 log.debug("device {} is added", deviceEvent.subject().id());
sanghoshin65723ae2015-11-17 22:07:21 +0900467 break;
sanghoshin65723ae2015-11-17 22:07:21 +0900468 case DEVICE_AVAILABILITY_CHANGED:
Daniel Park23193902016-03-24 18:17:19 +0900469 Device device = deviceEvent.subject();
sanghoshin65723ae2015-11-17 22:07:21 +0900470 if (deviceService.isAvailable(device.id())) {
Daniel Park23193902016-03-24 18:17:19 +0900471 log.debug("device {} is added", device.id());
sanghoshin65723ae2015-11-17 22:07:21 +0900472 }
473 break;
474 case PORT_ADDED:
Daniel Park23193902016-03-24 18:17:19 +0900475 processPortUpdated(deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900476 break;
477 case PORT_UPDATED:
Daniel Park23193902016-03-24 18:17:19 +0900478 processPortUpdated(deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900479 break;
480 case PORT_REMOVED:
Daniel Park23193902016-03-24 18:17:19 +0900481 processPortRemoved(deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900482 break;
483 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900484 log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900485 break;
486 }
487 } else if (event instanceof HostEvent) {
488 HostEvent hostEvent = (HostEvent) event;
489
490 switch (hostEvent.type()) {
491 case HOST_REMOVED:
Daniel Park23193902016-03-24 18:17:19 +0900492 log.debug("host {} was removed", hostEvent.subject().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900493 break;
494 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900495 log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900496 break;
497 }
sanghoshin94872a12015-10-16 18:04:34 +0900498 }
499 }
500 }
Daniel Park23193902016-03-24 18:17:19 +0900501
502 private void readConfiguration() {
sangho48907542016-03-28 16:07:07 +0900503 config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
Daniel Park23193902016-03-24 18:17:19 +0900504 if (config == null) {
505 log.error("No configuration found");
506 return;
507 }
508
509 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
510 sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
511
512 initializeFlowRules();
513 }
514
515 private class InternalConfigListener implements NetworkConfigListener {
516
517 @Override
518 public void event(NetworkConfigEvent event) {
sangho48907542016-03-28 16:07:07 +0900519 if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
Daniel Park23193902016-03-24 18:17:19 +0900520 return;
521 }
522
523 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
524 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
525 configEventExecutorService.execute(OpenstackSwitchingManager.this::readConfiguration);
526
Daniel Park23193902016-03-24 18:17:19 +0900527 }
528 }
529 }
Jonathan Hart51539b82015-10-29 09:53:04 -0700530}