blob: 891b622b91fca1ff91699596e814a1ce240cf39f [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;
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;
Daniel Park23193902016-03-24 18:17:19 +090065import java.util.Map;
66import java.util.Optional;
sangho0c2a3da2016-02-16 13:39:07 +090067import java.util.concurrent.ExecutorService;
68import java.util.concurrent.Executors;
69import java.util.stream.Collectors;
70
71import static com.google.common.base.Preconditions.checkNotNull;
72import static org.onlab.util.Tools.groupedThreads;
73
sangho0c2a3da2016-02-16 13:39:07 +090074@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090075@Service
sangho0c2a3da2016-02-16 13:39:07 +090076/**
77 * Populates flow rules about L3 functionality for VMs in Openstack.
78 */
79public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090080
81 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090082
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected CoreService coreService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected PacketService packetService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected DeviceService deviceService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090093 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park81a61a12016-02-26 08:24:44 +090096 protected OpenstackSwitchingService openstackSwitchingService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho0c2a3da2016-02-16 13:39:07 +090099 protected FlowObjectiveService flowObjectiveService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected DriverService driverService;
103
Daniel Park81a61a12016-02-26 08:24:44 +0900104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected NetworkConfigService configService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected NetworkConfigRegistry configRegistry;
109
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected StorageService storageService;
Daniel Park81a61a12016-02-26 08:24:44 +0900112
Daniel Park23193902016-03-24 18:17:19 +0900113
sangho0c2a3da2016-02-16 13:39:07 +0900114 private ApplicationId appId;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900115 private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
116 private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
sangho0c2a3da2016-02-16 13:39:07 +0900117 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900118 private static final String PORT_NAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900119 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900120 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900121 private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
122 private static final String TP_PORT_MAP_NAME = "openstackrouting-portnum";
Daniel Park23193902016-03-24 18:17:19 +0900123 private static final String COLON = ":";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900124 private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
125 private static final int TP_PORT_MINIMUM_NUM = 1024;
126 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Daniel Park81a61a12016-02-26 08:24:44 +0900127 private final ConfigFactory configFactory =
128 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackRoutingConfig.class, "openstackrouting") {
129 @Override
130 public OpenstackRoutingConfig createConfig() {
131 return new OpenstackRoutingConfig();
132 }
133 };
134 private final NetworkConfigListener configListener = new InternalConfigListener();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900135
Daniel Park81a61a12016-02-26 08:24:44 +0900136 private OpenstackRoutingConfig config;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900137 private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
138 .register(KryoNamespaces.API)
139 .register(KryoNamespaces.MISC)
140 .register(OpenstackFloatingIP.FloatingIpStatus.class)
141 .register(OpenstackFloatingIP.class)
142 .register(Ip4Address.class)
143 .register(String.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900144
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900145 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
146 .register(KryoNamespaces.API)
147 .register(KryoNamespaces.MISC)
148 .register(Integer.class)
149 .register(String.class);
sangho0c2a3da2016-02-16 13:39:07 +0900150
151 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
152 private ExecutorService l3EventExecutorService =
153 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
154 private ExecutorService icmpEventExecutorService =
155 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
Daniel Park81a61a12016-02-26 08:24:44 +0900156 private ExecutorService arpEventExecutorService =
157 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
158 private OpenstackIcmpHandler openstackIcmpHandler;
159 private OpenstackRoutingArpHandler openstackArpHandler;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900160 private OpenstackRoutingRulePopulator rulePopulator;
Daniel Park23193902016-03-24 18:17:19 +0900161 private Map<DeviceId, Ip4Address> computeNodeMap;
sangho0c2a3da2016-02-16 13:39:07 +0900162
163 @Activate
164 protected void activate() {
165 appId = coreService.registerApplication(APP_ID);
166 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
Daniel Park81a61a12016-02-26 08:24:44 +0900167 configRegistry.registerConfigFactory(configFactory);
168 configService.addListener(configListener);
169
170 readConfiguration();
171
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900172 floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
173 .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
174 .withName(FLOATING_IP_MAP_NAME)
175 .withApplicationId(appId)
176 .build();
177 tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
178 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
179 .withName(TP_PORT_MAP_NAME)
180 .withApplicationId(appId)
181 .build();
182
sangho0c2a3da2016-02-16 13:39:07 +0900183 log.info("onos-openstackrouting started");
184 }
185
186 @Deactivate
187 protected void deactivate() {
188 packetService.removeProcessor(internalPacketProcessor);
Daniel Park81a61a12016-02-26 08:24:44 +0900189 l3EventExecutorService.shutdown();
190 icmpEventExecutorService.shutdown();
191 arpEventExecutorService.shutdown();
192
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900193 floatingIpMap.clear();
194 tpPortNumMap.clear();
195
sangho0c2a3da2016-02-16 13:39:07 +0900196 log.info("onos-openstackrouting stopped");
197 }
198
199
200 @Override
201 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900202 floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
sangho0c2a3da2016-02-16 13:39:07 +0900203 }
204
205 @Override
206 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900207 if (!floatingIpMap.containsKey(openstackFloatingIP.id())) {
208 log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIP.id());
209 return;
210 }
211 if (openstackFloatingIP.portId() == null || openstackFloatingIP.portId().equals("null")) {
212 OpenstackFloatingIP floatingIP = floatingIpMap.get(openstackFloatingIP.id()).value();
213 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
214 .get(PORTNAME_PREFIX_VM.concat(floatingIP.portId().substring(0, 11)));
215 if (portInfo == null) {
216 log.warn("There`s no portInfo information about portId {}", floatingIP.portId());
217 return;
218 }
219 l3EventExecutorService.execute(
220 new OpenstackFloatingIPHandler(rulePopulator, floatingIP, false, portInfo));
221 floatingIpMap.replace(floatingIP.id(), openstackFloatingIP);
222 } else {
223 floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
224 l3EventExecutorService.execute(
225 new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIP, true, null));
226 }
sangho0c2a3da2016-02-16 13:39:07 +0900227 }
228
229 @Override
230 public void deleteFloatingIP(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900231 floatingIpMap.remove(id);
sangho0c2a3da2016-02-16 13:39:07 +0900232 }
233
234 @Override
235 public void createRouter(OpenstackRouter openstackRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900236 }
237
238 @Override
239 public void updateRouter(OpenstackRouter openstackRouter) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900240 if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sanghoefbc0382016-04-06 13:35:38 +0900241 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900242 } else {
243 unsetExternalConnection();
244 }
245 }
246
247 private void unsetExternalConnection() {
248 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
249 internalRouters.forEach(r ->
250 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
251 }
252
253 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
254 List<OpenstackRouter> routers;
255 if (externalConnection) {
256 routers = openstackService.routers()
257 .stream()
258 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
259 .collect(Collectors.toList());
260 } else {
261 routers = openstackService.routers()
262 .stream()
263 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
264 .collect(Collectors.toList());
265 }
266 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900267 }
268
269 @Override
270 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900271 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900272 }
273
274 @Override
275 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900276 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
277 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900278 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
sangho0c2a3da2016-02-16 13:39:07 +0900279 }
280
281 @Override
282 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900283 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900284 }
285
286 @Override
287 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
288 if (floatingIpMap.size() < 1) {
289 log.info("No information in FloatingIpMap");
290 return;
291 }
292 OpenstackFloatingIP floatingIp = associatedFloatingIps()
293 .stream()
294 .filter(fIp -> fIp.portId().equals(portId))
295 .findAny()
296 .orElse(null);
297 if (floatingIp != null && portInfo != null) {
298 l3EventExecutorService.execute(
299 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
300 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
301 .floatingIpAddress(floatingIp.floatingIpAddress())
302 .id(floatingIp.id())
303 .networkId(floatingIp.networkId())
304 .status(floatingIp.status())
305 .tenantId(floatingIp.tenantId());
306 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
307 } else if (portInfo == null) {
308 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
309 }
310 }
311
312 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
313 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
314 floatingIpMap.values()
315 .stream()
316 .filter(fIp -> fIp.value().portId() != null)
317 .forEach(fIp -> fIps.add(fIp.value()));
318 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900319 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900320
321 private void reloadInitL3Rules() {
Daniel Park23193902016-03-24 18:17:19 +0900322 l3EventExecutorService.execute(() ->
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900323 openstackService.ports()
324 .stream()
325 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
326 .forEach(p -> {
327 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
328 updateRouterInterface(routerInterface);
329 })
330 );
331
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900332 }
333
334 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
335 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900336 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900337 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
338 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900339 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900340
341 return osBuilder.build();
342 }
343
sangho0c2a3da2016-02-16 13:39:07 +0900344 private class InternalPacketProcessor implements PacketProcessor {
345
346 @Override
347 public void process(PacketContext context) {
348
349 if (context.isHandled()) {
350 return;
Daniel Park81a61a12016-02-26 08:24:44 +0900351 } else if (!context.inPacket().receivedFrom().deviceId().toString()
352 .equals(config.gatewayBridgeId())) {
353 return;
sangho0c2a3da2016-02-16 13:39:07 +0900354 }
355
356 InboundPacket pkt = context.inPacket();
357 Ethernet ethernet = pkt.parsed();
358
Daniel Park81a61a12016-02-26 08:24:44 +0900359 //TODO: Considers IPv6 later.
360 if (ethernet == null) {
361 return;
362 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900363 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900364 switch (iPacket.getProtocol()) {
365 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900366
Daniel Park23193902016-03-24 18:17:19 +0900367 icmpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900368 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900369 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800370 case IPv4.PROTOCOL_UDP:
371 // don't process DHCP
372 UDP udpPacket = (UDP) iPacket.getPayload();
373 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
374 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
375 break;
376 }
sangho0c2a3da2016-02-16 13:39:07 +0900377 default:
378 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Daniel Park23193902016-03-24 18:17:19 +0900379 Optional<Port> port =
Daniel Park81a61a12016-02-26 08:24:44 +0900380 getExternalPort(pkt.receivedFrom().deviceId(), config.gatewayExternalInterfaceName());
Daniel Park23193902016-03-24 18:17:19 +0900381
382 if (!port.isPresent()) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900383 log.warn("There`s no external interface");
Daniel Park23193902016-03-24 18:17:19 +0900384 } else {
385 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
386 Ip4Address.valueOf(iPacket.getSourceAddress()));
387 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
388 portNum, openstackPort, port.get(), config));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900389 }
sangho0c2a3da2016-02-16 13:39:07 +0900390 break;
391 }
Daniel Park81a61a12016-02-26 08:24:44 +0900392 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park23193902016-03-24 18:17:19 +0900393 arpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900394 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900395 }
396 }
397
398 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900399 int portNum = findUnusedPortNum();
400 if (portNum == 0) {
401 clearPortNumMap();
402 portNum = findUnusedPortNum();
403 }
Daniel Park23193902016-03-24 18:17:19 +0900404 tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900405 return portNum;
406 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900407
408 private int findUnusedPortNum() {
409 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
410 if (!tpPortNumMap.containsKey(i)) {
411 return i;
412 }
413 }
414 return 0;
415 }
416
417 }
418
419 private void clearPortNumMap() {
420 tpPortNumMap.entrySet().forEach(e -> {
421 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
422 tpPortNumMap.remove(e.getKey());
423 }
424 });
sangho0c2a3da2016-02-16 13:39:07 +0900425 }
426
Daniel Park23193902016-03-24 18:17:19 +0900427 private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900428 return deviceService.getPorts(deviceId)
429 .stream()
430 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
Daniel Park23193902016-03-24 18:17:19 +0900431 .findAny();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900432 }
433
sangho0c2a3da2016-02-16 13:39:07 +0900434 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900435 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900436 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900437 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900438 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
439 .values().stream().findFirst().orElse(null);
440 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900441 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900442 return;
443 }
Daniel Park23193902016-03-24 18:17:19 +0900444 interfaces.forEach(this::initiateL3Rule);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900445 }
446
Daniel Park23193902016-03-24 18:17:19 +0900447 private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) {
448 return getExternalRouter(true)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900449 .stream()
450 .filter(r -> r.gatewayExternalInfo()
451 .externalFixedIps()
452 .values()
453 .stream()
Daniel Park23193902016-03-24 18:17:19 +0900454 .findAny()
455 .get()
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900456 .equals(externalIp))
Daniel Park23193902016-03-24 18:17:19 +0900457 .findAny();
sangho0c2a3da2016-02-16 13:39:07 +0900458 }
459
Daniel Park23193902016-03-24 18:17:19 +0900460 private void initiateL3Rule(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900461 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900462 .port(routerInterface.portId()).networkId()).segmentId());
Daniel Park23193902016-03-24 18:17:19 +0900463 rulePopulator.populateExternalRules(vni);
sangho0c2a3da2016-02-16 13:39:07 +0900464 }
465
466 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900467 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
468 openstackService.ports()
469 .stream()
470 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
471 .filter(p -> p.deviceId().equals(router.id()))
472 .forEach(p -> {
Daniel Park23193902016-03-24 18:17:19 +0900473 interfaces.add(portToRouterInterface(p));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900474 });
475 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900476 }
477
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900478 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900479 return openstackService.routers().stream().filter(r ->
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900480 r.id().equals(id)).findAny().orElse(null);
sangho0c2a3da2016-02-16 13:39:07 +0900481 }
482
483 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900484 OpenstackPort openstackPort = openstackService.ports().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900485 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900486 return openstackPort.fixedIps().values().stream().filter(ip ->
487 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900488 }
489
Daniel Park81a61a12016-02-26 08:24:44 +0900490 private void readConfiguration() {
491 config = configService.getConfig(appId, OpenstackRoutingConfig.class);
492 if (config == null) {
493 log.error("No configuration found");
494 return;
495 }
496
497 checkNotNull(config.physicalRouterMac());
498 checkNotNull(config.gatewayBridgeId());
499 checkNotNull(config.gatewayExternalInterfaceMac());
500 checkNotNull(config.gatewayExternalInterfaceName());
501
502 log.debug("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
503 config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
504
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900505 rulePopulator = new OpenstackRoutingRulePopulator(appId,
506 openstackService, flowObjectiveService, deviceService, driverService, config);
Daniel Park81a61a12016-02-26 08:24:44 +0900507
508 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
509 openstackService, config, openstackSwitchingService);
510 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, config);
511
512 openstackIcmpHandler.requestPacket(appId);
513 openstackArpHandler.requestPacket(appId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900514 reloadInitL3Rules();
Daniel Park81a61a12016-02-26 08:24:44 +0900515 log.info("OpenstackRouting configured");
516 }
517
518 private class InternalConfigListener implements NetworkConfigListener {
519
520 @Override
521 public void event(NetworkConfigEvent event) {
522 if (!event.configClass().equals(OpenstackRoutingConfig.class)) {
523 return;
524 }
525
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900526 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
527 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
528 l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
Daniel Park81a61a12016-02-26 08:24:44 +0900529 }
530 }
531 }
sangho0c2a3da2016-02-16 13:39:07 +0900532}