blob: 781dfa75dd24bfb88780b1361c68dabffd8eb80c [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
sangho0c2a3da2016-02-16 13:39:07 +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 */
16package org.onosproject.openstacknetworking.routing;
17
18import com.google.common.collect.Lists;
sangho0c2a3da2016-02-16 13:39:07 +090019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.packet.Ethernet;
26import org.onlab.packet.IPv4;
27import org.onlab.packet.Ip4Address;
28import org.onlab.packet.MacAddress;
Hyunsun Moon0448ea02016-02-23 14:17:39 -080029import org.onlab.packet.UDP;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090030import org.onlab.util.KryoNamespace;
sangho0c2a3da2016-02-16 13:39:07 +090031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090033import org.onosproject.net.DeviceId;
34import org.onosproject.net.Port;
Daniel Park81a61a12016-02-26 08:24:44 +090035import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigRegistry;
39import org.onosproject.net.config.NetworkConfigService;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090040import org.onosproject.net.device.DeviceEvent;
41import org.onosproject.net.device.DeviceListener;
sangho0c2a3da2016-02-16 13:39:07 +090042import org.onosproject.net.device.DeviceService;
43import org.onosproject.net.driver.DriverService;
44import org.onosproject.net.flowobjective.FlowObjectiveService;
45import org.onosproject.net.packet.InboundPacket;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketProcessor;
48import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090049import org.onosproject.openstackinterface.OpenstackFloatingIP;
50import org.onosproject.openstackinterface.OpenstackInterfaceService;
51import org.onosproject.openstackinterface.OpenstackPort;
52import org.onosproject.openstackinterface.OpenstackRouter;
53import org.onosproject.openstackinterface.OpenstackRouterInterface;
sangho48907542016-03-28 16:07:07 +090054import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090055import org.onosproject.openstacknetworking.OpenstackPortInfo;
sangho0c2a3da2016-02-16 13:39:07 +090056import org.onosproject.openstacknetworking.OpenstackRoutingService;
sangho48907542016-03-28 16:07:07 +090057import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
Daniel Park81a61a12016-02-26 08:24:44 +090058import org.onosproject.openstacknetworking.OpenstackSwitchingService;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090059import org.onosproject.store.serializers.KryoNamespaces;
60import org.onosproject.store.service.ConsistentMap;
61import org.onosproject.store.service.Serializer;
62import org.onosproject.store.service.StorageService;
sangho0c2a3da2016-02-16 13:39:07 +090063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
66import java.util.Collection;
67import java.util.List;
Daniel Park23193902016-03-24 18:17:19 +090068import java.util.Map;
69import java.util.Optional;
sangho0c2a3da2016-02-16 13:39:07 +090070import java.util.concurrent.ExecutorService;
71import java.util.concurrent.Executors;
72import java.util.stream.Collectors;
73
74import static com.google.common.base.Preconditions.checkNotNull;
75import static org.onlab.util.Tools.groupedThreads;
76
sangho0c2a3da2016-02-16 13:39:07 +090077@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090078@Service
sangho0c2a3da2016-02-16 13:39:07 +090079/**
80 * Populates flow rules about L3 functionality for VMs in Openstack.
81 */
82public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090083
84 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090085
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected CoreService coreService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected PacketService packetService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DeviceService deviceService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090096 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090097
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park81a61a12016-02-26 08:24:44 +090099 protected OpenstackSwitchingService openstackSwitchingService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho0c2a3da2016-02-16 13:39:07 +0900102 protected FlowObjectiveService flowObjectiveService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected DriverService driverService;
106
Daniel Park81a61a12016-02-26 08:24:44 +0900107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected NetworkConfigService configService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected NetworkConfigRegistry configRegistry;
112
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected StorageService storageService;
Daniel Park81a61a12016-02-26 08:24:44 +0900115
Daniel Park23193902016-03-24 18:17:19 +0900116
sangho0c2a3da2016-02-16 13:39:07 +0900117 private ApplicationId appId;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900118 private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
119 private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900120 // Map<RouterInterface`s portId, Corresponded port`s network id>
121 private ConsistentMap<String, String> routerInterfaceMap;
sangho0c2a3da2016-02-16 13:39:07 +0900122 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900123 private static final String PORT_NAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900124 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900125 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900126 private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900127 private static final String TP_PORT_MAP_NAME = "openstackrouting-tpportnum";
128 private static final String ROUTER_INTERFACE_MAP_NAME = "openstackrouting-routerinterface";
Daniel Park23193902016-03-24 18:17:19 +0900129 private static final String COLON = ":";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900130 private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
131 private static final int TP_PORT_MINIMUM_NUM = 1024;
132 private static final int TP_PORT_MAXIMUM_NUM = 65535;
sangho48907542016-03-28 16:07:07 +0900133
Daniel Park81a61a12016-02-26 08:24:44 +0900134 private final ConfigFactory configFactory =
sangho48907542016-03-28 16:07:07 +0900135 new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
136 "config") {
Daniel Park81a61a12016-02-26 08:24:44 +0900137 @Override
sangho48907542016-03-28 16:07:07 +0900138 public OpenstackNetworkingConfig createConfig() {
139 return new OpenstackNetworkingConfig();
Daniel Park81a61a12016-02-26 08:24:44 +0900140 }
141 };
sangho48907542016-03-28 16:07:07 +0900142
Daniel Park81a61a12016-02-26 08:24:44 +0900143 private final NetworkConfigListener configListener = new InternalConfigListener();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900144
sangho48907542016-03-28 16:07:07 +0900145 private OpenstackNetworkingConfig config;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900146 private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
147 .register(KryoNamespaces.API)
148 .register(KryoNamespaces.MISC)
149 .register(OpenstackFloatingIP.FloatingIpStatus.class)
150 .register(OpenstackFloatingIP.class)
151 .register(Ip4Address.class)
152 .register(String.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900153
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900154 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
155 .register(KryoNamespaces.API)
156 .register(KryoNamespaces.MISC)
157 .register(Integer.class)
158 .register(String.class);
sangho0c2a3da2016-02-16 13:39:07 +0900159
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900160 private static final KryoNamespace.Builder ROUTER_INTERFACE_SERIALIZER = KryoNamespace.newBuilder()
161 .register(KryoNamespaces.API)
162 .register(KryoNamespaces.MISC)
163 .register(String.class);
164
sangho0c2a3da2016-02-16 13:39:07 +0900165 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900166 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sangho0c2a3da2016-02-16 13:39:07 +0900167 private ExecutorService l3EventExecutorService =
168 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
169 private ExecutorService icmpEventExecutorService =
170 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
Daniel Park81a61a12016-02-26 08:24:44 +0900171 private ExecutorService arpEventExecutorService =
172 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
173 private OpenstackIcmpHandler openstackIcmpHandler;
174 private OpenstackRoutingArpHandler openstackArpHandler;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900175 private OpenstackRoutingRulePopulator rulePopulator;
Daniel Park23193902016-03-24 18:17:19 +0900176 private Map<DeviceId, Ip4Address> computeNodeMap;
sangho0c2a3da2016-02-16 13:39:07 +0900177
178 @Activate
179 protected void activate() {
180 appId = coreService.registerApplication(APP_ID);
181 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
Daniel Park81a61a12016-02-26 08:24:44 +0900182 configRegistry.registerConfigFactory(configFactory);
183 configService.addListener(configListener);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900184 deviceService.addListener(internalDeviceListener);
Daniel Park81a61a12016-02-26 08:24:44 +0900185
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900186 floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
187 .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
188 .withName(FLOATING_IP_MAP_NAME)
189 .withApplicationId(appId)
190 .build();
191 tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
192 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
193 .withName(TP_PORT_MAP_NAME)
194 .withApplicationId(appId)
195 .build();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900196 routerInterfaceMap = storageService.<String, String>consistentMapBuilder()
197 .withSerializer(Serializer.using(ROUTER_INTERFACE_SERIALIZER.build()))
198 .withName(ROUTER_INTERFACE_MAP_NAME)
199 .withApplicationId(appId)
200 .build();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900201
sangho48907542016-03-28 16:07:07 +0900202 readConfiguration();
203
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900204 log.info("started");
sangho0c2a3da2016-02-16 13:39:07 +0900205 }
206
207 @Deactivate
208 protected void deactivate() {
209 packetService.removeProcessor(internalPacketProcessor);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900210 deviceService.removeListener(internalDeviceListener);
Daniel Park81a61a12016-02-26 08:24:44 +0900211 l3EventExecutorService.shutdown();
212 icmpEventExecutorService.shutdown();
213 arpEventExecutorService.shutdown();
214
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900215 floatingIpMap.clear();
216 tpPortNumMap.clear();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900217 routerInterfaceMap.clear();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900218
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900219 log.info("stopped");
sangho0c2a3da2016-02-16 13:39:07 +0900220 }
221
222
223 @Override
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900224 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
225 floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
sangho0c2a3da2016-02-16 13:39:07 +0900226 }
227
228 @Override
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900229 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
230 if (!floatingIpMap.containsKey(openstackFloatingIp.id())) {
231 log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIp.id());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900232 return;
233 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900234 if (openstackFloatingIp.portId() == null || openstackFloatingIp.portId().equals("null")) {
235 OpenstackFloatingIP floatingIp = floatingIpMap.get(openstackFloatingIp.id()).value();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900236 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900237 .get(PORTNAME_PREFIX_VM.concat(floatingIp.portId().substring(0, 11)));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900238 if (portInfo == null) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900239 log.warn("There`s no portInfo information about portId {}", floatingIp.portId());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900240 return;
241 }
242 l3EventExecutorService.execute(
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900243 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
244 floatingIpMap.replace(floatingIp.id(), openstackFloatingIp);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900245 } else {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900246 floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900247 l3EventExecutorService.execute(
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900248 new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, true, null));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900249 }
sangho0c2a3da2016-02-16 13:39:07 +0900250 }
251
252 @Override
253 public void deleteFloatingIP(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900254 floatingIpMap.remove(id);
sangho0c2a3da2016-02-16 13:39:07 +0900255 }
256
257 @Override
258 public void createRouter(OpenstackRouter openstackRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900259 }
260
261 @Override
262 public void updateRouter(OpenstackRouter openstackRouter) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900263 if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sanghoefbc0382016-04-06 13:35:38 +0900264 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900265 } else {
266 unsetExternalConnection();
267 }
268 }
269
270 private void unsetExternalConnection() {
271 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
272 internalRouters.forEach(r ->
273 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
274 }
275
276 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
277 List<OpenstackRouter> routers;
278 if (externalConnection) {
279 routers = openstackService.routers()
280 .stream()
281 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
282 .collect(Collectors.toList());
283 } else {
284 routers = openstackService.routers()
285 .stream()
286 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
287 .collect(Collectors.toList());
288 }
289 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900290 }
291
292 @Override
293 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900294 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900295 }
296
297 @Override
298 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900299 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
300 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900301 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900302 setL3Connection(getOpenstackRouter(routerInterface.id()), null);
303 routerInterfaceMap.put(routerInterface.portId(), openstackService.port(routerInterface.portId()).networkId());
304 }
305
306 private void setL3Connection(OpenstackRouter openstackRouter, OpenstackPort openstackPort) {
307 Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(openstackRouter);
308 if (interfaceList.size() < 2) {
309 return;
310 }
311 if (openstackPort == null) {
312 interfaceList.forEach(i -> {
313 OpenstackPort interfacePort = openstackService.port(i.portId());
314 openstackService.ports()
315 .stream()
316 .filter(p -> p.networkId().equals(interfacePort.networkId())
317 && !p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
318 .forEach(p -> rulePopulator.populateL3Rules(p,
319 getL3ConnectionList(p.networkId(), interfaceList)));
320 });
321 } else {
322 rulePopulator.populateL3Rules(openstackPort, getL3ConnectionList(openstackPort.networkId(), interfaceList));
323 }
324
325 }
326
327 private List<OpenstackRouterInterface> getL3ConnectionList(String networkId,
328 Collection<OpenstackRouterInterface> interfaceList) {
329 List<OpenstackRouterInterface> targetList = Lists.newArrayList();
330 interfaceList.forEach(i -> {
331 OpenstackPort port = openstackService.port(i.portId());
332 if (!port.networkId().equals(networkId)) {
333 targetList.add(i);
334 }
335 });
336 return targetList;
sangho0c2a3da2016-02-16 13:39:07 +0900337 }
338
339 @Override
340 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900341 OpenstackRouter router = openstackService.router(routerInterface.id());
342 Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(router);
343 if (interfaceList.size() == 1) {
344 List<OpenstackRouterInterface> newList = Lists.newArrayList();
345 newList.add(routerInterface);
346 interfaceList.forEach(i -> removeL3RulesForRouterInterface(i, router, newList));
347 }
348 removeL3RulesForRouterInterface(routerInterface, router, null);
sangho0c2a3da2016-02-16 13:39:07 +0900349 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900350 routerInterfaceMap.remove(routerInterface.portId());
351 }
352
353 private void removeL3RulesForRouterInterface(OpenstackRouterInterface routerInterface, OpenstackRouter router,
354 List<OpenstackRouterInterface> newList) {
355 openstackService.ports(routerInterfaceMap.get(routerInterface.portId()).value()).forEach(p -> {
356 Ip4Address vmIp = (Ip4Address) p.fixedIps().values().toArray()[0];
357 if (newList == null) {
358 rulePopulator.removeL3Rules(vmIp,
359 getL3ConnectionList(p.networkId(), getOpenstackRouterInterface(router)));
360 } else {
361 rulePopulator.removeL3Rules(vmIp, newList);
362 }
363 }
364 );
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900365 }
366
367 @Override
368 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
369 if (floatingIpMap.size() < 1) {
370 log.info("No information in FloatingIpMap");
371 return;
372 }
373 OpenstackFloatingIP floatingIp = associatedFloatingIps()
374 .stream()
375 .filter(fIp -> fIp.portId().equals(portId))
376 .findAny()
377 .orElse(null);
378 if (floatingIp != null && portInfo != null) {
379 l3EventExecutorService.execute(
380 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
381 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
382 .floatingIpAddress(floatingIp.floatingIpAddress())
383 .id(floatingIp.id())
384 .networkId(floatingIp.networkId())
385 .status(floatingIp.status())
386 .tenantId(floatingIp.tenantId());
387 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
388 } else if (portInfo == null) {
389 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
390 }
391 }
392
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900393 @Override
394 public String networkIdForRouterInterface(String portId) {
395 return routerInterfaceMap.get(portId).value();
396 }
397
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900398 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
399 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
400 floatingIpMap.values()
401 .stream()
402 .filter(fIp -> fIp.value().portId() != null)
403 .forEach(fIp -> fIps.add(fIp.value()));
404 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900405 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900406
407 private void reloadInitL3Rules() {
Daniel Park23193902016-03-24 18:17:19 +0900408 l3EventExecutorService.execute(() ->
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900409 openstackService.ports()
410 .stream()
411 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900412 .forEach(p -> updateRouterInterface(portToRouterInterface(p)))
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900413 );
414
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900415 }
416
417 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
418 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900419 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900420 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
421 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900422 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900423
424 return osBuilder.build();
425 }
426
sangho0c2a3da2016-02-16 13:39:07 +0900427 private class InternalPacketProcessor implements PacketProcessor {
428
429 @Override
430 public void process(PacketContext context) {
431
432 if (context.isHandled()) {
433 return;
Daniel Park81a61a12016-02-26 08:24:44 +0900434 } else if (!context.inPacket().receivedFrom().deviceId().toString()
435 .equals(config.gatewayBridgeId())) {
436 return;
sangho0c2a3da2016-02-16 13:39:07 +0900437 }
438
439 InboundPacket pkt = context.inPacket();
440 Ethernet ethernet = pkt.parsed();
441
Daniel Park81a61a12016-02-26 08:24:44 +0900442 //TODO: Considers IPv6 later.
443 if (ethernet == null) {
444 return;
445 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900446 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900447 switch (iPacket.getProtocol()) {
448 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900449
Daniel Park23193902016-03-24 18:17:19 +0900450 icmpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900451 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900452 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800453 case IPv4.PROTOCOL_UDP:
454 // don't process DHCP
455 UDP udpPacket = (UDP) iPacket.getPayload();
456 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
457 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
458 break;
459 }
sangho0c2a3da2016-02-16 13:39:07 +0900460 default:
461 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Daniel Park23193902016-03-24 18:17:19 +0900462 Optional<Port> port =
Daniel Park81a61a12016-02-26 08:24:44 +0900463 getExternalPort(pkt.receivedFrom().deviceId(), config.gatewayExternalInterfaceName());
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900464 if (port.isPresent()) {
Daniel Park23193902016-03-24 18:17:19 +0900465 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
466 Ip4Address.valueOf(iPacket.getSourceAddress()));
467 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
468 portNum, openstackPort, port.get(), config));
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900469 } else {
470 log.warn("There`s no external interface");
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900471 }
sangho0c2a3da2016-02-16 13:39:07 +0900472 break;
473 }
Daniel Park81a61a12016-02-26 08:24:44 +0900474 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park23193902016-03-24 18:17:19 +0900475 arpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900476 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900477 }
478 }
479
480 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900481 int portNum = findUnusedPortNum();
482 if (portNum == 0) {
483 clearPortNumMap();
484 portNum = findUnusedPortNum();
485 }
Daniel Park23193902016-03-24 18:17:19 +0900486 tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900487 return portNum;
488 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900489
490 private int findUnusedPortNum() {
491 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
492 if (!tpPortNumMap.containsKey(i)) {
493 return i;
494 }
495 }
496 return 0;
497 }
498
499 }
500
501 private void clearPortNumMap() {
502 tpPortNumMap.entrySet().forEach(e -> {
503 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
504 tpPortNumMap.remove(e.getKey());
505 }
506 });
sangho0c2a3da2016-02-16 13:39:07 +0900507 }
508
Daniel Park23193902016-03-24 18:17:19 +0900509 private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900510 return deviceService.getPorts(deviceId)
511 .stream()
512 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
Daniel Park23193902016-03-24 18:17:19 +0900513 .findAny();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900514 }
515
sangho0c2a3da2016-02-16 13:39:07 +0900516 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900517 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900518 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900519 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900520 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
521 .values().stream().findFirst().orElse(null);
522 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900523 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900524 return;
525 }
Daniel Park23193902016-03-24 18:17:19 +0900526 interfaces.forEach(this::initiateL3Rule);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900527 }
528
Daniel Park23193902016-03-24 18:17:19 +0900529 private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) {
530 return getExternalRouter(true)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900531 .stream()
532 .filter(r -> r.gatewayExternalInfo()
533 .externalFixedIps()
534 .values()
535 .stream()
Daniel Park23193902016-03-24 18:17:19 +0900536 .findAny()
537 .get()
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900538 .equals(externalIp))
Daniel Park23193902016-03-24 18:17:19 +0900539 .findAny();
sangho0c2a3da2016-02-16 13:39:07 +0900540 }
541
Daniel Park23193902016-03-24 18:17:19 +0900542 private void initiateL3Rule(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900543 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900544 .port(routerInterface.portId()).networkId()).segmentId());
Daniel Park23193902016-03-24 18:17:19 +0900545 rulePopulator.populateExternalRules(vni);
sangho0c2a3da2016-02-16 13:39:07 +0900546 }
547
548 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900549 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
550 openstackService.ports()
551 .stream()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900552 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
553 && p.deviceId().equals(router.id()))
554 .forEach(p -> interfaces.add(portToRouterInterface(p)));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900555 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900556 }
557
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900558 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900559 return openstackService.routers().stream().filter(r ->
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900560 r.id().equals(id)).iterator().next();
sangho0c2a3da2016-02-16 13:39:07 +0900561 }
562
563 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900564 OpenstackPort openstackPort = openstackService.ports().stream()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900565 .filter(p -> p.macAddress().equals(sourceMac)).iterator().next();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900566 return openstackPort.fixedIps().values().stream().filter(ip ->
567 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900568 }
569
Daniel Park81a61a12016-02-26 08:24:44 +0900570 private void readConfiguration() {
sangho48907542016-03-28 16:07:07 +0900571 config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
Daniel Park81a61a12016-02-26 08:24:44 +0900572 if (config == null) {
573 log.error("No configuration found");
574 return;
575 }
576
577 checkNotNull(config.physicalRouterMac());
578 checkNotNull(config.gatewayBridgeId());
579 checkNotNull(config.gatewayExternalInterfaceMac());
580 checkNotNull(config.gatewayExternalInterfaceName());
581
sangho48907542016-03-28 16:07:07 +0900582 log.warn("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
Daniel Park81a61a12016-02-26 08:24:44 +0900583 config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
584
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900585 rulePopulator = new OpenstackRoutingRulePopulator(appId,
586 openstackService, flowObjectiveService, deviceService, driverService, config);
Daniel Park81a61a12016-02-26 08:24:44 +0900587
588 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
589 openstackService, config, openstackSwitchingService);
590 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, config);
591
592 openstackIcmpHandler.requestPacket(appId);
593 openstackArpHandler.requestPacket(appId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900594 reloadInitL3Rules();
sangho48907542016-03-28 16:07:07 +0900595
Daniel Park81a61a12016-02-26 08:24:44 +0900596 log.info("OpenstackRouting configured");
597 }
598
599 private class InternalConfigListener implements NetworkConfigListener {
600
601 @Override
602 public void event(NetworkConfigEvent event) {
sangho48907542016-03-28 16:07:07 +0900603 if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
Daniel Park81a61a12016-02-26 08:24:44 +0900604 return;
605 }
606
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900607 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
608 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
609 l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
Daniel Park81a61a12016-02-26 08:24:44 +0900610 }
611 }
612 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900613
614 private class InternalDeviceListener implements DeviceListener {
615
616 @Override
617 public void event(DeviceEvent deviceEvent) {
618 if (deviceEvent.type() == DeviceEvent.Type.PORT_UPDATED) {
619 Port port = deviceEvent.port();
620 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
621 .get(port.annotations().value(PORT_NAME));
622 OpenstackPort openstackPort = openstackService.port(port);
623 OpenstackPort interfacePort = openstackService.ports()
624 .stream()
625 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
626 && p.networkId().equals(openstackPort.networkId()))
627 .findAny()
628 .orElse(null);
629 if (portInfo == null && openstackPort == null) {
630 log.warn("As delete event timing issue between routing and switching, Can`t delete L3 rules");
631 return;
632 }
633 if ((port.isEnabled()) && (interfacePort != null)) {
634 OpenstackRouterInterface routerInterface = portToRouterInterface(interfacePort);
635 l3EventExecutorService.execute(() ->
636 setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
637 } else if (interfacePort != null) {
638 OpenstackRouterInterface routerInterface = portToRouterInterface(interfacePort);
639 l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(portInfo.ip(),
640 getL3ConnectionList(portInfo.networkId(),
641 getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id())))));
642 }
643 }
644 }
645 }
646
sangho0c2a3da2016-02-16 13:39:07 +0900647}