blob: 3cba0e3bc6ce7abf4b47dfa92e5a0c402b558245 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002* Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +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*/
16
17package org.onosproject.openstacknetworking.impl;
18
19import com.google.common.base.Strings;
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.onlab.packet.Ethernet;
Frank Wangf9571662017-06-06 18:01:29 +080026import org.onlab.packet.MacAddress;
daniel parka792cf72017-04-14 16:25:35 +090027import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
30import org.onosproject.mastership.MastershipService;
31import org.onosproject.net.device.DeviceService;
sangho1aaa7882017-05-31 13:22:47 +090032import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090033import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
sangho1aaa7882017-05-31 13:22:47 +090037import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.openstacknetworking.api.InstancePort;
39import org.onosproject.openstacknetworking.api.InstancePortEvent;
40import org.onosproject.openstacknetworking.api.InstancePortListener;
41import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090042import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghoe6457a32017-08-24 14:31:19 +090044import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090045import org.onosproject.openstacknode.api.OpenstackNode;
46import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.openstack4j.model.network.Network;
Frank Wangf9571662017-06-06 18:01:29 +080048import org.openstack4j.model.network.NetworkType;
49import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.slf4j.Logger;
51
52import java.util.concurrent.ExecutorService;
53
54import static java.util.concurrent.Executors.newSingleThreadExecutor;
55import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090056import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
57import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
58import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080059import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
sanghodc375372017-06-08 10:41:30 +090060import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
61import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
62import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090064import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090065import static org.slf4j.LoggerFactory.getLogger;
66
67
68/**
69 * Populates switching flow rules on OVS for the basic connectivity among the
70 * virtual instances in the same network.
71 */
72@Component(immediate = true)
73public final class OpenstackSwitchingHandler {
74
75 private final Logger log = getLogger(getClass());
76
Jian Li71670d12018-03-02 21:31:07 +090077 private static final String ERR_SET_FLOWS_VNI = "Failed to set flows for %s: Failed to get VNI for %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +090078
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080080 CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080083 MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090084
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080086 DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090087
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080089 OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090090
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080092 InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090093
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080095 OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -080098 OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090099
sangho1aaa7882017-05-31 13:22:47 +0900100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800101 DriverService driverService;
sangho1aaa7882017-05-31 13:22:47 +0900102
sanghoe6457a32017-08-24 14:31:19 +0900103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800104 OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900105
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 private final ExecutorService eventExecutor = newSingleThreadExecutor(
107 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
108 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
109 private ApplicationId appId;
110
111 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800112 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
114 instancePortService.addListener(instancePortListener);
115
116 log.info("Started");
117 }
118
119 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800120 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 instancePortService.removeListener(instancePortListener);
122 eventExecutor.shutdown();
123
124 log.info("Stopped");
125 }
126
127 private void setNetworkRules(InstancePort instPort, boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900128 switch (osNetworkService.network(instPort.networkId()).getNetworkType()) {
129 case VXLAN:
130 setTunnelTagFlowRules(instPort, install);
131 setForwardingRules(instPort, install);
132 break;
133 case VLAN:
134 setVlanTagFlowRules(instPort, install);
135 setForwardingRulesForVlan(instPort, install);
136 break;
137 default:
138 break;
139 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140 }
141
142 private void setForwardingRules(InstancePort instPort, boolean install) {
143 // switching rules for the instPorts in the same node
144 TrafficSelector selector = DefaultTrafficSelector.builder()
145 .matchEthType(Ethernet.TYPE_IPV4)
146 .matchIPDst(instPort.ipAddress().toIpPrefix())
147 .matchTunnelId(getVni(instPort))
148 .build();
149
150 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
151 .setEthDst(instPort.macAddress())
152 .setOutput(instPort.portNumber())
153 .build();
154
sanghodc375372017-06-08 10:41:30 +0900155 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 appId,
157 instPort.deviceId(),
158 selector,
159 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900161 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 install);
163
164 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900165 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
166 if (localNode == null) {
167 final String error = String.format("Cannot find openstack node for %s",
168 instPort.deviceId());
169 throw new IllegalStateException(error);
170 }
171 osNodeService.completeNodes(COMPUTE).stream()
172 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
173 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900174 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
175 .extension(buildExtension(
176 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900177 remoteNode.intgBridge(),
178 localNode.dataIp().getIp4Address()),
179 remoteNode.intgBridge())
180 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900181 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182
sanghodc375372017-06-08 10:41:30 +0900183 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900184 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900185 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900186 selector,
187 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900188 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900189 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900190 install);
191 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900192 }
193
daniel parka792cf72017-04-14 16:25:35 +0900194 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
195 // switching rules for the instPorts in the same node
196 TrafficSelector selector = DefaultTrafficSelector.builder()
197 .matchEthType(Ethernet.TYPE_IPV4)
198 .matchIPDst(instPort.ipAddress().toIpPrefix())
199 .matchVlanId(getVlanId(instPort))
200 .build();
201
202 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
203 .popVlan()
204 .setEthDst(instPort.macAddress())
205 .setOutput(instPort.portNumber())
206 .build();
207
sanghodc375372017-06-08 10:41:30 +0900208 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900209 appId,
210 instPort.deviceId(),
211 selector,
212 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900213 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900214 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900215 install);
216
217 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900218 osNodeService.completeNodes(COMPUTE).stream()
219 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
220 remoteNode.vlanIntf() != null)
221 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900222 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900223 .setOutput(remoteNode.vlanPortNum())
daniel parka792cf72017-04-14 16:25:35 +0900224 .build();
225
sanghodc375372017-06-08 10:41:30 +0900226 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900227 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900228 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900229 selector,
230 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900231 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900232 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900233 install);
234 });
daniel parka792cf72017-04-14 16:25:35 +0900235 }
236
Hyunsun Moon44aac662017-02-18 02:07:01 +0900237 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
238 TrafficSelector selector = DefaultTrafficSelector.builder()
239 .matchEthType(Ethernet.TYPE_IPV4)
240 .matchInPort(instPort.portNumber())
241 .build();
242
sangho1aaa7882017-05-31 13:22:47 +0900243 // XXX All egress traffic needs to go through connection tracking module, which might hurt its performance.
244 ExtensionTreatment ctTreatment =
245 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
246 .commit(true).build();
247
sanghoe6457a32017-08-24 14:31:19 +0900248 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900249 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900250 .transition(ACL_TABLE);
251
252 if (securityGroupService.isSecurityGroupEnabled()) {
253 tb.extension(ctTreatment, instPort.deviceId());
254 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255
sanghodc375372017-06-08 10:41:30 +0900256 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900257 appId,
258 instPort.deviceId(),
259 selector,
sanghoe6457a32017-08-24 14:31:19 +0900260 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900261 PRIORITY_TUNNEL_TAG_RULE,
sanghodc375372017-06-08 10:41:30 +0900262 SRC_VNI_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900263 install);
264 }
265
daniel parka792cf72017-04-14 16:25:35 +0900266 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
267 TrafficSelector selector = DefaultTrafficSelector.builder()
268 .matchEthType(Ethernet.TYPE_IPV4)
269 .matchInPort(instPort.portNumber())
270 .build();
271
272 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
273 .pushVlan()
274 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900275 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900276 .build();
277
sanghodc375372017-06-08 10:41:30 +0900278 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900279 appId,
280 instPort.deviceId(),
281 selector,
282 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900283 PRIORITY_TUNNEL_TAG_RULE,
sanghodc375372017-06-08 10:41:30 +0900284 SRC_VNI_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900285 install);
286
287 }
288
Frank Wangf9571662017-06-06 18:01:29 +0800289 private void setNetworkAdminRules(Network network, boolean install) {
290 TrafficSelector selector;
291 if (network.getNetworkType() == NetworkType.VXLAN) {
292
293 selector = DefaultTrafficSelector.builder()
294 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
295 .build();
296 } else {
297 selector = DefaultTrafficSelector.builder()
298 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
299 .build();
300 }
301
302 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
303 .drop()
304 .build();
305
306 osNodeService.completeNodes().stream()
307 .filter(osNode -> osNode.type() == COMPUTE)
308 .forEach(osNode -> {
309 osFlowRuleService.setRule(
310 appId,
311 osNode.intgBridge(),
312 selector,
313 treatment,
314 PRIORITY_ADMIN_RULE,
315 ACL_TABLE,
316 install);
317 });
318 }
319
320 private void setPortAdminRules(Port port, boolean install) {
321 InstancePort instancePort = instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
322 TrafficSelector selector = DefaultTrafficSelector.builder()
323 .matchInPort(instancePort.portNumber())
324 .build();
325
326 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
327 .drop()
328 .build();
329
330 osFlowRuleService.setRule(
331 appId,
332 instancePort.deviceId(),
333 selector,
334 treatment,
335 PRIORITY_ADMIN_RULE,
336 SRC_VNI_TABLE,
337 install);
338 }
339
daniel parka792cf72017-04-14 16:25:35 +0900340 private VlanId getVlanId(InstancePort instPort) {
341 Network osNet = osNetworkService.network(instPort.networkId());
342
343 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900344 final String error =
345 String.format(ERR_SET_FLOWS_VNI,
346 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900347 throw new IllegalStateException(error);
348 }
349
350 return VlanId.vlanId(osNet.getProviderSegID());
351 }
352
353
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 private Long getVni(InstancePort instPort) {
355 Network osNet = osNetworkService.network(instPort.networkId());
356 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900357 final String error =
358 String.format(ERR_SET_FLOWS_VNI,
359 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 throw new IllegalStateException(error);
361 }
362 return Long.valueOf(osNet.getProviderSegID());
363 }
364
365 private class InternalInstancePortListener implements InstancePortListener {
366
367 @Override
368 public boolean isRelevant(InstancePortEvent event) {
369 InstancePort instPort = event.subject();
370 return mastershipService.isLocalMaster(instPort.deviceId());
371 }
372
373 @Override
374 public void event(InstancePortEvent event) {
375 InstancePort instPort = event.subject();
376 switch (event.type()) {
377 case OPENSTACK_INSTANCE_PORT_UPDATED:
378 case OPENSTACK_INSTANCE_PORT_DETECTED:
379 eventExecutor.execute(() -> {
380 log.info("Instance port detected MAC:{} IP:{}",
381 instPort.macAddress(),
382 instPort.ipAddress());
383 instPortDetected(event.subject());
384 });
385 break;
386 case OPENSTACK_INSTANCE_PORT_VANISHED:
387 eventExecutor.execute(() -> {
388 log.info("Instance port vanished MAC:{} IP:{}",
389 instPort.macAddress(),
390 instPort.ipAddress());
391 instPortRemoved(event.subject());
392 });
393 break;
394 default:
395 break;
396 }
397 }
398
399 private void instPortDetected(InstancePort instPort) {
400 setNetworkRules(instPort, true);
401 // TODO add something else if needed
402 }
403
404 private void instPortRemoved(InstancePort instPort) {
405 setNetworkRules(instPort, false);
406 // TODO add something else if needed
407 }
408 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900409}