blob: 6da152368fe297a166afa3dd2c0d4c45ee1382e7 [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
sangho0c2a3da2016-02-16 13:39:07 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.routing;
17
18import com.google.common.collect.Lists;
sangho0c2a3da2016-02-16 13:39:07 +090019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.packet.Ethernet;
26import org.onlab.packet.IPv4;
27import org.onlab.packet.Ip4Address;
28import org.onlab.packet.MacAddress;
Hyunsun Moon0448ea02016-02-23 14:17:39 -080029import org.onlab.packet.UDP;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090030import org.onlab.util.KryoNamespace;
sangho0c2a3da2016-02-16 13:39:07 +090031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090033import org.onosproject.net.DeviceId;
34import org.onosproject.net.Port;
Daniel Park81a61a12016-02-26 08:24:44 +090035import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigRegistry;
39import org.onosproject.net.config.NetworkConfigService;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +090040import org.onosproject.net.device.DeviceEvent;
41import org.onosproject.net.device.DeviceListener;
sangho0c2a3da2016-02-16 13:39:07 +090042import org.onosproject.net.device.DeviceService;
43import org.onosproject.net.driver.DriverService;
44import org.onosproject.net.flowobjective.FlowObjectiveService;
45import org.onosproject.net.packet.InboundPacket;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketProcessor;
48import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090049import org.onosproject.openstackinterface.OpenstackFloatingIP;
50import org.onosproject.openstackinterface.OpenstackInterfaceService;
51import org.onosproject.openstackinterface.OpenstackPort;
52import org.onosproject.openstackinterface.OpenstackRouter;
53import org.onosproject.openstackinterface.OpenstackRouterInterface;
sangho48907542016-03-28 16:07:07 +090054import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090055import org.onosproject.openstacknetworking.OpenstackPortInfo;
sangho0c2a3da2016-02-16 13:39:07 +090056import org.onosproject.openstacknetworking.OpenstackRoutingService;
sangho48907542016-03-28 16:07:07 +090057import org.onosproject.openstacknetworking.OpenstackSubjectFactories;
Daniel Park81a61a12016-02-26 08:24:44 +090058import org.onosproject.openstacknetworking.OpenstackSwitchingService;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090059import org.onosproject.scalablegateway.api.ScalableGatewayService;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090060import org.onosproject.store.serializers.KryoNamespaces;
61import org.onosproject.store.service.ConsistentMap;
62import org.onosproject.store.service.Serializer;
63import org.onosproject.store.service.StorageService;
sangho0c2a3da2016-02-16 13:39:07 +090064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
67import java.util.Collection;
68import java.util.List;
Daniel Park23193902016-03-24 18:17:19 +090069import java.util.Map;
70import java.util.Optional;
sangho0c2a3da2016-02-16 13:39:07 +090071import java.util.concurrent.ExecutorService;
72import java.util.concurrent.Executors;
73import java.util.stream.Collectors;
74
75import static com.google.common.base.Preconditions.checkNotNull;
76import static org.onlab.util.Tools.groupedThreads;
77
sangho0c2a3da2016-02-16 13:39:07 +090078@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090079@Service
sangho0c2a3da2016-02-16 13:39:07 +090080/**
81 * Populates flow rules about L3 functionality for VMs in Openstack.
82 */
83public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090084
85 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected CoreService coreService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected PacketService packetService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DeviceService deviceService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090097 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park81a61a12016-02-26 08:24:44 +0900100 protected OpenstackSwitchingService openstackSwitchingService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho0c2a3da2016-02-16 13:39:07 +0900103 protected FlowObjectiveService flowObjectiveService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected DriverService driverService;
107
Daniel Park81a61a12016-02-26 08:24:44 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected NetworkConfigService configService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected NetworkConfigRegistry configRegistry;
113
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected StorageService storageService;
Daniel Park81a61a12016-02-26 08:24:44 +0900116
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected ScalableGatewayService gatewayService;
Daniel Park23193902016-03-24 18:17:19 +0900119
sangho0c2a3da2016-02-16 13:39:07 +0900120 private ApplicationId appId;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900121 private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
122 private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900123 // Map<RouterInterface`s portId, Corresponded port`s network id>
124 private ConsistentMap<String, String> routerInterfaceMap;
sangho0c2a3da2016-02-16 13:39:07 +0900125 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900126 private static final String PORT_NAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900127 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900128 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900129 private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900130 private static final String TP_PORT_MAP_NAME = "openstackrouting-tpportnum";
131 private static final String ROUTER_INTERFACE_MAP_NAME = "openstackrouting-routerinterface";
Daniel Park23193902016-03-24 18:17:19 +0900132 private static final String COLON = ":";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900133 private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
134 private static final int TP_PORT_MINIMUM_NUM = 1024;
135 private static final int TP_PORT_MAXIMUM_NUM = 65535;
sangho48907542016-03-28 16:07:07 +0900136
Daniel Park81a61a12016-02-26 08:24:44 +0900137 private final ConfigFactory configFactory =
sangho48907542016-03-28 16:07:07 +0900138 new ConfigFactory(OpenstackSubjectFactories.USER_DEFINED_SUBJECT_FACTORY, OpenstackNetworkingConfig.class,
139 "config") {
Daniel Park81a61a12016-02-26 08:24:44 +0900140 @Override
sangho48907542016-03-28 16:07:07 +0900141 public OpenstackNetworkingConfig createConfig() {
142 return new OpenstackNetworkingConfig();
Daniel Park81a61a12016-02-26 08:24:44 +0900143 }
144 };
sangho48907542016-03-28 16:07:07 +0900145
Daniel Park81a61a12016-02-26 08:24:44 +0900146 private final NetworkConfigListener configListener = new InternalConfigListener();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900147
sangho48907542016-03-28 16:07:07 +0900148 private OpenstackNetworkingConfig config;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900149 private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
150 .register(KryoNamespaces.API)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900151 .register(OpenstackFloatingIP.FloatingIpStatus.class)
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700152 .register(OpenstackFloatingIP.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900153
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900154 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700155 .register(KryoNamespaces.API);
sangho0c2a3da2016-02-16 13:39:07 +0900156
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900157 private static final KryoNamespace.Builder ROUTER_INTERFACE_SERIALIZER = KryoNamespace.newBuilder()
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700158 .register(KryoNamespaces.API);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900159
sangho0c2a3da2016-02-16 13:39:07 +0900160 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900161 private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
sangho0c2a3da2016-02-16 13:39:07 +0900162 private ExecutorService l3EventExecutorService =
163 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
164 private ExecutorService icmpEventExecutorService =
165 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
Daniel Park81a61a12016-02-26 08:24:44 +0900166 private ExecutorService arpEventExecutorService =
167 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
168 private OpenstackIcmpHandler openstackIcmpHandler;
169 private OpenstackRoutingArpHandler openstackArpHandler;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900170 private OpenstackRoutingRulePopulator rulePopulator;
Daniel Park23193902016-03-24 18:17:19 +0900171 private Map<DeviceId, Ip4Address> computeNodeMap;
sangho0c2a3da2016-02-16 13:39:07 +0900172
173 @Activate
174 protected void activate() {
175 appId = coreService.registerApplication(APP_ID);
176 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
Daniel Park81a61a12016-02-26 08:24:44 +0900177 configRegistry.registerConfigFactory(configFactory);
178 configService.addListener(configListener);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900179 deviceService.addListener(internalDeviceListener);
Daniel Park81a61a12016-02-26 08:24:44 +0900180
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900181 floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
182 .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
183 .withName(FLOATING_IP_MAP_NAME)
184 .withApplicationId(appId)
185 .build();
186 tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
187 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
188 .withName(TP_PORT_MAP_NAME)
189 .withApplicationId(appId)
190 .build();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900191 routerInterfaceMap = storageService.<String, String>consistentMapBuilder()
192 .withSerializer(Serializer.using(ROUTER_INTERFACE_SERIALIZER.build()))
193 .withName(ROUTER_INTERFACE_MAP_NAME)
194 .withApplicationId(appId)
195 .build();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900196
sangho48907542016-03-28 16:07:07 +0900197 readConfiguration();
198
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900199 log.info("started");
sangho0c2a3da2016-02-16 13:39:07 +0900200 }
201
202 @Deactivate
203 protected void deactivate() {
204 packetService.removeProcessor(internalPacketProcessor);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900205 deviceService.removeListener(internalDeviceListener);
Daniel Park81a61a12016-02-26 08:24:44 +0900206 l3EventExecutorService.shutdown();
207 icmpEventExecutorService.shutdown();
208 arpEventExecutorService.shutdown();
209
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900210 floatingIpMap.clear();
211 tpPortNumMap.clear();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900212 routerInterfaceMap.clear();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900213
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900214 log.info("stopped");
sangho0c2a3da2016-02-16 13:39:07 +0900215 }
216
217
218 @Override
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900219 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
220 floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
sangho0c2a3da2016-02-16 13:39:07 +0900221 }
222
223 @Override
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900224 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
225 if (!floatingIpMap.containsKey(openstackFloatingIp.id())) {
226 log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIp.id());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900227 return;
228 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900229 if (openstackFloatingIp.portId() == null || openstackFloatingIp.portId().equals("null")) {
230 OpenstackFloatingIP floatingIp = floatingIpMap.get(openstackFloatingIp.id()).value();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900231 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900232 .get(PORTNAME_PREFIX_VM.concat(floatingIp.portId().substring(0, 11)));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900233 if (portInfo == null) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900234 log.warn("There`s no portInfo information about portId {}", floatingIp.portId());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900235 return;
236 }
237 l3EventExecutorService.execute(
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900238 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
239 floatingIpMap.replace(floatingIp.id(), openstackFloatingIp);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900240 } else {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900241 floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900242 l3EventExecutorService.execute(
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900243 new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, true, null));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900244 }
sangho0c2a3da2016-02-16 13:39:07 +0900245 }
246
247 @Override
248 public void deleteFloatingIP(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900249 floatingIpMap.remove(id);
sangho0c2a3da2016-02-16 13:39:07 +0900250 }
251
252 @Override
253 public void createRouter(OpenstackRouter openstackRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900254 }
255
256 @Override
257 public void updateRouter(OpenstackRouter openstackRouter) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900258 if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sanghoefbc0382016-04-06 13:35:38 +0900259 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900260 } else {
261 unsetExternalConnection();
262 }
263 }
264
265 private void unsetExternalConnection() {
266 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
267 internalRouters.forEach(r ->
268 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
269 }
270
271 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
272 List<OpenstackRouter> routers;
273 if (externalConnection) {
274 routers = openstackService.routers()
275 .stream()
276 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
277 .collect(Collectors.toList());
278 } else {
279 routers = openstackService.routers()
280 .stream()
281 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
282 .collect(Collectors.toList());
283 }
284 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900285 }
286
287 @Override
288 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900289 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900290 }
291
292 @Override
293 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900294 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
295 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900296 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900297 setL3Connection(getOpenstackRouter(routerInterface.id()), null);
298 routerInterfaceMap.put(routerInterface.portId(), openstackService.port(routerInterface.portId()).networkId());
299 }
300
sanghod177f8f2016-06-29 21:52:23 +0900301 /**
302 * Set flow rules for traffic between two different subnets when more than one subnets
303 * connected to a router.
304 *
305 * @param openstackRouter OpenstackRouter Info
306 * @param openstackPort OpenstackPort Info
307 */
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900308 private void setL3Connection(OpenstackRouter openstackRouter, OpenstackPort openstackPort) {
309 Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(openstackRouter);
sanghod177f8f2016-06-29 21:52:23 +0900310
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900311 if (interfaceList.size() < 2) {
312 return;
313 }
314 if (openstackPort == null) {
315 interfaceList.forEach(i -> {
316 OpenstackPort interfacePort = openstackService.port(i.portId());
317 openstackService.ports()
318 .stream()
319 .filter(p -> p.networkId().equals(interfacePort.networkId())
320 && !p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
321 .forEach(p -> rulePopulator.populateL3Rules(p,
sanghod177f8f2016-06-29 21:52:23 +0900322 getL3ConnectionList(p.networkId(), interfaceList)));
323
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900324 });
325 } else {
326 rulePopulator.populateL3Rules(openstackPort, getL3ConnectionList(openstackPort.networkId(), interfaceList));
327 }
328
329 }
330
331 private List<OpenstackRouterInterface> getL3ConnectionList(String networkId,
332 Collection<OpenstackRouterInterface> interfaceList) {
333 List<OpenstackRouterInterface> targetList = Lists.newArrayList();
334 interfaceList.forEach(i -> {
335 OpenstackPort port = openstackService.port(i.portId());
336 if (!port.networkId().equals(networkId)) {
337 targetList.add(i);
338 }
339 });
340 return targetList;
sangho0c2a3da2016-02-16 13:39:07 +0900341 }
342
343 @Override
344 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900345 OpenstackRouter router = openstackService.router(routerInterface.id());
346 Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(router);
347 if (interfaceList.size() == 1) {
348 List<OpenstackRouterInterface> newList = Lists.newArrayList();
349 newList.add(routerInterface);
350 interfaceList.forEach(i -> removeL3RulesForRouterInterface(i, router, newList));
351 }
352 removeL3RulesForRouterInterface(routerInterface, router, null);
sangho0c2a3da2016-02-16 13:39:07 +0900353 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900354 routerInterfaceMap.remove(routerInterface.portId());
355 }
356
357 private void removeL3RulesForRouterInterface(OpenstackRouterInterface routerInterface, OpenstackRouter router,
358 List<OpenstackRouterInterface> newList) {
359 openstackService.ports(routerInterfaceMap.get(routerInterface.portId()).value()).forEach(p -> {
360 Ip4Address vmIp = (Ip4Address) p.fixedIps().values().toArray()[0];
361 if (newList == null) {
362 rulePopulator.removeL3Rules(vmIp,
363 getL3ConnectionList(p.networkId(), getOpenstackRouterInterface(router)));
364 } else {
365 rulePopulator.removeL3Rules(vmIp, newList);
366 }
367 }
368 );
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900369 }
370
371 @Override
372 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
373 if (floatingIpMap.size() < 1) {
374 log.info("No information in FloatingIpMap");
375 return;
376 }
377 OpenstackFloatingIP floatingIp = associatedFloatingIps()
378 .stream()
379 .filter(fIp -> fIp.portId().equals(portId))
380 .findAny()
381 .orElse(null);
382 if (floatingIp != null && portInfo != null) {
383 l3EventExecutorService.execute(
384 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
385 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
386 .floatingIpAddress(floatingIp.floatingIpAddress())
387 .id(floatingIp.id())
388 .networkId(floatingIp.networkId())
389 .status(floatingIp.status())
390 .tenantId(floatingIp.tenantId());
391 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
392 } else if (portInfo == null) {
393 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
394 }
395 }
396
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900397 @Override
398 public String networkIdForRouterInterface(String portId) {
399 return routerInterfaceMap.get(portId).value();
400 }
401
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900402 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
403 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
404 floatingIpMap.values()
405 .stream()
406 .filter(fIp -> fIp.value().portId() != null)
407 .forEach(fIp -> fIps.add(fIp.value()));
408 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900409 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900410
411 private void reloadInitL3Rules() {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900412
sanghod177f8f2016-06-29 21:52:23 +0900413 l3EventExecutorService.execute(() ->
414 openstackService.ports()
415 .stream()
416 .forEach(p ->
417 {
418 if (p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)) {
419 updateRouterInterface(portToRouterInterface(p));
420 } else {
421 Optional<Ip4Address> vmIp = p.fixedIps().values().stream().findAny();
422 if (vmIp.isPresent()) {
423 OpenstackFloatingIP floatingIP = getOpenstackFloatingIp(vmIp.get());
424 if (floatingIP != null) {
425 updateFloatingIP(floatingIP);
426 }
427 }
428 }
429 })
430 );
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900431 }
432
433 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
434 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900435 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900436 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
437 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900438 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900439
440 return osBuilder.build();
441 }
442
sangho0c2a3da2016-02-16 13:39:07 +0900443 private class InternalPacketProcessor implements PacketProcessor {
444
445 @Override
446 public void process(PacketContext context) {
447
448 if (context.isHandled()) {
449 return;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900450 } else if (!checkGatewayNode(context.inPacket().receivedFrom().deviceId())) {
Daniel Park81a61a12016-02-26 08:24:44 +0900451 return;
sangho0c2a3da2016-02-16 13:39:07 +0900452 }
453
454 InboundPacket pkt = context.inPacket();
455 Ethernet ethernet = pkt.parsed();
456
Daniel Park81a61a12016-02-26 08:24:44 +0900457 //TODO: Considers IPv6 later.
458 if (ethernet == null) {
459 return;
460 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900461 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900462 switch (iPacket.getProtocol()) {
463 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900464
Daniel Park23193902016-03-24 18:17:19 +0900465 icmpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900466 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900467 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800468 case IPv4.PROTOCOL_UDP:
469 // don't process DHCP
470 UDP udpPacket = (UDP) iPacket.getPayload();
471 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
472 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
473 break;
474 }
sangho0c2a3da2016-02-16 13:39:07 +0900475 default:
476 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900477 DeviceId deviceId = pkt.receivedFrom().deviceId();
478 Port port = null;
479 port = deviceService.getPort(deviceId,
480 gatewayService.getGatewayExternalPorts(deviceId).get(0));
481 if (port != null) {
Daniel Park23193902016-03-24 18:17:19 +0900482 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
483 Ip4Address.valueOf(iPacket.getSourceAddress()));
484 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900485 portNum, openstackPort, port, config));
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900486 } else {
487 log.warn("There`s no external interface");
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900488 }
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900489
sangho0c2a3da2016-02-16 13:39:07 +0900490 break;
491 }
Daniel Park81a61a12016-02-26 08:24:44 +0900492 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park23193902016-03-24 18:17:19 +0900493 arpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900494 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900495 }
496 }
497
498 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900499 int portNum = findUnusedPortNum();
500 if (portNum == 0) {
501 clearPortNumMap();
502 portNum = findUnusedPortNum();
503 }
Daniel Park23193902016-03-24 18:17:19 +0900504 tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900505 return portNum;
506 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900507
508 private int findUnusedPortNum() {
509 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
510 if (!tpPortNumMap.containsKey(i)) {
511 return i;
512 }
513 }
514 return 0;
515 }
516
517 }
518
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900519 private boolean checkGatewayNode(DeviceId deviceId) {
520 return gatewayService.getGatewayDeviceIds().contains(deviceId);
521 }
522
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900523 private void clearPortNumMap() {
524 tpPortNumMap.entrySet().forEach(e -> {
525 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
526 tpPortNumMap.remove(e.getKey());
527 }
528 });
sangho0c2a3da2016-02-16 13:39:07 +0900529 }
530
Daniel Park23193902016-03-24 18:17:19 +0900531 private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900532 return deviceService.getPorts(deviceId)
533 .stream()
534 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
Daniel Park23193902016-03-24 18:17:19 +0900535 .findAny();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900536 }
537
sangho0c2a3da2016-02-16 13:39:07 +0900538 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900539 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900540 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900541 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900542 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
543 .values().stream().findFirst().orElse(null);
544 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900545 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900546 return;
547 }
Daniel Park23193902016-03-24 18:17:19 +0900548 interfaces.forEach(this::initiateL3Rule);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900549 }
550
Daniel Park23193902016-03-24 18:17:19 +0900551 private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) {
552 return getExternalRouter(true)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900553 .stream()
554 .filter(r -> r.gatewayExternalInfo()
555 .externalFixedIps()
556 .values()
557 .stream()
Daniel Park23193902016-03-24 18:17:19 +0900558 .findAny()
559 .get()
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900560 .equals(externalIp))
Daniel Park23193902016-03-24 18:17:19 +0900561 .findAny();
sangho0c2a3da2016-02-16 13:39:07 +0900562 }
563
Daniel Park23193902016-03-24 18:17:19 +0900564 private void initiateL3Rule(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900565 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900566 .port(routerInterface.portId()).networkId()).segmentId());
Daniel Park23193902016-03-24 18:17:19 +0900567 rulePopulator.populateExternalRules(vni);
sangho0c2a3da2016-02-16 13:39:07 +0900568 }
569
570 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900571 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
572 openstackService.ports()
573 .stream()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900574 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
575 && p.deviceId().equals(router.id()))
576 .forEach(p -> interfaces.add(portToRouterInterface(p)));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900577 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900578 }
579
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900580 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900581 return openstackService.routers().stream().filter(r ->
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900582 r.id().equals(id)).iterator().next();
sangho0c2a3da2016-02-16 13:39:07 +0900583 }
584
585 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900586 OpenstackPort openstackPort = openstackService.ports().stream()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900587 .filter(p -> p.macAddress().equals(sourceMac)).iterator().next();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900588 return openstackPort.fixedIps().values().stream().filter(ip ->
589 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900590 }
591
sanghod177f8f2016-06-29 21:52:23 +0900592 private OpenstackFloatingIP getOpenstackFloatingIp(Ip4Address vmIp) {
593 Optional<OpenstackFloatingIP> floatingIp = floatingIpMap.asJavaMap().values().stream()
594 .filter(f -> f.portId() != null && f.fixedIpAddress().equals(vmIp))
595 .findAny();
596
597 if (floatingIp.isPresent()) {
598 return floatingIp.get();
599 }
600 log.debug("There is no floating IP information for VM IP {}", vmIp);
601
602 return null;
603 }
604
Daniel Park81a61a12016-02-26 08:24:44 +0900605 private void readConfiguration() {
sangho48907542016-03-28 16:07:07 +0900606 config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
Daniel Park81a61a12016-02-26 08:24:44 +0900607 if (config == null) {
608 log.error("No configuration found");
609 return;
610 }
611
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900612 rulePopulator = new OpenstackRoutingRulePopulator(appId, openstackService, flowObjectiveService,
613 deviceService, driverService, config, gatewayService);
Daniel Park81a61a12016-02-26 08:24:44 +0900614 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900615 openstackService, config, openstackSwitchingService, gatewayService);
616 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService,
617 config, gatewayService);
Daniel Park81a61a12016-02-26 08:24:44 +0900618 openstackIcmpHandler.requestPacket(appId);
619 openstackArpHandler.requestPacket(appId);
sanghod177f8f2016-06-29 21:52:23 +0900620
621 openstackService.floatingIps().stream()
622 .forEach(f -> floatingIpMap.put(f.id(), f));
623
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900624 reloadInitL3Rules();
sangho48907542016-03-28 16:07:07 +0900625
Daniel Park81a61a12016-02-26 08:24:44 +0900626 log.info("OpenstackRouting configured");
627 }
628
629 private class InternalConfigListener implements NetworkConfigListener {
630
631 @Override
632 public void event(NetworkConfigEvent event) {
sangho48907542016-03-28 16:07:07 +0900633 if (!event.configClass().equals(OpenstackNetworkingConfig.class)) {
Daniel Park81a61a12016-02-26 08:24:44 +0900634 return;
635 }
636
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900637 if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
638 event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
639 l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
Daniel Park81a61a12016-02-26 08:24:44 +0900640 }
641 }
642 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900643
644 private class InternalDeviceListener implements DeviceListener {
645
646 @Override
647 public void event(DeviceEvent deviceEvent) {
648 if (deviceEvent.type() == DeviceEvent.Type.PORT_UPDATED) {
649 Port port = deviceEvent.port();
650 OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
651 .get(port.annotations().value(PORT_NAME));
652 OpenstackPort openstackPort = openstackService.port(port);
653 OpenstackPort interfacePort = openstackService.ports()
654 .stream()
655 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
656 && p.networkId().equals(openstackPort.networkId()))
657 .findAny()
658 .orElse(null);
659 if (portInfo == null && openstackPort == null) {
660 log.warn("As delete event timing issue between routing and switching, Can`t delete L3 rules");
661 return;
662 }
663 if ((port.isEnabled()) && (interfacePort != null)) {
664 OpenstackRouterInterface routerInterface = portToRouterInterface(interfacePort);
665 l3EventExecutorService.execute(() ->
666 setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
667 } else if (interfacePort != null) {
668 OpenstackRouterInterface routerInterface = portToRouterInterface(interfacePort);
669 l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(portInfo.ip(),
670 getL3ConnectionList(portInfo.networkId(),
671 getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id())))));
672 }
673 }
674 }
675 }
676
sangho0c2a3da2016-02-16 13:39:07 +0900677}