blob: 62e8cdf3d0a43b84de4eda661b1c2351c4e3e961 [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;
sangho0c2a3da2016-02-16 13:39:07 +090040import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.driver.DriverService;
42import org.onosproject.net.flowobjective.FlowObjectiveService;
43import org.onosproject.net.packet.InboundPacket;
44import org.onosproject.net.packet.PacketContext;
45import org.onosproject.net.packet.PacketProcessor;
46import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090047import org.onosproject.openstackinterface.OpenstackFloatingIP;
48import org.onosproject.openstackinterface.OpenstackInterfaceService;
49import org.onosproject.openstackinterface.OpenstackPort;
50import org.onosproject.openstackinterface.OpenstackRouter;
51import org.onosproject.openstackinterface.OpenstackRouterInterface;
sangho48907542016-03-28 16:07:07 +090052import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090053import org.onosproject.openstacknetworking.OpenstackPortInfo;
sangho0c2a3da2016-02-16 13:39:07 +090054import org.onosproject.openstacknetworking.OpenstackRoutingService;
sangho48907542016-03-28 16:07:07 +090055import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
Daniel Park81a61a12016-02-26 08:24:44 +090056import org.onosproject.openstacknetworking.OpenstackSwitchingService;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090057import org.onosproject.store.serializers.KryoNamespaces;
58import org.onosproject.store.service.ConsistentMap;
59import org.onosproject.store.service.Serializer;
60import org.onosproject.store.service.StorageService;
sangho0c2a3da2016-02-16 13:39:07 +090061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
64import java.util.Collection;
65import java.util.List;
Daniel Park23193902016-03-24 18:17:19 +090066import java.util.Map;
67import java.util.Optional;
sangho0c2a3da2016-02-16 13:39:07 +090068import java.util.concurrent.ExecutorService;
69import java.util.concurrent.Executors;
70import java.util.stream.Collectors;
71
72import static com.google.common.base.Preconditions.checkNotNull;
73import static org.onlab.util.Tools.groupedThreads;
74
sangho0c2a3da2016-02-16 13:39:07 +090075@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090076@Service
sangho0c2a3da2016-02-16 13:39:07 +090077/**
78 * Populates flow rules about L3 functionality for VMs in Openstack.
79 */
80public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090081
82 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected CoreService coreService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected PacketService packetService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DeviceService deviceService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090094 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park81a61a12016-02-26 08:24:44 +090097 protected OpenstackSwitchingService openstackSwitchingService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho0c2a3da2016-02-16 13:39:07 +0900100 protected FlowObjectiveService flowObjectiveService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected DriverService driverService;
104
Daniel Park81a61a12016-02-26 08:24:44 +0900105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected NetworkConfigService configService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected NetworkConfigRegistry configRegistry;
110
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected StorageService storageService;
Daniel Park81a61a12016-02-26 08:24:44 +0900113
Daniel Park23193902016-03-24 18:17:19 +0900114
sangho0c2a3da2016-02-16 13:39:07 +0900115 private ApplicationId appId;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900116 private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
117 private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
sangho0c2a3da2016-02-16 13:39:07 +0900118 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900119 private static final String PORT_NAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900120 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900121 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900122 private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
123 private static final String TP_PORT_MAP_NAME = "openstackrouting-portnum";
Daniel Park23193902016-03-24 18:17:19 +0900124 private static final String COLON = ":";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900125 private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
126 private static final int TP_PORT_MINIMUM_NUM = 1024;
127 private static final int TP_PORT_MAXIMUM_NUM = 65535;
sangho48907542016-03-28 16:07:07 +0900128
Daniel Park81a61a12016-02-26 08:24:44 +0900129 private final ConfigFactory configFactory =
sangho48907542016-03-28 16:07:07 +0900130 new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
131 "config") {
Daniel Park81a61a12016-02-26 08:24:44 +0900132 @Override
sangho48907542016-03-28 16:07:07 +0900133 public OpenstackNetworkingConfig createConfig() {
134 return new OpenstackNetworkingConfig();
Daniel Park81a61a12016-02-26 08:24:44 +0900135 }
136 };
sangho48907542016-03-28 16:07:07 +0900137
Daniel Park81a61a12016-02-26 08:24:44 +0900138 private final NetworkConfigListener configListener = new InternalConfigListener();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900139
sangho48907542016-03-28 16:07:07 +0900140 private OpenstackNetworkingConfig config;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900141 private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
142 .register(KryoNamespaces.API)
143 .register(KryoNamespaces.MISC)
144 .register(OpenstackFloatingIP.FloatingIpStatus.class)
145 .register(OpenstackFloatingIP.class)
146 .register(Ip4Address.class)
147 .register(String.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900148
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900149 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
150 .register(KryoNamespaces.API)
151 .register(KryoNamespaces.MISC)
152 .register(Integer.class)
153 .register(String.class);
sangho0c2a3da2016-02-16 13:39:07 +0900154
155 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
156 private ExecutorService l3EventExecutorService =
157 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
158 private ExecutorService icmpEventExecutorService =
159 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
Daniel Park81a61a12016-02-26 08:24:44 +0900160 private ExecutorService arpEventExecutorService =
161 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
162 private OpenstackIcmpHandler openstackIcmpHandler;
163 private OpenstackRoutingArpHandler openstackArpHandler;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900164 private OpenstackRoutingRulePopulator rulePopulator;
Daniel Park23193902016-03-24 18:17:19 +0900165 private Map<DeviceId, Ip4Address> computeNodeMap;
sangho0c2a3da2016-02-16 13:39:07 +0900166
167 @Activate
168 protected void activate() {
169 appId = coreService.registerApplication(APP_ID);
170 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
Daniel Park81a61a12016-02-26 08:24:44 +0900171 configRegistry.registerConfigFactory(configFactory);
172 configService.addListener(configListener);
173
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900174 floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
175 .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
176 .withName(FLOATING_IP_MAP_NAME)
177 .withApplicationId(appId)
178 .build();
179 tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
180 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
181 .withName(TP_PORT_MAP_NAME)
182 .withApplicationId(appId)
183 .build();
184
sangho48907542016-03-28 16:07:07 +0900185 readConfiguration();
186
sangho0c2a3da2016-02-16 13:39:07 +0900187 log.info("onos-openstackrouting started");
188 }
189
190 @Deactivate
191 protected void deactivate() {
192 packetService.removeProcessor(internalPacketProcessor);
Daniel Park81a61a12016-02-26 08:24:44 +0900193 l3EventExecutorService.shutdown();
194 icmpEventExecutorService.shutdown();
195 arpEventExecutorService.shutdown();
196
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900197 floatingIpMap.clear();
198 tpPortNumMap.clear();
199
sangho0c2a3da2016-02-16 13:39:07 +0900200 log.info("onos-openstackrouting stopped");
201 }
202
203
204 @Override
205 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900206 floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
sangho0c2a3da2016-02-16 13:39:07 +0900207 }
208
209 @Override
210 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900211 if (!floatingIpMap.containsKey(openstackFloatingIP.id())) {
212 log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIP.id());
213 return;
214 }
215 if (openstackFloatingIP.portId() == null || openstackFloatingIP.portId().equals("null")) {
216 OpenstackFloatingIP floatingIP = floatingIpMap.get(openstackFloatingIP.id()).value();
217 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
218 .get(PORTNAME_PREFIX_VM.concat(floatingIP.portId().substring(0, 11)));
219 if (portInfo == null) {
220 log.warn("There`s no portInfo information about portId {}", floatingIP.portId());
221 return;
222 }
223 l3EventExecutorService.execute(
224 new OpenstackFloatingIPHandler(rulePopulator, floatingIP, false, portInfo));
225 floatingIpMap.replace(floatingIP.id(), openstackFloatingIP);
226 } else {
227 floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
228 l3EventExecutorService.execute(
229 new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIP, true, null));
230 }
sangho0c2a3da2016-02-16 13:39:07 +0900231 }
232
233 @Override
234 public void deleteFloatingIP(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900235 floatingIpMap.remove(id);
sangho0c2a3da2016-02-16 13:39:07 +0900236 }
237
238 @Override
239 public void createRouter(OpenstackRouter openstackRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900240 }
241
242 @Override
243 public void updateRouter(OpenstackRouter openstackRouter) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900244 if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sanghoefbc0382016-04-06 13:35:38 +0900245 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900246 } else {
247 unsetExternalConnection();
248 }
249 }
250
251 private void unsetExternalConnection() {
252 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
253 internalRouters.forEach(r ->
254 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
255 }
256
257 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
258 List<OpenstackRouter> routers;
259 if (externalConnection) {
260 routers = openstackService.routers()
261 .stream()
262 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
263 .collect(Collectors.toList());
264 } else {
265 routers = openstackService.routers()
266 .stream()
267 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
268 .collect(Collectors.toList());
269 }
270 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900271 }
272
273 @Override
274 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900275 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900276 }
277
278 @Override
279 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900280 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
281 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900282 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
sangho0c2a3da2016-02-16 13:39:07 +0900283 }
284
285 @Override
286 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900287 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900288 }
289
290 @Override
291 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
292 if (floatingIpMap.size() < 1) {
293 log.info("No information in FloatingIpMap");
294 return;
295 }
296 OpenstackFloatingIP floatingIp = associatedFloatingIps()
297 .stream()
298 .filter(fIp -> fIp.portId().equals(portId))
299 .findAny()
300 .orElse(null);
301 if (floatingIp != null && portInfo != null) {
302 l3EventExecutorService.execute(
303 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
304 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
305 .floatingIpAddress(floatingIp.floatingIpAddress())
306 .id(floatingIp.id())
307 .networkId(floatingIp.networkId())
308 .status(floatingIp.status())
309 .tenantId(floatingIp.tenantId());
310 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
311 } else if (portInfo == null) {
312 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
313 }
314 }
315
316 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
317 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
318 floatingIpMap.values()
319 .stream()
320 .filter(fIp -> fIp.value().portId() != null)
321 .forEach(fIp -> fIps.add(fIp.value()));
322 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900323 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900324
325 private void reloadInitL3Rules() {
Daniel Park23193902016-03-24 18:17:19 +0900326 l3EventExecutorService.execute(() ->
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900327 openstackService.ports()
328 .stream()
329 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
330 .forEach(p -> {
331 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
332 updateRouterInterface(routerInterface);
333 })
334 );
335
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900336 }
337
338 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
339 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900340 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900341 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
342 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900343 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900344
345 return osBuilder.build();
346 }
347
sangho0c2a3da2016-02-16 13:39:07 +0900348 private class InternalPacketProcessor implements PacketProcessor {
349
350 @Override
351 public void process(PacketContext context) {
352
353 if (context.isHandled()) {
354 return;
Daniel Park81a61a12016-02-26 08:24:44 +0900355 } else if (!context.inPacket().receivedFrom().deviceId().toString()
356 .equals(config.gatewayBridgeId())) {
357 return;
sangho0c2a3da2016-02-16 13:39:07 +0900358 }
359
360 InboundPacket pkt = context.inPacket();
361 Ethernet ethernet = pkt.parsed();
362
Daniel Park81a61a12016-02-26 08:24:44 +0900363 //TODO: Considers IPv6 later.
364 if (ethernet == null) {
365 return;
366 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900367 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900368 switch (iPacket.getProtocol()) {
369 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900370
Daniel Park23193902016-03-24 18:17:19 +0900371 icmpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900372 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900373 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800374 case IPv4.PROTOCOL_UDP:
375 // don't process DHCP
376 UDP udpPacket = (UDP) iPacket.getPayload();
377 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
378 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
379 break;
380 }
sangho0c2a3da2016-02-16 13:39:07 +0900381 default:
382 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Daniel Park23193902016-03-24 18:17:19 +0900383 Optional<Port> port =
Daniel Park81a61a12016-02-26 08:24:44 +0900384 getExternalPort(pkt.receivedFrom().deviceId(), config.gatewayExternalInterfaceName());
Daniel Park23193902016-03-24 18:17:19 +0900385
386 if (!port.isPresent()) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900387 log.warn("There`s no external interface");
Daniel Park23193902016-03-24 18:17:19 +0900388 } else {
389 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
390 Ip4Address.valueOf(iPacket.getSourceAddress()));
391 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
392 portNum, openstackPort, port.get(), config));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900393 }
sangho0c2a3da2016-02-16 13:39:07 +0900394 break;
395 }
Daniel Park81a61a12016-02-26 08:24:44 +0900396 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park23193902016-03-24 18:17:19 +0900397 arpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900398 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900399 }
400 }
401
402 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900403 int portNum = findUnusedPortNum();
404 if (portNum == 0) {
405 clearPortNumMap();
406 portNum = findUnusedPortNum();
407 }
Daniel Park23193902016-03-24 18:17:19 +0900408 tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900409 return portNum;
410 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900411
412 private int findUnusedPortNum() {
413 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
414 if (!tpPortNumMap.containsKey(i)) {
415 return i;
416 }
417 }
418 return 0;
419 }
420
421 }
422
423 private void clearPortNumMap() {
424 tpPortNumMap.entrySet().forEach(e -> {
425 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
426 tpPortNumMap.remove(e.getKey());
427 }
428 });
sangho0c2a3da2016-02-16 13:39:07 +0900429 }
430
Daniel Park23193902016-03-24 18:17:19 +0900431 private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900432 return deviceService.getPorts(deviceId)
433 .stream()
434 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
Daniel Park23193902016-03-24 18:17:19 +0900435 .findAny();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900436 }
437
sangho0c2a3da2016-02-16 13:39:07 +0900438 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900439 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900440 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900441 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900442 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
443 .values().stream().findFirst().orElse(null);
444 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900445 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900446 return;
447 }
Daniel Park23193902016-03-24 18:17:19 +0900448 interfaces.forEach(this::initiateL3Rule);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900449 }
450
Daniel Park23193902016-03-24 18:17:19 +0900451 private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) {
452 return getExternalRouter(true)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900453 .stream()
454 .filter(r -> r.gatewayExternalInfo()
455 .externalFixedIps()
456 .values()
457 .stream()
Daniel Park23193902016-03-24 18:17:19 +0900458 .findAny()
459 .get()
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900460 .equals(externalIp))
Daniel Park23193902016-03-24 18:17:19 +0900461 .findAny();
sangho0c2a3da2016-02-16 13:39:07 +0900462 }
463
Daniel Park23193902016-03-24 18:17:19 +0900464 private void initiateL3Rule(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900465 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900466 .port(routerInterface.portId()).networkId()).segmentId());
Daniel Park23193902016-03-24 18:17:19 +0900467 rulePopulator.populateExternalRules(vni);
sangho0c2a3da2016-02-16 13:39:07 +0900468 }
469
470 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900471 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
472 openstackService.ports()
473 .stream()
474 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
475 .filter(p -> p.deviceId().equals(router.id()))
476 .forEach(p -> {
Daniel Park23193902016-03-24 18:17:19 +0900477 interfaces.add(portToRouterInterface(p));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900478 });
479 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900480 }
481
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900482 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900483 return openstackService.routers().stream().filter(r ->
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900484 r.id().equals(id)).findAny().orElse(null);
sangho0c2a3da2016-02-16 13:39:07 +0900485 }
486
487 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900488 OpenstackPort openstackPort = openstackService.ports().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900489 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900490 return openstackPort.fixedIps().values().stream().filter(ip ->
491 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900492 }
493
Daniel Park81a61a12016-02-26 08:24:44 +0900494 private void readConfiguration() {
sangho48907542016-03-28 16:07:07 +0900495 config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
Daniel Park81a61a12016-02-26 08:24:44 +0900496 if (config == null) {
497 log.error("No configuration found");
498 return;
499 }
500
501 checkNotNull(config.physicalRouterMac());
502 checkNotNull(config.gatewayBridgeId());
503 checkNotNull(config.gatewayExternalInterfaceMac());
504 checkNotNull(config.gatewayExternalInterfaceName());
505
sangho48907542016-03-28 16:07:07 +0900506 log.warn("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
Daniel Park81a61a12016-02-26 08:24:44 +0900507 config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
508
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900509 rulePopulator = new OpenstackRoutingRulePopulator(appId,
510 openstackService, flowObjectiveService, deviceService, driverService, config);
Daniel Park81a61a12016-02-26 08:24:44 +0900511
512 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
513 openstackService, config, openstackSwitchingService);
514 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, config);
515
516 openstackIcmpHandler.requestPacket(appId);
517 openstackArpHandler.requestPacket(appId);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900518 reloadInitL3Rules();
sangho48907542016-03-28 16:07:07 +0900519
Daniel Park81a61a12016-02-26 08:24:44 +0900520 log.info("OpenstackRouting configured");
521 }
522
523 private class InternalConfigListener implements NetworkConfigListener {
524
525 @Override
526 public void event(NetworkConfigEvent event) {
sangho48907542016-03-28 16:07:07 +0900527 if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
Daniel Park81a61a12016-02-26 08:24:44 +0900528 return;
529 }
530
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900531 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
532 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
533 l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
Daniel Park81a61a12016-02-26 08:24:44 +0900534 }
535 }
536 }
sangho0c2a3da2016-02-16 13:39:07 +0900537}