blob: 2ea59356ed109fd1532edb94b6c19d0ffee33e4f [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;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.driver.DriverService;
34import org.onosproject.net.flowobjective.FlowObjectiveService;
35import org.onosproject.net.packet.InboundPacket;
36import org.onosproject.net.packet.PacketContext;
37import org.onosproject.net.packet.PacketProcessor;
38import org.onosproject.net.packet.PacketService;
39import org.onosproject.openstacknetworking.OpenstackFloatingIP;
40import org.onosproject.openstacknetworking.OpenstackNetworkingService;
41import org.onosproject.openstacknetworking.OpenstackPort;
42import org.onosproject.openstacknetworking.OpenstackRouter;
43import org.onosproject.openstacknetworking.OpenstackRouterInterface;
44import org.onosproject.openstacknetworking.OpenstackRoutingService;
45import org.slf4j.Logger;
46import org.slf4j.LoggerFactory;
47
48import java.util.Collection;
49import java.util.List;
50import java.util.Map;
51import java.util.concurrent.ExecutorService;
52import java.util.concurrent.Executors;
53import java.util.stream.Collectors;
54
55import static com.google.common.base.Preconditions.checkNotNull;
56import static org.onlab.util.Tools.groupedThreads;
57
58@Service
59@Component(immediate = true)
60/**
61 * Populates flow rules about L3 functionality for VMs in Openstack.
62 */
63public class OpenstackRoutingManager implements OpenstackRoutingService {
64 private final Logger log = LoggerFactory
65 .getLogger(getClass());
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected CoreService coreService;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected PacketService packetService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected DeviceService deviceService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected OpenstackNetworkingService openstackService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected FlowObjectiveService flowObjectiveService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected DriverService driverService;
84
85 private ApplicationId appId;
86 private Map<String, OpenstackRouterInterface> routerInterfaceMap = Maps.newHashMap();
87 private Map<Integer, String> portNumMap = initPortNumMap();
88 private static final String APP_ID = "org.onosproject.openstackrouting";
89 private Map<Integer, String> initPortNumMap() {
90 Map<Integer, String> map = Maps.newHashMap();
91 for (int i = 1024; i < 65535; i++) {
92 map.put(i, "");
93 }
94 return map;
95 }
96
97 private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
98 private ExecutorService l3EventExecutorService =
99 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
100 private ExecutorService icmpEventExecutorService =
101 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
102
103 @Activate
104 protected void activate() {
105 appId = coreService.registerApplication(APP_ID);
106 packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
107
108 log.info("onos-openstackrouting started");
109 }
110
111 @Deactivate
112 protected void deactivate() {
113 packetService.removeProcessor(internalPacketProcessor);
114 log.info("onos-openstackrouting stopped");
115 }
116
117
118 @Override
119 public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
120
121 }
122
123 @Override
124 public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
125
126 }
127
128 @Override
129 public void deleteFloatingIP(String id) {
130
131 }
132
133 @Override
134 public void createRouter(OpenstackRouter openstackRouter) {
135 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
136 }
137
138 @Override
139 public void updateRouter(OpenstackRouter openstackRouter) {
140 checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
141 }
142
143 @Override
144 public void deleteRouter(String id) {
145 //TODO
146 }
147
148 @Override
149 public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
150 routerInterfaceMap.putIfAbsent(routerInterface.portId(), routerInterface);
151 List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
152 routerInterfaces.add(routerInterface);
153 checkExternalConnection(getOpenstackRouter(routerInterface.tenantId()), routerInterfaces);
154 }
155
156 @Override
157 public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
158 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
159 openstackService, flowObjectiveService, deviceService, driverService);
160 rulePopulator.removeExternalRules(routerInterface);
161 routerInterfaceMap.remove(routerInterface.portId());
162 }
163 private class InternalPacketProcessor implements PacketProcessor {
164
165 @Override
166 public void process(PacketContext context) {
167
168 if (context.isHandled()) {
169 return;
170 }
171
172 InboundPacket pkt = context.inPacket();
173 Ethernet ethernet = pkt.parsed();
174
175 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
176 IPv4 iPacket = (IPv4) ethernet.getPayload();
177 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
178 openstackService, flowObjectiveService, deviceService,
179 driverService);
180 switch (iPacket.getProtocol()) {
181 case IPv4.PROTOCOL_ICMP:
182 icmpEventExecutorService.execute(new OpenstackIcmpHandler(rulePopulator, context));
183 break;
184 default:
185 int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
186 OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
187 Ip4Address.valueOf(iPacket.getSourceAddress()));
188 l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
189 portNum, openstackPort));
190 break;
191 }
192
193 }
194 }
195
196 private int getPortNum(MacAddress sourceMac, int destinationAddress) {
197 int portNum = portNumMap.keySet().stream()
198 .filter(k -> portNumMap.get(k).equals("")).findFirst().orElse(0);
199 portNumMap.replace(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
200 return portNum;
201 }
202 }
203
204 private void checkExternalConnection(OpenstackRouter router,
205 Collection<OpenstackRouterInterface> routerInterfaces) {
206 checkNotNull(router, "Router can not be null");
207 checkNotNull(routerInterfaces, "RouterInterfaces can not be null");
208 Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
209 .values().stream().findFirst().orElse(null);
210 if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
211 log.debug("Failed to set pnat configuration");
212 return;
213 }
214 routerInterfaces.forEach(routerInterface -> {
215 initiateL3Rule(router, routerInterface);
216 });
217 }
218
219 private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
220 long vni = Long.parseLong(openstackService.network(openstackService
221 .port(routerInterface.portId()).networkId()).segmentId());
222 OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
223 openstackService, flowObjectiveService, deviceService, driverService);
224 rulePopulator.populateExternalRules(vni, router, routerInterface);
225 }
226
227 private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
228 return routerInterfaceMap.values().stream().filter(i -> i.id().equals(router.id()))
229 .collect(Collectors.toList());
230 }
231
232 private OpenstackRouter getOpenstackRouter(String tenantId) {
233 return openstackService.routers().stream().filter(r ->
234 r.tenantId().equals(tenantId)).findFirst().orElse(null);
235 }
236
237 private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
238 OpenstackPort openstackPort = openstackService.ports("").stream()
239 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
240 return openstackPort.fixedIps().values().stream().findFirst().orElse(null)
241 .equals(ip4Address) ? openstackPort : null;
242 }
243
244}