blob: edc340ba598563665c23bc53280109c02892b965 [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) {
236 Ip4Address externalIp = openstackRouter.gatewayExternalInfo().externalFixedIps()
237 .values().stream().findFirst().orElse(null);
238 OpenstackRouter router = getRouterfromExternalIp(externalIp);
239 checkExternalConnection(router, getOpenstackRouterInterface(router));
240 } else {
241 unsetExternalConnection();
242 }
243 }
244
245 private void unsetExternalConnection() {
246 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
247 internalRouters.forEach(r ->
248 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
249 }
250
251 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
252 List<OpenstackRouter> routers;
253 if (externalConnection) {
254 routers = openstackService.routers()
255 .stream()
256 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
257 .collect(Collectors.toList());
258 } else {
259 routers = openstackService.routers()
260 .stream()
261 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
262 .collect(Collectors.toList());
263 }
264 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900265 }
266
267 @Override
268 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900269 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900270 }
271
272 @Override
273 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900274 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
275 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900276 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
sangho0c2a3da2016-02-16 13:39:07 +0900277 }
278
279 @Override
280 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900281 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900282 }
283
284 @Override
285 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
286 if (floatingIpMap.size() < 1) {
287 log.info("No information in FloatingIpMap");
288 return;
289 }
290 OpenstackFloatingIP floatingIp = associatedFloatingIps()
291 .stream()
292 .filter(fIp -> fIp.portId().equals(portId))
293 .findAny()
294 .orElse(null);
295 if (floatingIp != null && portInfo != null) {
296 l3EventExecutorService.execute(
297 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
298 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
299 .floatingIpAddress(floatingIp.floatingIpAddress())
300 .id(floatingIp.id())
301 .networkId(floatingIp.networkId())
302 .status(floatingIp.status())
303 .tenantId(floatingIp.tenantId());
304 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
305 } else if (portInfo == null) {
306 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
307 }
308 }
309
310 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
311 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
312 floatingIpMap.values()
313 .stream()
314 .filter(fIp -> fIp.value().portId() != null)
315 .forEach(fIp -> fIps.add(fIp.value()));
316 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900317 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900318
319 private void reloadInitL3Rules() {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900320 l3EventExecutorService.submit(() ->
321 openstackService.ports()
322 .stream()
323 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
324 .forEach(p -> {
325 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
326 updateRouterInterface(routerInterface);
327 })
328 );
329
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900330 }
331
332 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
333 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900334 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900335 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
336 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900337 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900338
339 return osBuilder.build();
340 }
341
sangho0c2a3da2016-02-16 13:39:07 +0900342 private class InternalPacketProcessor implements PacketProcessor {
343
344 @Override
345 public void process(PacketContext context) {
346
347 if (context.isHandled()) {
348 return;
Daniel Park81a61a12016-02-26 08:24:44 +0900349 } else if (!context.inPacket().receivedFrom().deviceId().toString()
350 .equals(config.gatewayBridgeId())) {
351 return;
sangho0c2a3da2016-02-16 13:39:07 +0900352 }
353
354 InboundPacket pkt = context.inPacket();
355 Ethernet ethernet = pkt.parsed();
356
Daniel Park81a61a12016-02-26 08:24:44 +0900357 //TODO: Considers IPv6 later.
358 if (ethernet == null) {
359 return;
360 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900361 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900362 switch (iPacket.getProtocol()) {
363 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900364
365 icmpEventExecutorService.submit(() ->
366 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900367 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800368 case IPv4.PROTOCOL_UDP:
369 // don't process DHCP
370 UDP udpPacket = (UDP) iPacket.getPayload();
371 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
372 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
373 break;
374 }
sangho0c2a3da2016-02-16 13:39:07 +0900375 default:
376 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Daniel Park81a61a12016-02-26 08:24:44 +0900377 Port port =
378 getExternalPort(pkt.receivedFrom().deviceId(), config.gatewayExternalInterfaceName());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900379 if (port == null) {
380 log.warn("There`s no external interface");
381 break;
382 }
sangho0c2a3da2016-02-16 13:39:07 +0900383 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
384 Ip4Address.valueOf(iPacket.getSourceAddress()));
385 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900386 portNum, openstackPort, port, config));
sangho0c2a3da2016-02-16 13:39:07 +0900387 break;
388 }
Daniel Park81a61a12016-02-26 08:24:44 +0900389 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
390 arpEventExecutorService.submit(() ->
391 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900392 }
393 }
394
395 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900396 int portNum = findUnusedPortNum();
397 if (portNum == 0) {
398 clearPortNumMap();
399 portNum = findUnusedPortNum();
400 }
401 tpPortNumMap.put(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900402 return portNum;
403 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900404
405 private int findUnusedPortNum() {
406 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
407 if (!tpPortNumMap.containsKey(i)) {
408 return i;
409 }
410 }
411 return 0;
412 }
413
414 }
415
416 private void clearPortNumMap() {
417 tpPortNumMap.entrySet().forEach(e -> {
418 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
419 tpPortNumMap.remove(e.getKey());
420 }
421 });
sangho0c2a3da2016-02-16 13:39:07 +0900422 }
423
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900424 private Port getExternalPort(DeviceId deviceId, String interfaceName) {
425 return deviceService.getPorts(deviceId)
426 .stream()
427 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
428 .findAny()
429 .orElse(null);
430 }
431
sangho0c2a3da2016-02-16 13:39:07 +0900432 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900433 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900434 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900435 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900436 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
437 .values().stream().findFirst().orElse(null);
438 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900439 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900440 return;
441 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900442 if (router.id() == null) {
443 interfaces.forEach(i -> initiateL3Rule(getRouterfromExternalIp(externalIp), i));
444 } else {
445 interfaces.forEach(i -> initiateL3Rule(router, i));
446 }
447
448 }
449
450 private OpenstackRouter getRouterfromExternalIp(Ip4Address externalIp) {
451 OpenstackRouter router = getExternalRouter(true)
452 .stream()
453 .filter(r -> r.gatewayExternalInfo()
454 .externalFixedIps()
455 .values()
456 .stream()
457 .findFirst()
458 .orElse(null)
459 .equals(externalIp))
460 .findAny()
461 .orElse(null);
462 return checkNotNull(router);
sangho0c2a3da2016-02-16 13:39:07 +0900463 }
464
465 private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
466 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900467 .port(routerInterface.portId()).networkId()).segmentId());
sangho0c2a3da2016-02-16 13:39:07 +0900468 rulePopulator.populateExternalRules(vni, router, routerInterface);
469 }
470
471 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900472 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
473 openstackService.ports()
474 .stream()
475 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
476 .filter(p -> p.deviceId().equals(router.id()))
477 .forEach(p -> {
478 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
479 interfaces.add(routerInterface);
480 });
481 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900482 }
483
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900484 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900485 return openstackService.routers().stream().filter(r ->
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900486 r.id().equals(id)).findAny().orElse(null);
sangho0c2a3da2016-02-16 13:39:07 +0900487 }
488
489 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900490 OpenstackPort openstackPort = openstackService.ports().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900491 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900492 return openstackPort.fixedIps().values().stream().filter(ip ->
493 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900494 }
495
Daniel Park81a61a12016-02-26 08:24:44 +0900496 private void readConfiguration() {
497 config = configService.getConfig(appId, OpenstackRoutingConfig.class);
498 if (config == null) {
499 log.error("No configuration found");
500 return;
501 }
502
503 checkNotNull(config.physicalRouterMac());
504 checkNotNull(config.gatewayBridgeId());
505 checkNotNull(config.gatewayExternalInterfaceMac());
506 checkNotNull(config.gatewayExternalInterfaceName());
507
508 log.debug("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
509 config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
510
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900511 rulePopulator = new OpenstackRoutingRulePopulator(appId,
512 openstackService, flowObjectiveService, deviceService, driverService, config);
Daniel Park81a61a12016-02-26 08:24:44 +0900513
514 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
515 openstackService, config, openstackSwitchingService);
516 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, config);
517
518 openstackIcmpHandler.requestPacket(appId);
519 openstackArpHandler.requestPacket(appId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900520 reloadInitL3Rules();
Daniel Park81a61a12016-02-26 08:24:44 +0900521 log.info("OpenstackRouting configured");
522 }
523
524 private class InternalConfigListener implements NetworkConfigListener {
525
526 @Override
527 public void event(NetworkConfigEvent event) {
528 if (!event.configClass().equals(OpenstackRoutingConfig.class)) {
529 return;
530 }
531
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900532 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
533 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
534 l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
535 rulePopulator = new OpenstackRoutingRulePopulator(appId,
536 openstackService, flowObjectiveService, deviceService, driverService, config);
537
Daniel Park81a61a12016-02-26 08:24:44 +0900538 }
539 }
540 }
sangho0c2a3da2016-02-16 13:39:07 +0900541}