blob: 7f543a032af455cb0fce4d90970fcf863126a71c [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;
hyungseo Ryu38b5f182016-06-14 16:42:27 +0900129 public static final String SONA_DRIVER_NAME = "sona";
Daniel Park23193902016-03-24 18:17:19 +0900130
sangho3623cb62016-01-15 22:06:38 +0900131
sanghoshin94872a12015-10-16 18:04:34 +0900132 private ApplicationId appId;
sangho90088532016-02-25 18:06:12 +0900133
134 private OpenstackArpHandler arpHandler;
135 private OpenstackSecurityGroupRulePopulator sgRulePopulator;
danielbb83ebc2015-10-29 15:13:06 +0900136
Daniel Park23193902016-03-24 18:17:19 +0900137 private ExecutorService deviceEventExecutorService =
sanghoshinf6735b22015-12-17 18:23:53 +0900138 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
sanghoshin94872a12015-10-16 18:04:34 +0900139
Daniel Park23193902016-03-24 18:17:19 +0900140 private ExecutorService configEventExecutorService =
141 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
142
sanghoshin94872a12015-10-16 18:04:34 +0900143 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
144 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sanghoshin65723ae2015-11-17 22:07:21 +0900145 private InternalHostListener internalHostListener = new InternalHostListener();
sangho0c2a3da2016-02-16 13:39:07 +0900146
Daniel Park23193902016-03-24 18:17:19 +0900147 private final Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
sangho90088532016-02-25 18:06:12 +0900148 private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
Daniel Park5df65182016-01-09 00:12:03 +0900149
Daniel Park23193902016-03-24 18:17:19 +0900150 private final ConfigFactory configFactory =
sangho48907542016-03-28 16:07:07 +0900151 new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
152 "config") {
Daniel Park23193902016-03-24 18:17:19 +0900153 @Override
sangho48907542016-03-28 16:07:07 +0900154 public OpenstackNetworkingConfig createConfig() {
155 return new OpenstackNetworkingConfig();
Daniel Park23193902016-03-24 18:17:19 +0900156 }
157 };
158 private final NetworkConfigListener configListener = new InternalConfigListener();
159
sangho48907542016-03-28 16:07:07 +0900160 private OpenstackNetworkingConfig config;
Daniel Park23193902016-03-24 18:17:19 +0900161
sanghoshin94872a12015-10-16 18:04:34 +0900162 @Activate
163 protected void activate() {
164 appId = coreService
165 .registerApplication("org.onosproject.openstackswitching");
sanghoshinf25d2e02015-11-11 23:07:17 +0900166
sanghoshin94872a12015-10-16 18:04:34 +0900167 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
168 deviceService.addListener(internalDeviceListener);
sanghoshin65723ae2015-11-17 22:07:21 +0900169 hostService.addListener(internalHostListener);
Daniel Park23193902016-03-24 18:17:19 +0900170 configRegistry.registerConfigFactory(configFactory);
171 configService.addListener(configListener);
danielbb83ebc2015-10-29 15:13:06 +0900172
sangho48907542016-03-28 16:07:07 +0900173 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
174 sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
175
176 networkConfig.registerConfigFactory(configFactory);
177 networkConfig.addListener(configListener);
178
Daniel Park23193902016-03-24 18:17:19 +0900179 readConfiguration();
sanghoshin46297d22015-11-03 17:51:24 +0900180
sanghoshin94872a12015-10-16 18:04:34 +0900181 log.info("Started");
182 }
183
184 @Deactivate
185 protected void deactivate() {
186 packetService.removeProcessor(internalPacketProcessor);
187 deviceService.removeListener(internalDeviceListener);
188
Daniel Park23193902016-03-24 18:17:19 +0900189 deviceEventExecutorService.shutdown();
190 configEventExecutorService.shutdown();
191 hostService.removeListener(internalHostListener);
192 configService.removeListener(configListener);
193 configRegistry.unregisterConfigFactory(configFactory);
sanghoshin94872a12015-10-16 18:04:34 +0900194
195 log.info("Stopped");
196 }
197
198 @Override
199 public void createPorts(OpenstackPort openstackPort) {
Daniel Park3a06c522016-01-28 20:51:12 +0900200
201 if (!openstackPort.deviceOwner().equals(ROUTER_INTERFACE)
Daniel Park23193902016-03-24 18:17:19 +0900202 && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)
203 && !openstackPort.fixedIps().isEmpty()) {
Daniel Park3a06c522016-01-28 20:51:12 +0900204 registerDhcpInfo(openstackPort);
sanghof2ca7e5c2015-12-23 16:02:43 +0900205 }
sanghoshin94872a12015-10-16 18:04:34 +0900206 }
207
208 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900209 public void removePort(String uuid) {
sangho3623cb62016-01-15 22:06:38 +0900210 // When VMs are remvoed, the flow rules for the VMs are removed using ONOS port update event.
211 // But, when router is removed, no ONOS port event occurs and we need to use Neutron port event.
212 // Here we should not touch any rules for VMs.
213 log.debug("port {} was removed", uuid);
sanghoshin94872a12015-10-16 18:04:34 +0900214
sangho3623cb62016-01-15 22:06:38 +0900215 String routerPortName = PORTNAME_PREFIX_ROUTER + uuid.substring(0, 11);
216 OpenstackPortInfo routerPortInfo = openstackPortInfoMap.get(routerPortName);
217 if (routerPortInfo != null) {
218 dhcpService.removeStaticMapping(routerPortInfo.mac());
sangho93447f12016-02-24 00:33:22 +0900219 deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
Daniel Park23193902016-03-24 18:17:19 +0900220 String pName = port.annotations().value(PORTNAME);
sangho93447f12016-02-24 00:33:22 +0900221 if (pName.equals(routerPortName)) {
222 OpenstackSwitchingRulePopulator rulePopulator =
223 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900224 deviceService, openstackService, driverService, config);
sangho3623cb62016-01-15 22:06:38 +0900225
sangho93447f12016-02-24 00:33:22 +0900226 rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
227 openstackPortInfoMap.remove(routerPortName);
228 return;
229 }
230 });
sangho3623cb62016-01-15 22:06:38 +0900231 }
sanghoshin94872a12015-10-16 18:04:34 +0900232 }
233
234 @Override
sanghoshin65723ae2015-11-17 22:07:21 +0900235 public void updatePort(OpenstackPort openstackPort) {
sangho90088532016-02-25 18:06:12 +0900236 if (openstackPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
237 String portName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
238 OpenstackPortInfo osPortInfo = openstackPortInfoMap.get(portName);
239 if (osPortInfo != null) {
240 // Remove all security group rules based on the ones stored in security group map.
241 osPortInfo.securityGroups().stream().forEach(
242 sgId -> sgRulePopulator.removeSecurityGroupRules(osPortInfo.deviceId(), sgId,
243 osPortInfo.ip(), openstackPortInfoMap, securityGroupMap));
244 // Add all security group rules based on the updated security group.
245 openstackPort.securityGroups().stream().forEach(
246 sgId -> sgRulePopulator.populateSecurityGroupRules(osPortInfo.deviceId(), sgId,
247 osPortInfo.ip(), openstackPortInfoMap));
248 updatePortMap(osPortInfo.deviceId(), portName, openstackService.networks(),
249 openstackService.subnets(), openstackPort);
250 }
251 }
sanghoshin94872a12015-10-16 18:04:34 +0900252 }
253
254 @Override
255 public void createNetwork(OpenstackNetwork openstackNetwork) {
Daniel Park81a61a12016-02-26 08:24:44 +0900256 //TODO
sanghoshin94872a12015-10-16 18:04:34 +0900257 }
258
danielbb83ebc2015-10-29 15:13:06 +0900259 @Override
260 public void createSubnet(OpenstackSubnet openstackSubnet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900261 //TODO
danielbb83ebc2015-10-29 15:13:06 +0900262 }
263
sanghoshin46297d22015-11-03 17:51:24 +0900264 @Override
sangho0c2a3da2016-02-16 13:39:07 +0900265 public Map<String, OpenstackPortInfo> openstackPortInfo() {
266 return ImmutableMap.copyOf(this.openstackPortInfoMap);
Daniel Park3a06c522016-01-28 20:51:12 +0900267 }
268
Daniel Park5df65182016-01-09 00:12:03 +0900269 private void processPortUpdated(Device device, Port port) {
sangho90088532016-02-25 18:06:12 +0900270 String portName = port.annotations().value(PORTNAME);
271 synchronized (openstackPortInfoMap) {
272 if (portName.startsWith(PORTNAME_PREFIX_VM)) {
273 if (port.isEnabled()) {
274 OpenstackSwitchingRulePopulator rulePopulator =
275 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900276 deviceService, openstackService, driverService, config);
Daniel Park3a06c522016-01-28 20:51:12 +0900277
sangho90088532016-02-25 18:06:12 +0900278 rulePopulator.populateSwitchingRules(device, port);
279 OpenstackPort openstackPort = rulePopulator.openstackPort(port);
280 Ip4Address vmIp = (Ip4Address) openstackPort.fixedIps().values().stream()
281 .findAny().orElseGet(null);
282 openstackPort.securityGroups().stream().forEach(
283 sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(), sgId, vmIp,
284 openstackPortInfoMap));
285 updatePortMap(device.id(), port.annotations().value(PORTNAME),
286 openstackService.networks(), openstackService.subnets(), openstackPort);
Daniel Park3a06c522016-01-28 20:51:12 +0900287
sangho90088532016-02-25 18:06:12 +0900288 //In case portupdate event is driven by vm shutoff from openstack
289 } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
Daniel Park23193902016-03-24 18:17:19 +0900290 log.debug("Flowrules according to the port {} were removed", port.number());
sangho90088532016-02-25 18:06:12 +0900291 OpenstackSwitchingRulePopulator rulePopulator =
292 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900293 deviceService, openstackService, driverService, config);
sangho90088532016-02-25 18:06:12 +0900294 rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
295 openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
296 sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
297 openstackPortInfoMap.get(portName).ip(), openstackPortInfoMap, securityGroupMap));
298 dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
299 openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
300 }
Daniel Park5df65182016-01-09 00:12:03 +0900301 }
sanghoshin94872a12015-10-16 18:04:34 +0900302 }
303 }
304
Daniel Park23193902016-03-24 18:17:19 +0900305 private void processPortRemoved(Port port) {
danielbb83ebc2015-10-29 15:13:06 +0900306 log.debug("port {} is removed", port.toString());
sanghoshin94872a12015-10-16 18:04:34 +0900307 }
308
sanghoshin075e3e72015-11-25 16:34:29 +0900309 private void initializeFlowRules() {
310 OpenstackSwitchingRulePopulator rulePopulator =
311 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
Daniel Park23193902016-03-24 18:17:19 +0900312 deviceService, openstackService, driverService, config);
sanghoshin075e3e72015-11-25 16:34:29 +0900313
sangho0c2a3da2016-02-16 13:39:07 +0900314 Collection<OpenstackNetwork> networks = openstackService.networks();
315 Collection<OpenstackSubnet> subnets = openstackService.subnets();
sanghoshin46c6e3e2015-12-18 18:42:17 +0900316
sanghoshin075e3e72015-11-25 16:34:29 +0900317 deviceService.getDevices().forEach(device -> {
sangho90088532016-02-25 18:06:12 +0900318 log.debug("device {} num of ports {} ", device.id(),
319 deviceService.getPorts(device.id()).size());
320 deviceService.getPorts(device.id()).stream()
321 .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
322 port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
323 .forEach(vmPort -> {
324 OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
325 if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
326 rulePopulator.populateSwitchingRules(device, vmPort);
327 Ip4Address vmIp = (Ip4Address) osPort.fixedIps().values().stream()
328 .findAny().orElseGet(null);
329 osPort.securityGroups().stream().forEach(
330 sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(),
331 sgId, vmIp, openstackPortInfoMap));
332 updatePortMap(device.id(), vmPort.annotations().value(PORTNAME), networks,
333 subnets, osPort);
334 registerDhcpInfo(osPort);
335 } else {
336 log.warn("No openstackPort information for port {}", vmPort);
337 }
338 }
339 );
sanghoshin075e3e72015-11-25 16:34:29 +0900340 }
341 );
342 }
343
sangho90088532016-02-25 18:06:12 +0900344 private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
Daniel Park3a06c522016-01-28 20:51:12 +0900345 Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
Daniel Park81a61a12016-02-26 08:24:44 +0900346 long vni;
347 OpenstackNetwork openstackNetwork = networks.stream()
sanghoshin46c6e3e2015-12-18 18:42:17 +0900348 .filter(n -> n.id().equals(openstackPort.networkId()))
Daniel Park81a61a12016-02-26 08:24:44 +0900349 .findAny().orElse(null);
350 if (openstackNetwork != null) {
351 vni = Long.parseLong(openstackNetwork.segmentId());
352 } else {
353 log.debug("updatePortMap failed because there's no OpenstackNetwork matches {}", openstackPort.networkId());
354 return;
355 }
356
sanghoshin46c6e3e2015-12-18 18:42:17 +0900357
Daniel Park3a06c522016-01-28 20:51:12 +0900358 OpenstackSubnet openstackSubnet = subnets.stream()
359 .filter(n -> n.networkId().equals(openstackPort.networkId()))
360 .findFirst().get();
361
362 Ip4Address gatewayIPAddress = Ip4Address.valueOf(openstackSubnet.gatewayIp());
363
sanghoshin46c6e3e2015-12-18 18:42:17 +0900364 OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
365 .setDeviceId(deviceId)
366 .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
sangho3623cb62016-01-15 22:06:38 +0900367 .setHostMac(openstackPort.macAddress())
Daniel Park3a06c522016-01-28 20:51:12 +0900368 .setVni(vni)
sangho90088532016-02-25 18:06:12 +0900369 .setGatewayIP(gatewayIPAddress)
Daniel Park81a61a12016-02-26 08:24:44 +0900370 .setNetworkId(openstackPort.networkId())
sangho90088532016-02-25 18:06:12 +0900371 .setSecurityGroups(openstackPort.securityGroups());
sanghoshin46c6e3e2015-12-18 18:42:17 +0900372
sangho90088532016-02-25 18:06:12 +0900373 openstackPortInfoMap.put(portName, portBuilder.build());
374
375 openstackPort.securityGroups().stream().forEach(sgId -> {
376 if (!securityGroupMap.containsKey(sgId)) {
sanghod177f8f2016-06-29 21:52:23 +0900377 securityGroupMap.put(sgId, openstackService.securityGroup(sgId));
sangho90088532016-02-25 18:06:12 +0900378 }
379 });
sanghoshin46c6e3e2015-12-18 18:42:17 +0900380 }
381
sanghoshin46297d22015-11-03 17:51:24 +0900382 private void registerDhcpInfo(OpenstackPort openstackPort) {
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700383 checkNotNull(openstackPort);
384 checkArgument(!openstackPort.fixedIps().isEmpty());
sanghoshin46297d22015-11-03 17:51:24 +0900385
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700386 OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
sanghoshin46297d22015-11-03 17:51:24 +0900387 .filter(n -> n.networkId().equals(openstackPort.networkId()))
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700388 .findFirst().orElse(null);
389 if (openstackSubnet == null) {
390 log.warn("Failed to find subnet for {}", openstackPort);
391 return;
sanghoshin46297d22015-11-03 17:51:24 +0900392 }
sanghoshin46297d22015-11-03 17:51:24 +0900393
Hyunsun Moon04b1fe92016-05-18 21:28:06 -0700394 Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
395 IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
396 Ip4Address broadcast = Ip4Address.makeMaskedAddress(
397 ipAddress,
398 subnetPrefix.prefixLength());
399
400 // TODO: supports multiple DNS servers
401 Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
402 DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
403
404 IpAssignment ipAssignment = IpAssignment.builder()
405 .ipAddress(ipAddress)
406 .leasePeriod(DHCP_INFINITE_LEASE)
407 .timestamp(new Date())
408 .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
409 .broadcast(broadcast)
410 .domainServer(domainServer)
411 .assignmentStatus(Option_RangeNotEnforced)
412 .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
413 .build();
414
415 dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
sanghoshin46297d22015-11-03 17:51:24 +0900416 }
417
sanghoshin94872a12015-10-16 18:04:34 +0900418 private class InternalPacketProcessor implements PacketProcessor {
419
420 @Override
421 public void process(PacketContext context) {
hyungseo Ryu38b5f182016-06-14 16:42:27 +0900422 // FIXME: use GatewayNode list to check if the ARP packet is from GatewayNode's
sanghoshin94872a12015-10-16 18:04:34 +0900423 if (context.isHandled()) {
424 return;
hyungseo Ryu38b5f182016-06-14 16:42:27 +0900425 } else if (!SONA_DRIVER_NAME.equals(driverService
426 .getDriver(context.inPacket().receivedFrom().deviceId()).name())) {
427 return;
sanghoshin94872a12015-10-16 18:04:34 +0900428 }
429
430 InboundPacket pkt = context.inPacket();
431 Ethernet ethernet = pkt.parsed();
432
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800433 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park3a06c522016-01-28 20:51:12 +0900434 arpHandler.processPacketIn(pkt, openstackPortInfoMap.values());
sanghoshin94872a12015-10-16 18:04:34 +0900435 }
436 }
437 }
438
sanghoshin65723ae2015-11-17 22:07:21 +0900439 private class InternalHostListener implements HostListener {
440
441 @Override
442 public void event(HostEvent hostEvent) {
Daniel Park23193902016-03-24 18:17:19 +0900443 deviceEventExecutorService.execute(new InternalEventHandler(hostEvent));
sanghoshin65723ae2015-11-17 22:07:21 +0900444 }
445 }
446
sanghoshin94872a12015-10-16 18:04:34 +0900447 private class InternalDeviceListener implements DeviceListener {
448
449 @Override
sanghoshin46297d22015-11-03 17:51:24 +0900450 public void event(DeviceEvent deviceEvent) {
Daniel Park23193902016-03-24 18:17:19 +0900451 deviceEventExecutorService.execute(new InternalEventHandler(deviceEvent));
sanghoshin94872a12015-10-16 18:04:34 +0900452 }
453 }
454
455 private class InternalEventHandler implements Runnable {
456
sanghoshin65723ae2015-11-17 22:07:21 +0900457 volatile AbstractEvent event;
sanghoshin94872a12015-10-16 18:04:34 +0900458
sanghoshin65723ae2015-11-17 22:07:21 +0900459 InternalEventHandler(AbstractEvent event) {
460 this.event = event;
sanghoshin94872a12015-10-16 18:04:34 +0900461 }
462
463 @Override
464 public void run() {
sanghoshin46297d22015-11-03 17:51:24 +0900465
sanghoshin65723ae2015-11-17 22:07:21 +0900466 if (event instanceof DeviceEvent) {
467 DeviceEvent deviceEvent = (DeviceEvent) event;
sanghoshin46297d22015-11-03 17:51:24 +0900468
sanghoshin65723ae2015-11-17 22:07:21 +0900469 switch (deviceEvent.type()) {
470 case DEVICE_ADDED:
Daniel Park23193902016-03-24 18:17:19 +0900471 log.debug("device {} is added", deviceEvent.subject().id());
sanghoshin65723ae2015-11-17 22:07:21 +0900472 break;
sanghoshin65723ae2015-11-17 22:07:21 +0900473 case DEVICE_AVAILABILITY_CHANGED:
Daniel Park23193902016-03-24 18:17:19 +0900474 Device device = deviceEvent.subject();
sanghoshin65723ae2015-11-17 22:07:21 +0900475 if (deviceService.isAvailable(device.id())) {
Daniel Park23193902016-03-24 18:17:19 +0900476 log.debug("device {} is added", device.id());
sanghoshin65723ae2015-11-17 22:07:21 +0900477 }
478 break;
479 case PORT_ADDED:
Daniel Park23193902016-03-24 18:17:19 +0900480 processPortUpdated(deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900481 break;
482 case PORT_UPDATED:
Daniel Park23193902016-03-24 18:17:19 +0900483 processPortUpdated(deviceEvent.subject(), deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900484 break;
485 case PORT_REMOVED:
Daniel Park23193902016-03-24 18:17:19 +0900486 processPortRemoved(deviceEvent.port());
sanghoshin65723ae2015-11-17 22:07:21 +0900487 break;
488 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900489 log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900490 break;
491 }
492 } else if (event instanceof HostEvent) {
493 HostEvent hostEvent = (HostEvent) event;
494
495 switch (hostEvent.type()) {
496 case HOST_REMOVED:
Daniel Park23193902016-03-24 18:17:19 +0900497 log.debug("host {} was removed", hostEvent.subject().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900498 break;
499 default:
Daniel Park81a61a12016-02-26 08:24:44 +0900500 log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
sanghoshin65723ae2015-11-17 22:07:21 +0900501 break;
502 }
sanghoshin94872a12015-10-16 18:04:34 +0900503 }
504 }
505 }
Daniel Park23193902016-03-24 18:17:19 +0900506
507 private void readConfiguration() {
sangho48907542016-03-28 16:07:07 +0900508 config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
Daniel Park23193902016-03-24 18:17:19 +0900509 if (config == null) {
510 log.error("No configuration found");
511 return;
512 }
513
514 arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
515 sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
516
517 initializeFlowRules();
518 }
519
520 private class InternalConfigListener implements NetworkConfigListener {
521
522 @Override
523 public void event(NetworkConfigEvent event) {
sangho48907542016-03-28 16:07:07 +0900524 if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
Daniel Park23193902016-03-24 18:17:19 +0900525 return;
526 }
527
528 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
529 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
530 configEventExecutorService.execute(OpenstackSwitchingManager.this::readConfiguration);
531
Daniel Park23193902016-03-24 18:17:19 +0900532 }
533 }
534 }
Jonathan Hart51539b82015-10-29 09:53:04 -0700535}