blob: 1e0b9fd5d9c5c6eaf349afb3f6c8e1e7538ac5f9 [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;
sangho6032f342016-07-07 14:32:03 +090019import com.google.common.collect.Sets;
sangho0c2a3da2016-02-16 13:39:07 +090020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
sangho6032f342016-07-07 14:32:03 +090029import org.onlab.packet.IpAddress;
sangho0c2a3da2016-02-16 13:39:07 +090030import org.onlab.packet.MacAddress;
Hyunsun Moon0448ea02016-02-23 14:17:39 -080031import org.onlab.packet.UDP;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090032import org.onlab.util.KryoNamespace;
sangho0c2a3da2016-02-16 13:39:07 +090033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
sangho6032f342016-07-07 14:32:03 +090035import org.onosproject.mastership.MastershipService;
36import org.onosproject.net.DefaultAnnotations;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090037import org.onosproject.net.DeviceId;
sangho6032f342016-07-07 14:32:03 +090038import org.onosproject.net.Host;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090039import org.onosproject.net.Port;
sangho0c2a3da2016-02-16 13:39:07 +090040import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.driver.DriverService;
42import org.onosproject.net.flowobjective.FlowObjectiveService;
sangho6032f342016-07-07 14:32:03 +090043import org.onosproject.net.host.DefaultHostDescription;
44import org.onosproject.net.host.HostDescription;
45import org.onosproject.net.host.HostEvent;
46import org.onosproject.net.host.HostListener;
47import org.onosproject.net.host.HostProvider;
48import org.onosproject.net.host.HostProviderRegistry;
49import org.onosproject.net.host.HostProviderService;
50import org.onosproject.net.host.HostService;
sangho0c2a3da2016-02-16 13:39:07 +090051import org.onosproject.net.packet.InboundPacket;
52import org.onosproject.net.packet.PacketContext;
53import org.onosproject.net.packet.PacketProcessor;
54import org.onosproject.net.packet.PacketService;
sangho6032f342016-07-07 14:32:03 +090055import org.onosproject.net.provider.AbstractProvider;
56import org.onosproject.net.provider.ProviderId;
sangho93447f12016-02-24 00:33:22 +090057import org.onosproject.openstackinterface.OpenstackFloatingIP;
58import org.onosproject.openstackinterface.OpenstackInterfaceService;
59import org.onosproject.openstackinterface.OpenstackPort;
60import org.onosproject.openstackinterface.OpenstackRouter;
61import org.onosproject.openstackinterface.OpenstackRouterInterface;
sangho0c2a3da2016-02-16 13:39:07 +090062import org.onosproject.openstacknetworking.OpenstackRoutingService;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090063import org.onosproject.scalablegateway.api.ScalableGatewayService;
sangho6032f342016-07-07 14:32:03 +090064import org.onosproject.openstacknetworking.routing.OpenstackFloatingIPHandler.Action;
65import org.onosproject.openstacknetworking.Constants;
66import org.onosproject.openstacknode.OpenstackNode;
67import org.onosproject.openstacknode.OpenstackNodeEvent;
68import org.onosproject.openstacknode.OpenstackNodeListener;
69import org.onosproject.openstacknode.OpenstackNodeService;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090070import org.onosproject.store.serializers.KryoNamespaces;
71import org.onosproject.store.service.ConsistentMap;
72import org.onosproject.store.service.Serializer;
73import org.onosproject.store.service.StorageService;
sangho0c2a3da2016-02-16 13:39:07 +090074import org.slf4j.Logger;
75import org.slf4j.LoggerFactory;
76
77import java.util.Collection;
78import java.util.List;
Daniel Park23193902016-03-24 18:17:19 +090079import java.util.Optional;
sangho6032f342016-07-07 14:32:03 +090080import java.util.Set;
sangho0c2a3da2016-02-16 13:39:07 +090081import java.util.concurrent.ExecutorService;
82import java.util.concurrent.Executors;
83import java.util.stream.Collectors;
84
85import static com.google.common.base.Preconditions.checkNotNull;
86import static org.onlab.util.Tools.groupedThreads;
87
sangho0c2a3da2016-02-16 13:39:07 +090088@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090089@Service
sangho0c2a3da2016-02-16 13:39:07 +090090/**
91 * Populates flow rules about L3 functionality for VMs in Openstack.
92 */
93public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090094
95 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected CoreService coreService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected PacketService packetService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected DeviceService deviceService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +0900107 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +0900108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected FlowObjectiveService flowObjectiveService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected DriverService driverService;
114
Daniel Park81a61a12016-02-26 08:24:44 +0900115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900116 protected StorageService storageService;
Daniel Park81a61a12016-02-26 08:24:44 +0900117
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho6032f342016-07-07 14:32:03 +0900119 protected HostService hostService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected HostProviderRegistry hostProviderRegistry;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900125 protected ScalableGatewayService gatewayService;
Daniel Park23193902016-03-24 18:17:19 +0900126
sangho6032f342016-07-07 14:32:03 +0900127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected OpenstackNodeService nodeService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected MastershipService mastershipService;
132
sangho0c2a3da2016-02-16 13:39:07 +0900133 private ApplicationId appId;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900134 private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
135 private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900136 // Map<RouterInterface`s portId, Corresponded port`s network id>
137 private ConsistentMap<String, String> routerInterfaceMap;
sangho6032f342016-07-07 14:32:03 +0900138 private static final ProviderId PID = new ProviderId("of", "org.onosproject.openstackroutering", true);
sangho0c2a3da2016-02-16 13:39:07 +0900139 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900140 private static final String PORT_NAME = "portName";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900141 private static final String PORTNAME_PREFIX_VM = "tap";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900142 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900143 private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900144 private static final String TP_PORT_MAP_NAME = "openstackrouting-tpportnum";
145 private static final String ROUTER_INTERFACE_MAP_NAME = "openstackrouting-routerinterface";
Daniel Park23193902016-03-24 18:17:19 +0900146 private static final String COLON = ":";
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900147 private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
148 private static final int TP_PORT_MINIMUM_NUM = 1024;
149 private static final int TP_PORT_MAXIMUM_NUM = 65535;
sangho48907542016-03-28 16:07:07 +0900150
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900151 private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
152 .register(KryoNamespaces.API)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900153 .register(OpenstackFloatingIP.FloatingIpStatus.class)
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700154 .register(OpenstackFloatingIP.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900155
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900156 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700157 .register(KryoNamespaces.API);
sangho0c2a3da2016-02-16 13:39:07 +0900158
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900159 private static final KryoNamespace.Builder ROUTER_INTERFACE_SERIALIZER = KryoNamespace.newBuilder()
HIGUCHI Yutac0f50452016-05-13 19:26:05 -0700160 .register(KryoNamespaces.API);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900161
sangho0c2a3da2016-02-16 13:39:07 +0900162 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
sangho6032f342016-07-07 14:32:03 +0900163 private InternalHostListener internalHostListener = new InternalHostListener();
164 private InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
sangho0c2a3da2016-02-16 13:39:07 +0900165 private ExecutorService l3EventExecutorService =
166 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
167 private ExecutorService icmpEventExecutorService =
168 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
Daniel Park81a61a12016-02-26 08:24:44 +0900169 private ExecutorService arpEventExecutorService =
170 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
171 private OpenstackIcmpHandler openstackIcmpHandler;
172 private OpenstackRoutingArpHandler openstackArpHandler;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900173 private OpenstackRoutingRulePopulator rulePopulator;
sangho6032f342016-07-07 14:32:03 +0900174
175 private HostProviderService hostProviderService;
176 private final HostProvider hostProvider = new InternalHostProvider();
sangho0c2a3da2016-02-16 13:39:07 +0900177
178 @Activate
179 protected void activate() {
180 appId = coreService.registerApplication(APP_ID);
sangho6032f342016-07-07 14:32:03 +0900181 hostService.addListener(internalHostListener);
182 nodeService.addListener(internalNodeListener);
183 hostProviderService = hostProviderRegistry.register(hostProvider);
Daniel Park81a61a12016-02-26 08:24:44 +0900184
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900185 floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
186 .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
187 .withName(FLOATING_IP_MAP_NAME)
188 .withApplicationId(appId)
189 .build();
190 tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
191 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
192 .withName(TP_PORT_MAP_NAME)
193 .withApplicationId(appId)
194 .build();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900195 routerInterfaceMap = storageService.<String, String>consistentMapBuilder()
196 .withSerializer(Serializer.using(ROUTER_INTERFACE_SERIALIZER.build()))
197 .withName(ROUTER_INTERFACE_MAP_NAME)
198 .withApplicationId(appId)
199 .build();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900200
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900201 log.info("started");
sangho0c2a3da2016-02-16 13:39:07 +0900202 }
203
204 @Deactivate
205 protected void deactivate() {
206 packetService.removeProcessor(internalPacketProcessor);
sangho6032f342016-07-07 14:32:03 +0900207 hostService.removeListener(internalHostListener);
208 nodeService.removeListener(internalNodeListener);
209
Daniel Park81a61a12016-02-26 08:24:44 +0900210 l3EventExecutorService.shutdown();
211 icmpEventExecutorService.shutdown();
212 arpEventExecutorService.shutdown();
213
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900214 floatingIpMap.clear();
215 tpPortNumMap.clear();
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900216 routerInterfaceMap.clear();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900217
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900218 log.info("stopped");
sangho0c2a3da2016-02-16 13:39:07 +0900219 }
220
221
222 @Override
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900223 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
224 floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
sangho0c2a3da2016-02-16 13:39:07 +0900225 }
226
227 @Override
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900228 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
229 if (!floatingIpMap.containsKey(openstackFloatingIp.id())) {
230 log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIp.id());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900231 return;
232 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900233 if (openstackFloatingIp.portId() == null || openstackFloatingIp.portId().equals("null")) {
234 OpenstackFloatingIP floatingIp = floatingIpMap.get(openstackFloatingIp.id()).value();
sangho6032f342016-07-07 14:32:03 +0900235 // XXX When the VM has been removed, host information has been removed or not ???
236 Optional<Host> host = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress().getIp4Address())
237 .stream()
238 .findFirst();
239 if (!host.isPresent()) {
240 log.warn("No Host info with the VM IP the Floating IP address {} is found",
241 openstackFloatingIp.floatingIpAddress());
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900242 return;
243 }
244 l3EventExecutorService.execute(
sangho6032f342016-07-07 14:32:03 +0900245 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, Action.DISSASSOCIATE, host.get()));
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900246 floatingIpMap.replace(floatingIp.id(), openstackFloatingIp);
sangho6032f342016-07-07 14:32:03 +0900247 registerFloatingIpToHostService(openstackFloatingIp, Action.DISSASSOCIATE);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900248 } else {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900249 floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900250 l3EventExecutorService.execute(
sangho6032f342016-07-07 14:32:03 +0900251 new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, Action.ASSOCIATE, null));
252 registerFloatingIpToHostService(openstackFloatingIp, Action.ASSOCIATE);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900253 }
sangho6032f342016-07-07 14:32:03 +0900254
255
sangho0c2a3da2016-02-16 13:39:07 +0900256 }
257
258 @Override
259 public void deleteFloatingIP(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900260 floatingIpMap.remove(id);
sangho0c2a3da2016-02-16 13:39:07 +0900261 }
262
263 @Override
264 public void createRouter(OpenstackRouter openstackRouter) {
sangho0c2a3da2016-02-16 13:39:07 +0900265 }
266
267 @Override
268 public void updateRouter(OpenstackRouter openstackRouter) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900269 if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
sanghoefbc0382016-04-06 13:35:38 +0900270 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900271 } else {
272 unsetExternalConnection();
273 }
274 }
275
276 private void unsetExternalConnection() {
277 Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
278 internalRouters.forEach(r ->
279 getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
280 }
281
282 private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
283 List<OpenstackRouter> routers;
284 if (externalConnection) {
285 routers = openstackService.routers()
286 .stream()
287 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
288 .collect(Collectors.toList());
289 } else {
290 routers = openstackService.routers()
291 .stream()
292 .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
293 .collect(Collectors.toList());
294 }
295 return routers;
sangho0c2a3da2016-02-16 13:39:07 +0900296 }
297
298 @Override
299 public void deleteRouter(String id) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900300 //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
sangho0c2a3da2016-02-16 13:39:07 +0900301 }
302
303 @Override
304 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900305 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
306 routerInterfaces.add(routerInterface);
Daniel Park81a61a12016-02-26 08:24:44 +0900307 checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900308 setL3Connection(getOpenstackRouter(routerInterface.id()), null);
309 routerInterfaceMap.put(routerInterface.portId(), openstackService.port(routerInterface.portId()).networkId());
310 }
311
sanghod177f8f2016-06-29 21:52:23 +0900312 /**
313 * Set flow rules for traffic between two different subnets when more than one subnets
314 * connected to a router.
315 *
316 * @param openstackRouter OpenstackRouter Info
317 * @param openstackPort OpenstackPort Info
318 */
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900319 private void setL3Connection(OpenstackRouter openstackRouter, OpenstackPort openstackPort) {
320 Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(openstackRouter);
sanghod177f8f2016-06-29 21:52:23 +0900321
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900322 if (interfaceList.size() < 2) {
323 return;
324 }
325 if (openstackPort == null) {
326 interfaceList.forEach(i -> {
327 OpenstackPort interfacePort = openstackService.port(i.portId());
328 openstackService.ports()
329 .stream()
330 .filter(p -> p.networkId().equals(interfacePort.networkId())
331 && !p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
332 .forEach(p -> rulePopulator.populateL3Rules(p,
sanghod177f8f2016-06-29 21:52:23 +0900333 getL3ConnectionList(p.networkId(), interfaceList)));
334
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900335 });
336 } else {
337 rulePopulator.populateL3Rules(openstackPort, getL3ConnectionList(openstackPort.networkId(), interfaceList));
338 }
339
340 }
341
342 private List<OpenstackRouterInterface> getL3ConnectionList(String networkId,
343 Collection<OpenstackRouterInterface> interfaceList) {
344 List<OpenstackRouterInterface> targetList = Lists.newArrayList();
345 interfaceList.forEach(i -> {
346 OpenstackPort port = openstackService.port(i.portId());
347 if (!port.networkId().equals(networkId)) {
348 targetList.add(i);
349 }
350 });
351 return targetList;
sangho0c2a3da2016-02-16 13:39:07 +0900352 }
353
354 @Override
355 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900356 OpenstackRouter router = openstackService.router(routerInterface.id());
357 Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(router);
358 if (interfaceList.size() == 1) {
359 List<OpenstackRouterInterface> newList = Lists.newArrayList();
360 newList.add(routerInterface);
361 interfaceList.forEach(i -> removeL3RulesForRouterInterface(i, router, newList));
362 }
363 removeL3RulesForRouterInterface(routerInterface, router, null);
sangho0c2a3da2016-02-16 13:39:07 +0900364 rulePopulator.removeExternalRules(routerInterface);
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900365 routerInterfaceMap.remove(routerInterface.portId());
366 }
367
368 private void removeL3RulesForRouterInterface(OpenstackRouterInterface routerInterface, OpenstackRouter router,
369 List<OpenstackRouterInterface> newList) {
sangho6032f342016-07-07 14:32:03 +0900370 if (!routerInterfaceMap.containsKey(routerInterface.portId())) {
371 log.warn("No router interface information found for {}", routerInterface.portId());
372 return;
373 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900374 openstackService.ports(routerInterfaceMap.get(routerInterface.portId()).value()).forEach(p -> {
375 Ip4Address vmIp = (Ip4Address) p.fixedIps().values().toArray()[0];
376 if (newList == null) {
377 rulePopulator.removeL3Rules(vmIp,
378 getL3ConnectionList(p.networkId(), getOpenstackRouterInterface(router)));
379 } else {
380 rulePopulator.removeL3Rules(vmIp, newList);
381 }
382 }
383 );
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900384 }
385
sangho6032f342016-07-07 14:32:03 +0900386 /*
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900387 @Override
388 public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
389 if (floatingIpMap.size() < 1) {
390 log.info("No information in FloatingIpMap");
391 return;
392 }
393 OpenstackFloatingIP floatingIp = associatedFloatingIps()
394 .stream()
395 .filter(fIp -> fIp.portId().equals(portId))
396 .findAny()
397 .orElse(null);
398 if (floatingIp != null && portInfo != null) {
399 l3EventExecutorService.execute(
400 new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
401 OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
402 .floatingIpAddress(floatingIp.floatingIpAddress())
403 .id(floatingIp.id())
404 .networkId(floatingIp.networkId())
405 .status(floatingIp.status())
406 .tenantId(floatingIp.tenantId());
407 floatingIpMap.replace(floatingIp.id(), fBuilder.build());
408 } else if (portInfo == null) {
409 log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
410 }
411 }
sangho6032f342016-07-07 14:32:03 +0900412 */
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900413
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900414 @Override
415 public String networkIdForRouterInterface(String portId) {
416 return routerInterfaceMap.get(portId).value();
417 }
418
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900419 private Collection<OpenstackFloatingIP> associatedFloatingIps() {
420 List<OpenstackFloatingIP> fIps = Lists.newArrayList();
421 floatingIpMap.values()
422 .stream()
423 .filter(fIp -> fIp.value().portId() != null)
424 .forEach(fIp -> fIps.add(fIp.value()));
425 return fIps;
sangho0c2a3da2016-02-16 13:39:07 +0900426 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900427
428 private void reloadInitL3Rules() {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900429
sanghod177f8f2016-06-29 21:52:23 +0900430 l3EventExecutorService.execute(() ->
431 openstackService.ports()
432 .stream()
433 .forEach(p ->
434 {
435 if (p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)) {
436 updateRouterInterface(portToRouterInterface(p));
437 } else {
438 Optional<Ip4Address> vmIp = p.fixedIps().values().stream().findAny();
439 if (vmIp.isPresent()) {
440 OpenstackFloatingIP floatingIP = getOpenstackFloatingIp(vmIp.get());
441 if (floatingIP != null) {
442 updateFloatingIP(floatingIP);
443 }
444 }
445 }
446 })
447 );
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900448 }
449
450 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
451 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
Daniel Park81a61a12016-02-26 08:24:44 +0900452 .id(checkNotNull(p.deviceId()))
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900453 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
454 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
Daniel Park81a61a12016-02-26 08:24:44 +0900455 .portId(checkNotNull(p.id()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900456
457 return osBuilder.build();
458 }
459
sangho0c2a3da2016-02-16 13:39:07 +0900460 private class InternalPacketProcessor implements PacketProcessor {
461
462 @Override
463 public void process(PacketContext context) {
464
sangho6032f342016-07-07 14:32:03 +0900465 DeviceId senderDeviceId = context.inPacket().receivedFrom().deviceId();
466 if (!nodeService.routerBridge(senderDeviceId).isPresent()) {
467 log.warn("No router bridge for {} is found.", senderDeviceId);
468 return;
469 }
sangho0c2a3da2016-02-16 13:39:07 +0900470 if (context.isHandled()) {
471 return;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900472 } else if (!checkGatewayNode(context.inPacket().receivedFrom().deviceId())) {
Daniel Park81a61a12016-02-26 08:24:44 +0900473 return;
sangho0c2a3da2016-02-16 13:39:07 +0900474 }
475
476 InboundPacket pkt = context.inPacket();
477 Ethernet ethernet = pkt.parsed();
478
Daniel Park81a61a12016-02-26 08:24:44 +0900479 //TODO: Considers IPv6 later.
480 if (ethernet == null) {
481 return;
482 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
sangho0c2a3da2016-02-16 13:39:07 +0900483 IPv4 iPacket = (IPv4) ethernet.getPayload();
sangho0c2a3da2016-02-16 13:39:07 +0900484 switch (iPacket.getProtocol()) {
485 case IPv4.PROTOCOL_ICMP:
Daniel Park81a61a12016-02-26 08:24:44 +0900486
Daniel Park23193902016-03-24 18:17:19 +0900487 icmpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900488 openstackIcmpHandler.processIcmpPacket(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900489 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800490 case IPv4.PROTOCOL_UDP:
491 // don't process DHCP
492 UDP udpPacket = (UDP) iPacket.getPayload();
493 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
494 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
495 break;
496 }
sangho0c2a3da2016-02-16 13:39:07 +0900497 default:
498 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900499 DeviceId deviceId = pkt.receivedFrom().deviceId();
500 Port port = null;
501 port = deviceService.getPort(deviceId,
502 gatewayService.getGatewayExternalPorts(deviceId).get(0));
503 if (port != null) {
Daniel Park23193902016-03-24 18:17:19 +0900504 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
505 Ip4Address.valueOf(iPacket.getSourceAddress()));
506 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
sangho6032f342016-07-07 14:32:03 +0900507 portNum, openstackPort, port));
508
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900509 } else {
510 log.warn("There`s no external interface");
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900511 }
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900512
sangho0c2a3da2016-02-16 13:39:07 +0900513 break;
514 }
Daniel Park81a61a12016-02-26 08:24:44 +0900515 } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Daniel Park23193902016-03-24 18:17:19 +0900516 arpEventExecutorService.execute(() ->
Daniel Park81a61a12016-02-26 08:24:44 +0900517 openstackArpHandler.processArpPacketFromRouter(context, ethernet));
sangho0c2a3da2016-02-16 13:39:07 +0900518 }
519 }
520
521 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900522 int portNum = findUnusedPortNum();
523 if (portNum == 0) {
524 clearPortNumMap();
525 portNum = findUnusedPortNum();
526 }
Daniel Park23193902016-03-24 18:17:19 +0900527 tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
sangho0c2a3da2016-02-16 13:39:07 +0900528 return portNum;
529 }
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900530
531 private int findUnusedPortNum() {
532 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
533 if (!tpPortNumMap.containsKey(i)) {
534 return i;
535 }
536 }
537 return 0;
538 }
539
540 }
541
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900542 private boolean checkGatewayNode(DeviceId deviceId) {
543 return gatewayService.getGatewayDeviceIds().contains(deviceId);
544 }
545
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900546 private void clearPortNumMap() {
547 tpPortNumMap.entrySet().forEach(e -> {
548 if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
549 tpPortNumMap.remove(e.getKey());
550 }
551 });
sangho0c2a3da2016-02-16 13:39:07 +0900552 }
553
Daniel Park23193902016-03-24 18:17:19 +0900554 private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900555 return deviceService.getPorts(deviceId)
556 .stream()
557 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
Daniel Park23193902016-03-24 18:17:19 +0900558 .findAny();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900559 }
560
sangho0c2a3da2016-02-16 13:39:07 +0900561 private void checkExternalConnection(OpenstackRouter router,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900562 Collection<OpenstackRouterInterface> interfaces) {
sangho0c2a3da2016-02-16 13:39:07 +0900563 checkNotNull(router, "Router can not be null");
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900564 checkNotNull(interfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900565 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
566 .values().stream().findFirst().orElse(null);
567 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900568 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900569 return;
570 }
Daniel Park23193902016-03-24 18:17:19 +0900571 interfaces.forEach(this::initiateL3Rule);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900572 }
573
Daniel Park23193902016-03-24 18:17:19 +0900574 private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) {
575 return getExternalRouter(true)
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900576 .stream()
577 .filter(r -> r.gatewayExternalInfo()
578 .externalFixedIps()
579 .values()
580 .stream()
Daniel Park23193902016-03-24 18:17:19 +0900581 .findAny()
582 .get()
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900583 .equals(externalIp))
Daniel Park23193902016-03-24 18:17:19 +0900584 .findAny();
sangho0c2a3da2016-02-16 13:39:07 +0900585 }
586
Daniel Park23193902016-03-24 18:17:19 +0900587 private void initiateL3Rule(OpenstackRouterInterface routerInterface) {
sangho0c2a3da2016-02-16 13:39:07 +0900588 long vni = Long.parseLong(openstackService.network(openstackService
Daniel Park81a61a12016-02-26 08:24:44 +0900589 .port(routerInterface.portId()).networkId()).segmentId());
Daniel Park23193902016-03-24 18:17:19 +0900590 rulePopulator.populateExternalRules(vni);
sangho0c2a3da2016-02-16 13:39:07 +0900591 }
592
593 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900594 List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
595 openstackService.ports()
596 .stream()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900597 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
598 && p.deviceId().equals(router.id()))
599 .forEach(p -> interfaces.add(portToRouterInterface(p)));
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900600 return interfaces;
sangho0c2a3da2016-02-16 13:39:07 +0900601 }
602
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900603 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900604 return openstackService.routers().stream().filter(r ->
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900605 r.id().equals(id)).iterator().next();
sangho0c2a3da2016-02-16 13:39:07 +0900606 }
607
608 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900609 OpenstackPort openstackPort = openstackService.ports().stream()
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900610 .filter(p -> p.macAddress().equals(sourceMac)).iterator().next();
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900611 return openstackPort.fixedIps().values().stream().filter(ip ->
612 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
sangho0c2a3da2016-02-16 13:39:07 +0900613 }
614
sanghod177f8f2016-06-29 21:52:23 +0900615 private OpenstackFloatingIP getOpenstackFloatingIp(Ip4Address vmIp) {
616 Optional<OpenstackFloatingIP> floatingIp = floatingIpMap.asJavaMap().values().stream()
617 .filter(f -> f.portId() != null && f.fixedIpAddress().equals(vmIp))
618 .findAny();
619
620 if (floatingIp.isPresent()) {
621 return floatingIp.get();
622 }
623 log.debug("There is no floating IP information for VM IP {}", vmIp);
624
625 return null;
626 }
627
sangho6032f342016-07-07 14:32:03 +0900628 private Optional<OpenstackPort> getRouterInterfacePort(String networkId) {
629
630 return openstackService.ports()
631 .stream()
632 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
633 && p.networkId().equals(networkId))
634 .findAny();
635 }
636
637 // TODO: Remove the function and the related codes when vRouter is running on different ONOS instance.
638 private void registerFloatingIpToHostService(OpenstackFloatingIP openstackFloatingIp, Action action) {
639
640 Optional<Host> hostOptional = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress())
641 .stream()
642 .findFirst();
643 if (!hostOptional.isPresent()) {
644 log.warn("No host with IP {} is registered and cannot add the floating IP. ",
645 openstackFloatingIp.floatingIpAddress());
Daniel Park81a61a12016-02-26 08:24:44 +0900646 return;
647 }
648
sangho6032f342016-07-07 14:32:03 +0900649 Host host = hostOptional.get();
650 Set<IpAddress> ipAddresses = Sets.newHashSet();
651 if (action == Action.ASSOCIATE) {
652 ipAddresses.add(openstackFloatingIp.floatingIpAddress());
653 }
sanghod177f8f2016-06-29 21:52:23 +0900654
sangho6032f342016-07-07 14:32:03 +0900655 HostDescription hostDescription =
656 new DefaultHostDescription(host.mac(), host.vlan(), host.location(), ipAddresses,
657 (DefaultAnnotations) host.annotations());
sanghod177f8f2016-06-29 21:52:23 +0900658
sangho6032f342016-07-07 14:32:03 +0900659 hostProviderService.hostDetected(host.id(), hostDescription, false);
Daniel Park81a61a12016-02-26 08:24:44 +0900660 }
661
sangho6032f342016-07-07 14:32:03 +0900662 private class InternalHostListener implements HostListener {
Daniel Park81a61a12016-02-26 08:24:44 +0900663
sangho6032f342016-07-07 14:32:03 +0900664 private void hostDetected(Host host) {
665
666 String portId = host.annotations().value(Constants.PORT_ID);
667 OpenstackPort openstackPort = openstackService.port(portId);
668 if (openstackPort == null) {
669 log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
Daniel Park81a61a12016-02-26 08:24:44 +0900670 return;
671 }
672
sangho6032f342016-07-07 14:32:03 +0900673 Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
674 if (routerPort.isPresent()) {
675 OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
676 l3EventExecutorService.execute(() ->
677 setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
678
679 }
680 }
681
682 private void hostRemoved(Host host) {
683 String portId = host.annotations().value(Constants.PORT_ID);
684 OpenstackPort openstackPort = openstackService.port(portId);
685 if (openstackPort == null) {
686 log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
687 return;
688 }
689
690 Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
691 if (routerPort.isPresent()) {
692 OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
693 IpAddress ipAddress = host.ipAddresses().stream().findFirst().get();
694 l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(ipAddress.getIp4Address(),
695 getL3ConnectionList(host.annotations().value(Constants.NETWORK_ID),
696 getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id())))));
697 }
698 }
699
700 private boolean isValidHost(Host host) {
701 return !host.ipAddresses().isEmpty() &&
702 host.annotations().value(Constants.VXLAN_ID) != null &&
703 host.annotations().value(Constants.NETWORK_ID) != null &&
704 host.annotations().value(Constants.TENANT_ID) != null &&
705 host.annotations().value(Constants.PORT_ID) != null;
706 }
707
708 @Override
709 public void event(HostEvent event) {
710 Host host = event.subject();
711 if (!mastershipService.isLocalMaster(host.location().deviceId())) {
712 // do not allow to proceed without mastership
713 return;
714 }
715
716 if (!isValidHost(host)) {
717 log.debug("Invalid host event, ignore it {}", host);
718 return;
719 }
720
721 switch (event.type()) {
722 case HOST_UPDATED:
723 case HOST_ADDED:
724 l3EventExecutorService.execute(() -> hostDetected(host));
725 break;
726 case HOST_REMOVED:
727 l3EventExecutorService.execute(() -> hostRemoved(host));
728 break;
729 default:
730 break;
Daniel Park81a61a12016-02-26 08:24:44 +0900731 }
732 }
733 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900734
sangho6032f342016-07-07 14:32:03 +0900735 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
736
737 private void nodeComplete() {
738
739 rulePopulator = new OpenstackRoutingRulePopulator(appId, openstackService, flowObjectiveService,
740 deviceService, driverService, nodeService, gatewayService);
741 openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService, hostService,
742 openstackService, nodeService, gatewayService);
743 openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, nodeService,
744 gatewayService);
745
746 // Packet handlers must be started AFTER all initialization processes.
747 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
748
749 openstackIcmpHandler.requestPacket(appId);
750 openstackArpHandler.requestPacket(appId);
751
752 openstackService.floatingIps().stream()
753 .forEach(f -> floatingIpMap.put(f.id(), f));
754
755 reloadInitL3Rules();
756 }
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900757
758 @Override
sangho6032f342016-07-07 14:32:03 +0900759 public void event(OpenstackNodeEvent event) {
760 OpenstackNode node = event.node();
761
762 switch (event.type()) {
763 case COMPLETE:
764 log.info("COMPLETE node {} detected", node.hostname());
765 l3EventExecutorService.execute(() -> nodeComplete());
766 break;
767 case INCOMPLETE:
768 break;
769 default:
770 break;
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900771 }
sangho6032f342016-07-07 14:32:03 +0900772
773 }
774 }
775
776 private class InternalHostProvider extends AbstractProvider implements HostProvider {
777
778 /**
779 * Creates a provider with the supplier identifier.
780 */
781 protected InternalHostProvider() {
782 super(PID);
783 }
784
785 @Override
786 public void triggerProbe(Host host) {
787 // nothing to do
Kyuhwi Choi5e65e2c2016-04-01 11:48:15 +0900788 }
789 }
790
sangho0c2a3da2016-02-16 13:39:07 +0900791}