blob: b1c0a7490f5c91a2128dddb39ca80286fb6c035b [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.routing;
17
18import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import 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;
29import org.onlab.packet.MacAddress;
Hyunsun Moon0448ea02016-02-23 14:17:39 -080030import org.onlab.packet.UDP;
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;
sangho0c2a3da2016-02-16 13:39:07 +090035import org.onosproject.net.device.DeviceService;
36import org.onosproject.net.driver.DriverService;
37import org.onosproject.net.flowobjective.FlowObjectiveService;
38import org.onosproject.net.packet.InboundPacket;
39import org.onosproject.net.packet.PacketContext;
40import org.onosproject.net.packet.PacketProcessor;
41import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090042import org.onosproject.openstackinterface.OpenstackFloatingIP;
43import org.onosproject.openstackinterface.OpenstackInterfaceService;
44import org.onosproject.openstackinterface.OpenstackPort;
45import org.onosproject.openstackinterface.OpenstackRouter;
46import org.onosproject.openstackinterface.OpenstackRouterInterface;
sangho0c2a3da2016-02-16 13:39:07 +090047import org.onosproject.openstacknetworking.OpenstackRoutingService;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
51import java.util.Collection;
52import java.util.List;
53import java.util.Map;
54import java.util.concurrent.ExecutorService;
55import java.util.concurrent.Executors;
56import java.util.stream.Collectors;
57
58import static com.google.common.base.Preconditions.checkNotNull;
59import static org.onlab.util.Tools.groupedThreads;
60
sangho0c2a3da2016-02-16 13:39:07 +090061@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090062@Service
sangho0c2a3da2016-02-16 13:39:07 +090063/**
64 * Populates flow rules about L3 functionality for VMs in Openstack.
65 */
66public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090067
68 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090069
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected CoreService coreService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected PacketService packetService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected DeviceService deviceService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +090080 protected OpenstackInterfaceService openstackService;
sangho0c2a3da2016-02-16 13:39:07 +090081
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected FlowObjectiveService flowObjectiveService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected DriverService driverService;
87
88 private ApplicationId appId;
89 private Map<String, OpenstackRouterInterface> routerInterfaceMap = Maps.newHashMap();
90 private Map<Integer, String> portNumMap = initPortNumMap();
91 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090092 private static final String PORT_NAME = "portName";
93 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
94
95 // TODO: This will be replaced to get the information from openstackswitchingservice.
96 private static final String EXTERNAL_INTERFACE_NAME = "veth0";
97
sangho0c2a3da2016-02-16 13:39:07 +090098 private Map<Integer, String> initPortNumMap() {
99 Map<Integer, String> map = Maps.newHashMap();
100 for (int i = 1024; i < 65535; i++) {
101 map.put(i, "");
102 }
103 return map;
104 }
105
106 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
107 private ExecutorService l3EventExecutorService =
108 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
109 private ExecutorService icmpEventExecutorService =
110 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
111
112 @Activate
113 protected void activate() {
114 appId = coreService.registerApplication(APP_ID);
115 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
sangho0c2a3da2016-02-16 13:39:07 +0900116 log.info("onos-openstackrouting started");
117 }
118
119 @Deactivate
120 protected void deactivate() {
121 packetService.removeProcessor(internalPacketProcessor);
122 log.info("onos-openstackrouting stopped");
123 }
124
125
126 @Override
127 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
128
129 }
130
131 @Override
132 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
133
134 }
135
136 @Override
137 public void deleteFloatingIP(String id) {
138
139 }
140
141 @Override
142 public void createRouter(OpenstackRouter openstackRouter) {
143 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
144 }
145
146 @Override
147 public void updateRouter(OpenstackRouter openstackRouter) {
148 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
149 }
150
151 @Override
152 public void deleteRouter(String id) {
153 //TODO
154 }
155
156 @Override
157 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
158 routerInterfaceMap.putIfAbsent(routerInterface.portId(), routerInterface);
159 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
160 routerInterfaces.add(routerInterface);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900161 checkExternalConnection(getOpenstackRouter(routerInterface.portId()), routerInterfaces);
sangho0c2a3da2016-02-16 13:39:07 +0900162 }
163
164 @Override
165 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
166 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
167 openstackService, flowObjectiveService, deviceService, driverService);
168 rulePopulator.removeExternalRules(routerInterface);
169 routerInterfaceMap.remove(routerInterface.portId());
170 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900171
172 private void reloadInitL3Rules() {
173 openstackService.ports()
174 .stream()
175 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
176 .forEach(p -> {
177 OpenstackRouterInterface routerInterface = portToRouterInterface(p);
178 updateRouterInterface(routerInterface);
179 });
180 }
181
182 private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
183 OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
184 .id(checkNotNull(p.id()))
185 .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
186 .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
187 .portId(checkNotNull(p.deviceId()));
188
189 return osBuilder.build();
190 }
191
sangho0c2a3da2016-02-16 13:39:07 +0900192 private class InternalPacketProcessor implements PacketProcessor {
193
194 @Override
195 public void process(PacketContext context) {
196
197 if (context.isHandled()) {
198 return;
199 }
200
201 InboundPacket pkt = context.inPacket();
202 Ethernet ethernet = pkt.parsed();
203
204 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
205 IPv4 iPacket = (IPv4) ethernet.getPayload();
206 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
207 openstackService, flowObjectiveService, deviceService,
208 driverService);
209 switch (iPacket.getProtocol()) {
210 case IPv4.PROTOCOL_ICMP:
211 icmpEventExecutorService.execute(new OpenstackIcmpHandler(rulePopulator, context));
212 break;
Hyunsun Moon0448ea02016-02-23 14:17:39 -0800213 case IPv4.PROTOCOL_UDP:
214 // don't process DHCP
215 UDP udpPacket = (UDP) iPacket.getPayload();
216 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
217 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
218 break;
219 }
sangho0c2a3da2016-02-16 13:39:07 +0900220 default:
221 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900222 Port port = getExternalPort(pkt.receivedFrom().deviceId(), EXTERNAL_INTERFACE_NAME);
223 if (port == null) {
224 log.warn("There`s no external interface");
225 break;
226 }
sangho0c2a3da2016-02-16 13:39:07 +0900227 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
228 Ip4Address.valueOf(iPacket.getSourceAddress()));
229 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900230 portNum, openstackPort, port));
sangho0c2a3da2016-02-16 13:39:07 +0900231 break;
232 }
233
234 }
235 }
236
237 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
238 int portNum = portNumMap.keySet().stream()
239 .filter(k -> portNumMap.get(k).equals("")).findFirst().orElse(0);
240 portNumMap.replace(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
241 return portNum;
242 }
243 }
244
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900245 private Port getExternalPort(DeviceId deviceId, String interfaceName) {
246 return deviceService.getPorts(deviceId)
247 .stream()
248 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
249 .findAny()
250 .orElse(null);
251 }
252
sangho0c2a3da2016-02-16 13:39:07 +0900253 private void checkExternalConnection(OpenstackRouter router,
254 Collection<OpenstackRouterInterface> routerInterfaces) {
255 checkNotNull(router, "Router can not be null");
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900256 checkNotNull(routerInterfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900257 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
258 .values().stream().findFirst().orElse(null);
259 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900260 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900261 return;
262 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900263 routerInterfaces.forEach(routerInterface -> initiateL3Rule(router, routerInterface));
sangho0c2a3da2016-02-16 13:39:07 +0900264 }
265
266 private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
267 long vni = Long.parseLong(openstackService.network(openstackService
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900268 .port(routerInterface.id()).networkId()).segmentId());
sangho0c2a3da2016-02-16 13:39:07 +0900269 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
270 openstackService, flowObjectiveService, deviceService, driverService);
271 rulePopulator.populateExternalRules(vni, router, routerInterface);
272 }
273
274 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
275 return routerInterfaceMap.values().stream().filter(i -> i.id().equals(router.id()))
276 .collect(Collectors.toList());
277 }
278
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900279 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900280 return openstackService.routers().stream().filter(r ->
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900281 r.id().equals(id)).findAny().orElse(null);
sangho0c2a3da2016-02-16 13:39:07 +0900282 }
283
284 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900285 OpenstackPort openstackPort = openstackService.ports().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900286 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900287 return checkNotNull(openstackPort.fixedIps().values().stream().findFirst().orElse(null))
sangho0c2a3da2016-02-16 13:39:07 +0900288 .equals(ip4Address) ? openstackPort : null;
289 }
290
291}