blob: aab37804ea40c626ac08f62c9bfb39686480cf45 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Jian Li26949762018-03-30 15:46:37 +09002 * Copyright 2016-present Open Networking Foundation
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 */
Hyunsun Moon44aac662017-02-18 02:07:01 +090016
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;
daniel park796c2eb2018-03-22 17:01:51 +090031import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.net.device.DeviceService;
sangho1aaa7882017-05-31 13:22:47 +090033import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
sangho1aaa7882017-05-31 13:22:47 +090038import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.openstacknetworking.api.InstancePort;
40import org.onosproject.openstacknetworking.api.InstancePortEvent;
41import org.onosproject.openstacknetworking.api.InstancePortListener;
42import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090043import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghoe6457a32017-08-24 14:31:19 +090045import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090046import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import org.onosproject.openstacknode.api.OpenstackNode;
48import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.openstack4j.model.network.Network;
Frank Wangf9571662017-06-06 18:01:29 +080050import org.openstack4j.model.network.NetworkType;
51import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.slf4j.Logger;
53
54import java.util.concurrent.ExecutorService;
55
56import static java.util.concurrent.Executors.newSingleThreadExecutor;
57import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090058import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090059import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
60import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
sanghodc375372017-06-08 10:41:30 +090061import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
62import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080063import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Daniel Parkd1b14d32018-06-12 16:10:28 +090064import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_DOWNSTREAM_RULE;
65import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE;
66import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
67import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_UPSTREAM_RULE;
sanghodc375372017-06-08 10:41:30 +090068import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
69import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li70a2c3f2018-04-13 17:26:31 +090070import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Li26949762018-03-30 15:46:37 +090071import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090072import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import static org.slf4j.LoggerFactory.getLogger;
74
75
76/**
77 * Populates switching flow rules on OVS for the basic connectivity among the
78 * virtual instances in the same network.
79 */
80@Component(immediate = true)
81public final class OpenstackSwitchingHandler {
82
83 private final Logger log = getLogger(getClass());
84
Jian Li71670d12018-03-02 21:31:07 +090085 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 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090088 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090091 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090094 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090097 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900100 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900103 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900106 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107
sangho1aaa7882017-05-31 13:22:47 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900109 protected DriverService driverService;
sangho1aaa7882017-05-31 13:22:47 +0900110
sanghoe6457a32017-08-24 14:31:19 +0900111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900112 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900113
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 private final ExecutorService eventExecutor = newSingleThreadExecutor(
115 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
116 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
117 private ApplicationId appId;
118
119 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800120 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
122 instancePortService.addListener(instancePortListener);
123
124 log.info("Started");
125 }
126
127 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800128 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 instancePortService.removeListener(instancePortListener);
130 eventExecutor.shutdown();
131
132 log.info("Stopped");
133 }
134
Jian Liea1b9662018-03-02 18:07:32 +0900135 /**
136 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900137 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900138 *
139 * @param instPort instance port object
140 * @param install install flag, add the rule if true, remove it otherwise
141 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900143 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
144 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900145 case VXLAN:
146 setTunnelTagFlowRules(instPort, install);
147 setForwardingRules(instPort, install);
148 break;
149 case VLAN:
150 setVlanTagFlowRules(instPort, install);
151 setForwardingRulesForVlan(instPort, install);
152 break;
daniel park796c2eb2018-03-22 17:01:51 +0900153 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900154 setFlatJumpRules(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900155 setDownstreamRules(instPort, install);
156 setUpstreamRules(instPort, install);
157 break;
daniel parka792cf72017-04-14 16:25:35 +0900158 default:
Jian Liea1b9662018-03-02 18:07:32 +0900159 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900160 break;
161 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 }
163
Jian Li24ec59f2018-05-23 19:01:25 +0900164 /**
165 * Removes virtual port.
166 *
167 * @param instPort instance port
168 */
169 private void removeVportRules(InstancePort instPort) {
170 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
171
172 switch (type) {
173 case VXLAN:
174 setTunnelTagFlowRules(instPort, false);
175 break;
176 case VLAN:
177 setVlanTagFlowRules(instPort, false);
178 break;
179 default:
180 log.warn("Unsupported network tunnel type {}", type.name());
181 break;
182 }
183 }
184
Jian Li70a2c3f2018-04-13 17:26:31 +0900185 private void setFlatJumpRules(InstancePort port, boolean install) {
186 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
187 selector.matchInPort(port.portNumber());
188
189 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
190 treatment.transition(FLAT_TABLE);
191
192 osFlowRuleService.setRule(
193 appId,
194 port.deviceId(),
195 selector.build(),
196 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900197 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900198 DHCP_ARP_TABLE,
199 install);
200
201 Network network = osNetworkService.network(port.networkId());
202
203 if (network == null) {
204 log.warn("The network does not exist");
205 return;
206 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900207 PortNumber portNumber = osNodeService.node(port.deviceId())
208 .phyIntfPortNum(network.getProviderPhyNet());
209
210 if (portNumber == null) {
211 log.warn("The port number does not exist");
212 return;
213 }
214
215 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900216 selector.matchInPort(portNumber)
217 .matchEthType(Ethernet.TYPE_IPV4)
218 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900219
220 osFlowRuleService.setRule(
221 appId,
222 port.deviceId(),
223 selector.build(),
224 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900225 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
226 DHCP_ARP_TABLE,
227 install);
228
229 selector = DefaultTrafficSelector.builder();
230 selector.matchInPort(portNumber)
231 .matchEthType(Ethernet.TYPE_ARP)
232 .matchArpTpa(port.ipAddress().getIp4Address());
233
234 osFlowRuleService.setRule(
235 appId,
236 port.deviceId(),
237 selector.build(),
238 treatment.build(),
239 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900240 DHCP_ARP_TABLE,
241 install);
242 }
243
daniel park796c2eb2018-03-22 17:01:51 +0900244 private void setDownstreamRules(InstancePort instPort, boolean install) {
245 TrafficSelector selector = DefaultTrafficSelector.builder()
246 .matchEthType(Ethernet.TYPE_IPV4)
247 .matchIPDst(instPort.ipAddress().toIpPrefix())
248 .build();
249 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
250 .setOutput(instPort.portNumber())
251 .build();
252
253 osFlowRuleService.setRule(
254 appId,
255 instPort.deviceId(),
256 selector,
257 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900258 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900259 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900260 install);
261
262 selector = DefaultTrafficSelector.builder()
263 .matchEthType(Ethernet.TYPE_ARP)
264 .matchArpTpa(instPort.ipAddress().getIp4Address())
265 .build();
266
267 osFlowRuleService.setRule(
268 appId,
269 instPort.deviceId(),
270 selector,
271 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900272 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900273 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900274 install);
275 }
276
277 private void setUpstreamRules(InstancePort instPort, boolean install) {
278 TrafficSelector selector = DefaultTrafficSelector.builder()
279 .matchInPort(instPort.portNumber())
280 .build();
281
282 Network network = osNetworkService.network(instPort.networkId());
283
284 if (network == null) {
285 log.warn("The network does not exist");
286 return;
287 }
288
289 PortNumber portNumber = osNodeService.node(instPort.deviceId())
290 .phyIntfPortNum(network.getProviderPhyNet());
291
292 if (portNumber == null) {
293 log.warn("The port number does not exist");
294 return;
295 }
296
297 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
298 .setOutput(portNumber)
299 .build();
300
301 osFlowRuleService.setRule(
302 appId,
303 instPort.deviceId(),
304 selector,
305 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900306 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900307 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900308 install);
309 }
310
311
Jian Liea1b9662018-03-02 18:07:32 +0900312 /**
313 * Configures the flow rules which are used for L2 packet switching.
314 * Note that these rules will be inserted in switching table (table 5).
315 *
316 * @param instPort instance port object
317 * @param install install flag, add the rule if true, remove it otherwise
318 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900319 private void setForwardingRules(InstancePort instPort, boolean install) {
320 // switching rules for the instPorts in the same node
321 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900322 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900323 .matchEthType(Ethernet.TYPE_IPV4)
324 .matchIPDst(instPort.ipAddress().toIpPrefix())
325 .matchTunnelId(getVni(instPort))
326 .build();
327
328 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900329 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900330 .setEthDst(instPort.macAddress())
331 .setOutput(instPort.portNumber())
332 .build();
333
sanghodc375372017-06-08 10:41:30 +0900334 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 appId,
336 instPort.deviceId(),
337 selector,
338 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900339 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900340 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 install);
342
343 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900344 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
345 if (localNode == null) {
346 final String error = String.format("Cannot find openstack node for %s",
347 instPort.deviceId());
348 throw new IllegalStateException(error);
349 }
350 osNodeService.completeNodes(COMPUTE).stream()
351 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
352 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900353 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
354 .extension(buildExtension(
355 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900356 remoteNode.intgBridge(),
357 localNode.dataIp().getIp4Address()),
358 remoteNode.intgBridge())
359 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900360 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900361
sanghodc375372017-06-08 10:41:30 +0900362 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900363 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900364 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900365 selector,
366 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900367 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900368 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900369 install);
370 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 }
372
Jian Liea1b9662018-03-02 18:07:32 +0900373 /**
374 * Configures the flow rules which are used for L2 VLAN packet switching.
375 * Note that these rules will be inserted in switching table (table 5).
376 *
377 * @param instPort instance port object
378 * @param install install flag, add the rule if true, remove it otherwise
379 */
daniel parka792cf72017-04-14 16:25:35 +0900380 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
381 // switching rules for the instPorts in the same node
382 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900383 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900384 .matchEthType(Ethernet.TYPE_IPV4)
385 .matchIPDst(instPort.ipAddress().toIpPrefix())
386 .matchVlanId(getVlanId(instPort))
387 .build();
388
389 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
390 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900391 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900392 .setEthDst(instPort.macAddress())
393 .setOutput(instPort.portNumber())
394 .build();
395
sanghodc375372017-06-08 10:41:30 +0900396 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900397 appId,
398 instPort.deviceId(),
399 selector,
400 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900401 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900402 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900403 install);
404
405 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900406 osNodeService.completeNodes(COMPUTE).stream()
407 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
408 remoteNode.vlanIntf() != null)
409 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900410 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900411 .setEthDst(instPort.macAddress())
412 .setOutput(remoteNode.vlanPortNum())
413 .build();
daniel parka792cf72017-04-14 16:25:35 +0900414
sanghodc375372017-06-08 10:41:30 +0900415 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900416 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900417 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900418 selector,
419 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900420 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900421 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900422 install);
423 });
daniel parka792cf72017-04-14 16:25:35 +0900424 }
425
Jian Liea1b9662018-03-02 18:07:32 +0900426 /**
427 * Configures the flow rule which is for using VXLAN to tag the packet
428 * based on the in_port number of a virtual instance.
429 * Note that this rule will be inserted in VNI table (table 0).
430 *
431 * @param instPort instance port object
432 * @param install install flag, add the rule if true, remove it otherwise
433 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
435 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900436 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900437 .matchEthType(Ethernet.TYPE_IPV4)
438 .matchInPort(instPort.portNumber())
439 .build();
440
Jian Liea1b9662018-03-02 18:07:32 +0900441 // XXX All egress traffic needs to go through connection tracking module,
442 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900443 ExtensionTreatment ctTreatment =
444 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
445 .commit(true).build();
446
sanghoe6457a32017-08-24 14:31:19 +0900447 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900448 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900449 .transition(ACL_TABLE);
450
451 if (securityGroupService.isSecurityGroupEnabled()) {
452 tb.extension(ctTreatment, instPort.deviceId());
453 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900454
sanghodc375372017-06-08 10:41:30 +0900455 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900456 appId,
457 instPort.deviceId(),
458 selector,
sanghoe6457a32017-08-24 14:31:19 +0900459 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900460 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900461 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900462 install);
463 }
464
Jian Liea1b9662018-03-02 18:07:32 +0900465 /**
466 * Configures the flow rule which is for using VLAN to tag the packet
467 * based on the in_port number of a virtual instance.
468 * Note that this rule will be inserted in VNI table (table 0).
469 *
470 * @param instPort instance port object
471 * @param install install flag, add the rule if true, remove it otherwise
472 */
daniel parka792cf72017-04-14 16:25:35 +0900473 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
474 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900475 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900476 .matchEthType(Ethernet.TYPE_IPV4)
477 .matchInPort(instPort.portNumber())
478 .build();
479
480 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
481 .pushVlan()
482 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900483 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900484 .build();
485
sanghodc375372017-06-08 10:41:30 +0900486 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900487 appId,
488 instPort.deviceId(),
489 selector,
490 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900491 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900492 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900493 install);
daniel parka792cf72017-04-14 16:25:35 +0900494 }
495
Frank Wangf9571662017-06-06 18:01:29 +0800496 private void setNetworkAdminRules(Network network, boolean install) {
497 TrafficSelector selector;
498 if (network.getNetworkType() == NetworkType.VXLAN) {
499
500 selector = DefaultTrafficSelector.builder()
501 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
502 .build();
503 } else {
504 selector = DefaultTrafficSelector.builder()
505 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
506 .build();
507 }
508
509 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
510 .drop()
511 .build();
512
513 osNodeService.completeNodes().stream()
514 .filter(osNode -> osNode.type() == COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900515 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800516 osFlowRuleService.setRule(
517 appId,
518 osNode.intgBridge(),
519 selector,
520 treatment,
521 PRIORITY_ADMIN_RULE,
522 ACL_TABLE,
Jian Liea1b9662018-03-02 18:07:32 +0900523 install)
524 );
Frank Wangf9571662017-06-06 18:01:29 +0800525 }
526
Jian Li70a2c3f2018-04-13 17:26:31 +0900527 // TODO: need to be purged sooner or later
Frank Wangf9571662017-06-06 18:01:29 +0800528 private void setPortAdminRules(Port port, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900529 InstancePort instancePort =
530 instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
Frank Wangf9571662017-06-06 18:01:29 +0800531 TrafficSelector selector = DefaultTrafficSelector.builder()
532 .matchInPort(instancePort.portNumber())
533 .build();
534
535 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
536 .drop()
537 .build();
538
539 osFlowRuleService.setRule(
540 appId,
541 instancePort.deviceId(),
542 selector,
543 treatment,
544 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900545 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800546 install);
547 }
548
Jian Liea1b9662018-03-02 18:07:32 +0900549 /**
550 * Obtains the VLAN ID from the given instance port.
551 *
552 * @param instPort instance port object
553 * @return VLAN ID
554 */
daniel parka792cf72017-04-14 16:25:35 +0900555 private VlanId getVlanId(InstancePort instPort) {
556 Network osNet = osNetworkService.network(instPort.networkId());
557
558 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900559 final String error =
560 String.format(ERR_SET_FLOWS_VNI,
561 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900562 throw new IllegalStateException(error);
563 }
564
565 return VlanId.vlanId(osNet.getProviderSegID());
566 }
567
Jian Liea1b9662018-03-02 18:07:32 +0900568 /**
569 * Obtains the VNI from the given instance port.
570 *
571 * @param instPort instance port object
572 * @return VXLAN Network Identifier (VNI)
573 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900574 private Long getVni(InstancePort instPort) {
575 Network osNet = osNetworkService.network(instPort.networkId());
576 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900577 final String error =
578 String.format(ERR_SET_FLOWS_VNI,
579 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900580 throw new IllegalStateException(error);
581 }
582 return Long.valueOf(osNet.getProviderSegID());
583 }
584
Jian Liea1b9662018-03-02 18:07:32 +0900585 /**
586 * An internal instance port listener which listens the port events generated
587 * from VM. The corresponding L2 forwarding rules will be generated and
588 * inserted to integration bridge only if a new VM port is detected. If the
589 * existing detected VM port is removed due to VM purge, we will remove the
590 * corresponding L2 forwarding to as well for the sake of resource saving.
591 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900592 private class InternalInstancePortListener implements InstancePortListener {
593
594 @Override
595 public boolean isRelevant(InstancePortEvent event) {
596 InstancePort instPort = event.subject();
597 return mastershipService.isLocalMaster(instPort.deviceId());
598 }
599
600 @Override
601 public void event(InstancePortEvent event) {
602 InstancePort instPort = event.subject();
603 switch (event.type()) {
604 case OPENSTACK_INSTANCE_PORT_UPDATED:
605 case OPENSTACK_INSTANCE_PORT_DETECTED:
606 eventExecutor.execute(() -> {
607 log.info("Instance port detected MAC:{} IP:{}",
608 instPort.macAddress(),
609 instPort.ipAddress());
610 instPortDetected(event.subject());
611 });
612 break;
613 case OPENSTACK_INSTANCE_PORT_VANISHED:
614 eventExecutor.execute(() -> {
615 log.info("Instance port vanished MAC:{} IP:{}",
616 instPort.macAddress(),
617 instPort.ipAddress());
618 instPortRemoved(event.subject());
619 });
620 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900621 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
622 eventExecutor.execute(() -> {
623 log.info("Instance port vanished MAC:{} IP:{}, due to VM migration",
624 instPort.macAddress(),
625 instPort.ipAddress());
626 removeVportRules(event.subject());
627 });
628 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900629 default:
630 break;
631 }
632 }
633
634 private void instPortDetected(InstancePort instPort) {
635 setNetworkRules(instPort, true);
636 // TODO add something else if needed
637 }
638
639 private void instPortRemoved(InstancePort instPort) {
640 setNetworkRules(instPort, false);
641 // TODO add something else if needed
642 }
643 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900644}