blob: b653c5a2eae783753daee66f22b4731fdefdfeba [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
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;
40import org.onosproject.net.config.basics.SubjectFactories;
sangho0c2a3da2016-02-16 13:39:07 +090041import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.driver.DriverService;
43import org.onosproject.net.flowobjective.FlowObjectiveService;
44import org.onosproject.net.packet.InboundPacket;
45import org.onosproject.net.packet.PacketContext;
46import org.onosproject.net.packet.PacketProcessor;
47import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090048import org.onosproject.openstackinterface.OpenstackFloatingIP;
49import org.onosproject.openstackinterface.OpenstackInterfaceService;
50import org.onosproject.openstackinterface.OpenstackPort;
51import org.onosproject.openstackinterface.OpenstackRouter;
52import org.onosproject.openstackinterface.OpenstackRouterInterface;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090053import org.onosproject.openstacknetworking.OpenstackPortInfo;
sangho0c2a3da2016-02-16 13:39:07 +090054import org.onosproject.openstacknetworking.OpenstackRoutingService;
Daniel Park81a61a12016-02-26 08:24:44 +090055import org.onosproject.openstacknetworking.OpenstackSwitchingService;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090056import org.onosproject.store.serializers.KryoNamespaces;
57import org.onosproject.store.service.ConsistentMap;
58import org.onosproject.store.service.Serializer;
59import org.onosproject.store.service.StorageService;
sangho0c2a3da2016-02-16 13:39:07 +090060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
63import java.util.Collection;
64import java.util.List;
sangho0c2a3da2016-02-16 13:39:07 +090065import java.util.concurrent.ExecutorService;
66import java.util.concurrent.Executors;
67import java.util.stream.Collectors;
68
69import static com.google.common.base.Preconditions.checkNotNull;
70import static org.onlab.util.Tools.groupedThreads;
71
sangho0c2a3da2016-02-16 13:39:07 +090072@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090073@Service
sangho0c2a3da2016-02-16 13:39:07 +090074/**
75 * Populates flow rules about L3 functionality for VMs in Openstack.
76 */
77public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090078
79 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090080
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected CoreService coreService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PacketService packetService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090091 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park81a61a12016-02-26 08:24:44 +090094 protected OpenstackSwitchingService openstackSwitchingService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho0c2a3da2016-02-16 13:39:07 +090097 protected FlowObjectiveService flowObjectiveService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected DriverService driverService;
101
Daniel Park81a61a12016-02-26 08:24:44 +0900102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected NetworkConfigService configService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected NetworkConfigRegistry configRegistry;
107
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected StorageService storageService;
Daniel Park81a61a12016-02-26 08:24:44 +0900110
sangho0c2a3da2016-02-16 13:39:07 +0900111 private ApplicationId appId;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900112 private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
113 private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
sangho0c2a3da2016-02-16 13:39:07 +0900114 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900115 private static final String PORT_NAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900116 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900117 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900118 private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
119 private static final String TP_PORT_MAP_NAME = "openstackrouting-portnum";
120 private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
121 private static final int TP_PORT_MINIMUM_NUM = 1024;
122 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Daniel Park81a61a12016-02-26 08:24:44 +0900123 private final ConfigFactory configFactory =
124 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackRoutingConfig.class, "openstackrouting") {
125 @Override
126 public OpenstackRoutingConfig createConfig() {
127 return new OpenstackRoutingConfig();
128 }
129 };
130 private final NetworkConfigListener configListener = new InternalConfigListener();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900131
Daniel Park81a61a12016-02-26 08:24:44 +0900132 private OpenstackRoutingConfig config;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900133 private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
134 .register(KryoNamespaces.API)
135 .register(KryoNamespaces.MISC)
136 .register(OpenstackFloatingIP.FloatingIpStatus.class)
137 .register(OpenstackFloatingIP.class)
138 .register(Ip4Address.class)
139 .register(String.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900140
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900141 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
142 .register(KryoNamespaces.API)
143 .register(KryoNamespaces.MISC)
144 .register(Integer.class)
145 .register(String.class);
sangho0c2a3da2016-02-16 13:39:07 +0900146
147 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
148 private ExecutorService l3EventExecutorService =
149 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
150 private ExecutorService icmpEventExecutorService =
151 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
Daniel Park81a61a12016-02-26 08:24:44 +0900152 private ExecutorService arpEventExecutorService =
153 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
154 private OpenstackIcmpHandler openstackIcmpHandler;
155 private OpenstackRoutingArpHandler openstackArpHandler;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900156 private OpenstackRoutingRulePopulator rulePopulator;
sangho0c2a3da2016-02-16 13:39:07 +0900157
158 @Activate
159 protected void activate() {
160 appId = coreService.registerApplication(APP_ID);
161 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
Daniel Park81a61a12016-02-26 08:24:44 +0900162 configRegistry.registerConfigFactory(configFactory);
163 configService.addListener(configListener);
164
165 readConfiguration();
166
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900167 floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
168 .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
169 .withName(FLOATING_IP_MAP_NAME)
170 .withApplicationId(appId)
171 .build();
172 tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
173 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
174 .withName(TP_PORT_MAP_NAME)
175 .withApplicationId(appId)
176 .build();
177
sangho0c2a3da2016-02-16 13:39:07 +0900178 log.info("onos-openstackrouting started");
179 }
180
181 @Deactivate
182 protected void deactivate() {
183 packetService.removeProcessor(internalPacketProcessor);
Daniel Park81a61a12016-02-26 08:24:44 +0900184 l3EventExecutorService.shutdown();
185 icmpEventExecutorService.shutdown();
186 arpEventExecutorService.shutdown();
187
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900188 floatingIpMap.clear();
189 tpPortNumMap.clear();
190
sangho0c2a3da2016-02-16 13:39:07 +0900191 log.info("onos-openstackrouting stopped");
192 }
193
194
195 @Override
196 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900197 floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
sangho0c2a3da2016-02-16 13:39:07 +0900198 }
199
200 @Override
201 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900202 if (!floatingIpMap.containsKey(openstackFloatingIP.id())) {
203 log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIP.id());
204 return;
205 }
206 if (openstackFloatingIP.portId() == null || openstackFloatingIP.portId().equals("null")) {
207 OpenstackFloatingIP floatingIP = floatingIpMap.get(openstackFloatingIP.id()).value();
208 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
209 .get(PORTNAME_PREFIX_VM.concat(floatingIP.portId().substring(0, 11)));
210 if (portInfo == null) {
211 log.warn("There`s no portInfo information about portId {}", floatingIP.portId());
212 return;
213 }
214 l3EventExecutorService.execute(
215 new OpenstackFloatingIPHandler(rulePopulator, floatingIP, false, portInfo));
216 floatingIpMap.replace(floatingIP.id(), openstackFloatingIP);
217 } else {
218 floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
219 l3EventExecutorService.execute(
220 new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIP, true, null));
221 }
sangho0c2a3da2016-02-16 13:39:07 +0900222 }
223
224 @Override
225 public void deleteFloatingIP(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900226 floatingIpMap.remove(id);
sangho0c2a3da2016-02-16 13:39:07 +0900227 }
228
229 @Override
230 public void createRouter(OpenstackRouter openstackRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900231 }
232
233 @Override
234 public void updateRouter(OpenstackRouter openstackRouter) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900235 if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sanghoefbc0382016-04-06 13:35:38 +0900236 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900237 } else {
238 unsetExternalConnection();
239 }
240 }
241
242 private void unsetExternalConnection() {
243 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
244 internalRouters.forEach(r ->
245 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
246 }
247
248 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
249 List<OpenstackRouter> routers;
250 if (externalConnection) {
251 routers = openstackService.routers()
252 .stream()
253 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
254 .collect(Collectors.toList());
255 } else {
256 routers = openstackService.routers()
257 .stream()
258 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
259 .collect(Collectors.toList());
260 }
261 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900262 }
263
264 @Override
265 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900266 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900267 }
268
269 @Override
270 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900271 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
272 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900273 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
sangho0c2a3da2016-02-16 13:39:07 +0900274 }
275
276 @Override
277 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900278 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900279 }
280
281 @Override
282 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
283 if (floatingIpMap.size() < 1) {
284 log.info("No information in FloatingIpMap");
285 return;
286 }
287 OpenstackFloatingIP floatingIp = associatedFloatingIps()
288 .stream()
289 .filter(fIp -> fIp.portId().equals(portId))
290 .findAny()
291 .orElse(null);
292 if (floatingIp != null && portInfo != null) {
293 l3EventExecutorService.execute(
294 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
295 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
296 .floatingIpAddress(floatingIp.floatingIpAddress())
297 .id(floatingIp.id())
298 .networkId(floatingIp.networkId())
299 .status(floatingIp.status())
300 .tenantId(floatingIp.tenantId());
301 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
302 } else if (portInfo == null) {
303 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
304 }
305 }
306
307 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
308 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
309 floatingIpMap.values()
310 .stream()
311 .filter(fIp -> fIp.value().portId() != null)
312 .forEach(fIp -> fIps.add(fIp.value()));
313 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900314 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900315
316 private void reloadInitL3Rules() {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900317 l3EventExecutorService.submit(() ->
318 openstackService.ports()
319 .stream()
320 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
321 .forEach(p -> {
322 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
323 updateRouterInterface(routerInterface);
324 })
325 );
326
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900327 }
328
329 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
330 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900331 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900332 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
333 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900334 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900335
336 return osBuilder.build();
337 }
338
sangho0c2a3da2016-02-16 13:39:07 +0900339 private class InternalPacketProcessor implements PacketProcessor {
340
341 @Override
342 public void process(PacketContext context) {
343
344 if (context.isHandled()) {
345 return;
Daniel Park81a61a12016-02-26 08:24:44 +0900346 } else if (!context.inPacket().receivedFrom().deviceId().toString()
347 .equals(config.gatewayBridgeId())) {
348 return;
sangho0c2a3da2016-02-16 13:39:07 +0900349 }
350
351 InboundPacket pkt = context.inPacket();
352 Ethernet ethernet = pkt.parsed();
353
Daniel Park81a61a12016-02-26 08:24:44 +0900354 //TODO: Considers IPv6 later.
355 if (ethernet == null) {
356 return;
357 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900358 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900359 switch (iPacket.getProtocol()) {
360 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900361
362 icmpEventExecutorService.submit(() ->
363 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900364 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800365 case IPv4.PROTOCOL_UDP:
366 // don't process DHCP
367 UDP udpPacket = (UDP) iPacket.getPayload();
368 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
369 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
370 break;
371 }
sangho0c2a3da2016-02-16 13:39:07 +0900372 default:
373 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Daniel Park81a61a12016-02-26 08:24:44 +0900374 Port port =
375 getExternalPort(pkt.receivedFrom().deviceId(), config.gatewayExternalInterfaceName());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900376 if (port == null) {
377 log.warn("There`s no external interface");
378 break;
379 }
sangho0c2a3da2016-02-16 13:39:07 +0900380 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
381 Ip4Address.valueOf(iPacket.getSourceAddress()));
382 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900383 portNum, openstackPort, port, config));
sangho0c2a3da2016-02-16 13:39:07 +0900384 break;
385 }
Daniel Park81a61a12016-02-26 08:24:44 +0900386 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
387 arpEventExecutorService.submit(() ->
388 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900389 }
390 }
391
392 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900393 int portNum = findUnusedPortNum();
394 if (portNum == 0) {
395 clearPortNumMap();
396 portNum = findUnusedPortNum();
397 }
398 tpPortNumMap.put(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900399 return portNum;
400 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900401
402 private int findUnusedPortNum() {
403 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
404 if (!tpPortNumMap.containsKey(i)) {
405 return i;
406 }
407 }
408 return 0;
409 }
410
411 }
412
413 private void clearPortNumMap() {
414 tpPortNumMap.entrySet().forEach(e -> {
415 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
416 tpPortNumMap.remove(e.getKey());
417 }
418 });
sangho0c2a3da2016-02-16 13:39:07 +0900419 }
420
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900421 private Port getExternalPort(DeviceId deviceId, String interfaceName) {
422 return deviceService.getPorts(deviceId)
423 .stream()
424 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
425 .findAny()
426 .orElse(null);
427 }
428
sangho0c2a3da2016-02-16 13:39:07 +0900429 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900430 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900431 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900432 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900433 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
434 .values().stream().findFirst().orElse(null);
435 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900436 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900437 return;
438 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900439 if (router.id() == null) {
440 interfaces.forEach(i -> initiateL3Rule(getRouterfromExternalIp(externalIp), i));
441 } else {
442 interfaces.forEach(i -> initiateL3Rule(router, i));
443 }
444
445 }
446
447 private OpenstackRouter getRouterfromExternalIp(Ip4Address externalIp) {
448 OpenstackRouter router = getExternalRouter(true)
449 .stream()
450 .filter(r -> r.gatewayExternalInfo()
451 .externalFixedIps()
452 .values()
453 .stream()
454 .findFirst()
455 .orElse(null)
456 .equals(externalIp))
457 .findAny()
458 .orElse(null);
459 return checkNotNull(router);
sangho0c2a3da2016-02-16 13:39:07 +0900460 }
461
462 private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
463 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900464 .port(routerInterface.portId()).networkId()).segmentId());
sangho0c2a3da2016-02-16 13:39:07 +0900465 rulePopulator.populateExternalRules(vni, router, routerInterface);
466 }
467
468 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900469 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
470 openstackService.ports()
471 .stream()
472 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
473 .filter(p -> p.deviceId().equals(router.id()))
474 .forEach(p -> {
475 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
476 interfaces.add(routerInterface);
477 });
478 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900479 }
480
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900481 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900482 return openstackService.routers().stream().filter(r ->
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900483 r.id().equals(id)).findAny().orElse(null);
sangho0c2a3da2016-02-16 13:39:07 +0900484 }
485
486 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900487 OpenstackPort openstackPort = openstackService.ports().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900488 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900489 return openstackPort.fixedIps().values().stream().filter(ip ->
490 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900491 }
492
Daniel Park81a61a12016-02-26 08:24:44 +0900493 private void readConfiguration() {
494 config = configService.getConfig(appId, OpenstackRoutingConfig.class);
495 if (config == null) {
496 log.error("No configuration found");
497 return;
498 }
499
500 checkNotNull(config.physicalRouterMac());
501 checkNotNull(config.gatewayBridgeId());
502 checkNotNull(config.gatewayExternalInterfaceMac());
503 checkNotNull(config.gatewayExternalInterfaceName());
504
505 log.debug("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
506 config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
507
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900508 rulePopulator = new OpenstackRoutingRulePopulator(appId,
509 openstackService, flowObjectiveService, deviceService, driverService, config);
Daniel Park81a61a12016-02-26 08:24:44 +0900510
511 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
512 openstackService, config, openstackSwitchingService);
513 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, config);
514
515 openstackIcmpHandler.requestPacket(appId);
516 openstackArpHandler.requestPacket(appId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900517 reloadInitL3Rules();
Daniel Park81a61a12016-02-26 08:24:44 +0900518 log.info("OpenstackRouting configured");
519 }
520
521 private class InternalConfigListener implements NetworkConfigListener {
522
523 @Override
524 public void event(NetworkConfigEvent event) {
525 if (!event.configClass().equals(OpenstackRoutingConfig.class)) {
526 return;
527 }
528
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900529 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
530 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
531 l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
532 rulePopulator = new OpenstackRoutingRulePopulator(appId,
533 openstackService, flowObjectiveService, deviceService, driverService, config);
534
Daniel Park81a61a12016-02-26 08:24:44 +0900535 }
536 }
537 }
sangho0c2a3da2016-02-16 13:39:07 +0900538}