blob: ab8c386d62332a4164a394841c7603fb10023c53 [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;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090032import org.onosproject.net.DeviceId;
33import org.onosproject.net.Port;
sangho0c2a3da2016-02-16 13:39:07 +090034import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.driver.DriverService;
36import org.onosproject.net.flowobjective.FlowObjectiveService;
37import org.onosproject.net.packet.InboundPacket;
38import org.onosproject.net.packet.PacketContext;
39import org.onosproject.net.packet.PacketProcessor;
40import org.onosproject.net.packet.PacketService;
41import org.onosproject.openstacknetworking.OpenstackFloatingIP;
42import org.onosproject.openstacknetworking.OpenstackNetworkingService;
43import org.onosproject.openstacknetworking.OpenstackPort;
44import org.onosproject.openstacknetworking.OpenstackRouter;
45import org.onosproject.openstacknetworking.OpenstackRouterInterface;
46import org.onosproject.openstacknetworking.OpenstackRoutingService;
47import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
50import java.util.Collection;
51import java.util.List;
52import java.util.Map;
53import java.util.concurrent.ExecutorService;
54import java.util.concurrent.Executors;
55import java.util.stream.Collectors;
56
57import static com.google.common.base.Preconditions.checkNotNull;
58import static org.onlab.util.Tools.groupedThreads;
59
sangho0c2a3da2016-02-16 13:39:07 +090060@Component(immediate = true)
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090061@Service
sangho0c2a3da2016-02-16 13:39:07 +090062/**
63 * Populates flow rules about L3 functionality for VMs in Openstack.
64 */
65public class OpenstackRoutingManager implements OpenstackRoutingService {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090066
67 private final Logger log = LoggerFactory.getLogger(getClass());
sangho0c2a3da2016-02-16 13:39:07 +090068
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected CoreService coreService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected PacketService packetService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DeviceService deviceService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected OpenstackNetworkingService openstackService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected FlowObjectiveService flowObjectiveService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected DriverService driverService;
86
87 private ApplicationId appId;
88 private Map<String, OpenstackRouterInterface> routerInterfaceMap = Maps.newHashMap();
89 private Map<Integer, String> portNumMap = initPortNumMap();
90 private static final String APP_ID = "org.onosproject.openstackrouting";
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090091 private static final String PORT_NAME = "portName";
92 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
93
94 // TODO: This will be replaced to get the information from openstackswitchingservice.
95 private static final String EXTERNAL_INTERFACE_NAME = "veth0";
96
sangho0c2a3da2016-02-16 13:39:07 +090097 private Map<Integer, String> initPortNumMap() {
98 Map<Integer, String> map = Maps.newHashMap();
99 for (int i = 1024; i < 65535; i++) {
100 map.put(i, "");
101 }
102 return map;
103 }
104
105 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
106 private ExecutorService l3EventExecutorService =
107 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
108 private ExecutorService icmpEventExecutorService =
109 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
110
111 @Activate
112 protected void activate() {
113 appId = coreService.registerApplication(APP_ID);
114 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900115 reloadInitL3Rules();
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;
213 default:
214 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900215 Port port = getExternalPort(pkt.receivedFrom().deviceId(), EXTERNAL_INTERFACE_NAME);
216 if (port == null) {
217 log.warn("There`s no external interface");
218 break;
219 }
sangho0c2a3da2016-02-16 13:39:07 +0900220 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
221 Ip4Address.valueOf(iPacket.getSourceAddress()));
222 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900223 portNum, openstackPort, port));
sangho0c2a3da2016-02-16 13:39:07 +0900224 break;
225 }
226
227 }
228 }
229
230 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
231 int portNum = portNumMap.keySet().stream()
232 .filter(k -> portNumMap.get(k).equals("")).findFirst().orElse(0);
233 portNumMap.replace(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
234 return portNum;
235 }
236 }
237
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900238 private Port getExternalPort(DeviceId deviceId, String interfaceName) {
239 return deviceService.getPorts(deviceId)
240 .stream()
241 .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
242 .findAny()
243 .orElse(null);
244 }
245
sangho0c2a3da2016-02-16 13:39:07 +0900246 private void checkExternalConnection(OpenstackRouter router,
247 Collection<OpenstackRouterInterface> routerInterfaces) {
248 checkNotNull(router, "Router can not be null");
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900249 checkNotNull(routerInterfaces, "routerInterfaces can not be null");
sangho0c2a3da2016-02-16 13:39:07 +0900250 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
251 .values().stream().findFirst().orElse(null);
252 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900253 log.debug("Not satisfied to set pnat configuration");
sangho0c2a3da2016-02-16 13:39:07 +0900254 return;
255 }
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900256 routerInterfaces.forEach(routerInterface -> initiateL3Rule(router, routerInterface));
sangho0c2a3da2016-02-16 13:39:07 +0900257 }
258
259 private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
260 long vni = Long.parseLong(openstackService.network(openstackService
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900261 .port(routerInterface.id()).networkId()).segmentId());
sangho0c2a3da2016-02-16 13:39:07 +0900262 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
263 openstackService, flowObjectiveService, deviceService, driverService);
264 rulePopulator.populateExternalRules(vni, router, routerInterface);
265 }
266
267 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
268 return routerInterfaceMap.values().stream().filter(i -> i.id().equals(router.id()))
269 .collect(Collectors.toList());
270 }
271
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900272 private OpenstackRouter getOpenstackRouter(String id) {
sangho0c2a3da2016-02-16 13:39:07 +0900273 return openstackService.routers().stream().filter(r ->
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900274 r.id().equals(id)).findAny().orElse(null);
sangho0c2a3da2016-02-16 13:39:07 +0900275 }
276
277 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900278 OpenstackPort openstackPort = openstackService.ports().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900279 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900280 return checkNotNull(openstackPort.fixedIps().values().stream().findFirst().orElse(null))
sangho0c2a3da2016-02-16 13:39:07 +0900281 .equals(ip4Address) ? openstackPort : null;
282 }
283
284}