blob: 61b4359ad6199f8a1df34a46b88d63bf967ef943 [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);
Jian Li9a921b42018-06-18 02:44:50 +0900147 setForwardingRulesForVxlan(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900148 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);
Jian Li9a921b42018-06-18 02:44:50 +0900155 setDownstreamRulesForFlat(instPort, install);
156 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900157 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;
Jian Li9a921b42018-06-18 02:44:50 +0900179 case FLAT:
180 setFlatJumpRules(instPort, false);
181 setUpstreamRulesForFlat(instPort, false);
182 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700183 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900184 default:
Jian Li9a921b42018-06-18 02:44:50 +0900185 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900186 break;
187 }
188 }
189
Jian Li70a2c3f2018-04-13 17:26:31 +0900190 private void setFlatJumpRules(InstancePort port, boolean install) {
191 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
192 selector.matchInPort(port.portNumber());
193
194 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
195 treatment.transition(FLAT_TABLE);
196
197 osFlowRuleService.setRule(
198 appId,
199 port.deviceId(),
200 selector.build(),
201 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900202 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900203 DHCP_ARP_TABLE,
204 install);
205
206 Network network = osNetworkService.network(port.networkId());
207
208 if (network == null) {
209 log.warn("The network does not exist");
210 return;
211 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900212 PortNumber portNumber = osNodeService.node(port.deviceId())
213 .phyIntfPortNum(network.getProviderPhyNet());
214
215 if (portNumber == null) {
216 log.warn("The port number does not exist");
217 return;
218 }
219
220 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900221 selector.matchInPort(portNumber)
222 .matchEthType(Ethernet.TYPE_IPV4)
223 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900224
225 osFlowRuleService.setRule(
226 appId,
227 port.deviceId(),
228 selector.build(),
229 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900230 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
231 DHCP_ARP_TABLE,
232 install);
233
234 selector = DefaultTrafficSelector.builder();
235 selector.matchInPort(portNumber)
236 .matchEthType(Ethernet.TYPE_ARP)
237 .matchArpTpa(port.ipAddress().getIp4Address());
238
239 osFlowRuleService.setRule(
240 appId,
241 port.deviceId(),
242 selector.build(),
243 treatment.build(),
244 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900245 DHCP_ARP_TABLE,
246 install);
247 }
248
Jian Li9a921b42018-06-18 02:44:50 +0900249 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900250 TrafficSelector selector = DefaultTrafficSelector.builder()
251 .matchEthType(Ethernet.TYPE_IPV4)
252 .matchIPDst(instPort.ipAddress().toIpPrefix())
253 .build();
254 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
255 .setOutput(instPort.portNumber())
256 .build();
257
258 osFlowRuleService.setRule(
259 appId,
260 instPort.deviceId(),
261 selector,
262 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900263 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900264 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900265 install);
266
267 selector = DefaultTrafficSelector.builder()
268 .matchEthType(Ethernet.TYPE_ARP)
269 .matchArpTpa(instPort.ipAddress().getIp4Address())
270 .build();
271
272 osFlowRuleService.setRule(
273 appId,
274 instPort.deviceId(),
275 selector,
276 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900277 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900278 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900279 install);
280 }
281
Jian Li9a921b42018-06-18 02:44:50 +0900282 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900283 TrafficSelector selector = DefaultTrafficSelector.builder()
284 .matchInPort(instPort.portNumber())
285 .build();
286
287 Network network = osNetworkService.network(instPort.networkId());
288
289 if (network == null) {
290 log.warn("The network does not exist");
291 return;
292 }
293
294 PortNumber portNumber = osNodeService.node(instPort.deviceId())
295 .phyIntfPortNum(network.getProviderPhyNet());
296
297 if (portNumber == null) {
298 log.warn("The port number does not exist");
299 return;
300 }
301
302 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
303 .setOutput(portNumber)
304 .build();
305
306 osFlowRuleService.setRule(
307 appId,
308 instPort.deviceId(),
309 selector,
310 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900311 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900312 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900313 install);
314 }
315
316
Jian Liea1b9662018-03-02 18:07:32 +0900317 /**
318 * Configures the flow rules which are used for L2 packet switching.
319 * Note that these rules will be inserted in switching table (table 5).
320 *
321 * @param instPort instance port object
322 * @param install install flag, add the rule if true, remove it otherwise
323 */
Jian Li9a921b42018-06-18 02:44:50 +0900324 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900325 // switching rules for the instPorts in the same node
326 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900327 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900328 .matchEthType(Ethernet.TYPE_IPV4)
329 .matchIPDst(instPort.ipAddress().toIpPrefix())
330 .matchTunnelId(getVni(instPort))
331 .build();
332
333 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900334 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 .setEthDst(instPort.macAddress())
336 .setOutput(instPort.portNumber())
337 .build();
338
sanghodc375372017-06-08 10:41:30 +0900339 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900340 appId,
341 instPort.deviceId(),
342 selector,
343 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900344 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900345 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 install);
347
348 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900349 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
350 if (localNode == null) {
351 final String error = String.format("Cannot find openstack node for %s",
352 instPort.deviceId());
353 throw new IllegalStateException(error);
354 }
355 osNodeService.completeNodes(COMPUTE).stream()
356 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
357 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900358 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
359 .extension(buildExtension(
360 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900361 remoteNode.intgBridge(),
362 localNode.dataIp().getIp4Address()),
363 remoteNode.intgBridge())
364 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900365 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366
sanghodc375372017-06-08 10:41:30 +0900367 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900368 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900369 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900370 selector,
371 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900372 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900373 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900374 install);
375 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900376 }
377
Jian Liea1b9662018-03-02 18:07:32 +0900378 /**
379 * Configures the flow rules which are used for L2 VLAN packet switching.
380 * Note that these rules will be inserted in switching table (table 5).
381 *
382 * @param instPort instance port object
383 * @param install install flag, add the rule if true, remove it otherwise
384 */
daniel parka792cf72017-04-14 16:25:35 +0900385 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
386 // switching rules for the instPorts in the same node
387 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900388 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900389 .matchEthType(Ethernet.TYPE_IPV4)
390 .matchIPDst(instPort.ipAddress().toIpPrefix())
391 .matchVlanId(getVlanId(instPort))
392 .build();
393
394 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
395 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900396 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900397 .setEthDst(instPort.macAddress())
398 .setOutput(instPort.portNumber())
399 .build();
400
sanghodc375372017-06-08 10:41:30 +0900401 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900402 appId,
403 instPort.deviceId(),
404 selector,
405 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900406 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900407 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900408 install);
409
410 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900411 osNodeService.completeNodes(COMPUTE).stream()
412 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
413 remoteNode.vlanIntf() != null)
414 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900415 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900416 .setEthDst(instPort.macAddress())
417 .setOutput(remoteNode.vlanPortNum())
418 .build();
daniel parka792cf72017-04-14 16:25:35 +0900419
sanghodc375372017-06-08 10:41:30 +0900420 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900421 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900422 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900423 selector,
424 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900425 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900426 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900427 install);
428 });
daniel parka792cf72017-04-14 16:25:35 +0900429 }
430
Jian Liea1b9662018-03-02 18:07:32 +0900431 /**
432 * Configures the flow rule which is for using VXLAN to tag the packet
433 * based on the in_port number of a virtual instance.
434 * Note that this rule will be inserted in VNI table (table 0).
435 *
436 * @param instPort instance port object
437 * @param install install flag, add the rule if true, remove it otherwise
438 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900439 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
440 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900441 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900442 .matchEthType(Ethernet.TYPE_IPV4)
443 .matchInPort(instPort.portNumber())
444 .build();
445
Jian Liea1b9662018-03-02 18:07:32 +0900446 // XXX All egress traffic needs to go through connection tracking module,
447 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900448 ExtensionTreatment ctTreatment =
449 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
450 .commit(true).build();
451
sanghoe6457a32017-08-24 14:31:19 +0900452 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900453 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900454 .transition(ACL_TABLE);
455
456 if (securityGroupService.isSecurityGroupEnabled()) {
457 tb.extension(ctTreatment, instPort.deviceId());
458 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900459
sanghodc375372017-06-08 10:41:30 +0900460 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900461 appId,
462 instPort.deviceId(),
463 selector,
sanghoe6457a32017-08-24 14:31:19 +0900464 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900465 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900466 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900467 install);
468 }
469
Jian Liea1b9662018-03-02 18:07:32 +0900470 /**
471 * Configures the flow rule which is for using VLAN to tag the packet
472 * based on the in_port number of a virtual instance.
473 * Note that this rule will be inserted in VNI table (table 0).
474 *
475 * @param instPort instance port object
476 * @param install install flag, add the rule if true, remove it otherwise
477 */
daniel parka792cf72017-04-14 16:25:35 +0900478 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
479 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900480 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900481 .matchEthType(Ethernet.TYPE_IPV4)
482 .matchInPort(instPort.portNumber())
483 .build();
484
485 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
486 .pushVlan()
487 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900488 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900489 .build();
490
sanghodc375372017-06-08 10:41:30 +0900491 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900492 appId,
493 instPort.deviceId(),
494 selector,
495 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900496 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900497 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900498 install);
daniel parka792cf72017-04-14 16:25:35 +0900499 }
500
Frank Wangf9571662017-06-06 18:01:29 +0800501 private void setNetworkAdminRules(Network network, boolean install) {
502 TrafficSelector selector;
503 if (network.getNetworkType() == NetworkType.VXLAN) {
504
505 selector = DefaultTrafficSelector.builder()
506 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
507 .build();
508 } else {
509 selector = DefaultTrafficSelector.builder()
510 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
511 .build();
512 }
513
514 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
515 .drop()
516 .build();
517
518 osNodeService.completeNodes().stream()
519 .filter(osNode -> osNode.type() == COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900520 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800521 osFlowRuleService.setRule(
522 appId,
523 osNode.intgBridge(),
524 selector,
525 treatment,
526 PRIORITY_ADMIN_RULE,
527 ACL_TABLE,
Jian Liea1b9662018-03-02 18:07:32 +0900528 install)
529 );
Frank Wangf9571662017-06-06 18:01:29 +0800530 }
531
Jian Li70a2c3f2018-04-13 17:26:31 +0900532 // TODO: need to be purged sooner or later
Frank Wangf9571662017-06-06 18:01:29 +0800533 private void setPortAdminRules(Port port, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900534 InstancePort instancePort =
535 instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
Frank Wangf9571662017-06-06 18:01:29 +0800536 TrafficSelector selector = DefaultTrafficSelector.builder()
537 .matchInPort(instancePort.portNumber())
538 .build();
539
540 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
541 .drop()
542 .build();
543
544 osFlowRuleService.setRule(
545 appId,
546 instancePort.deviceId(),
547 selector,
548 treatment,
549 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900550 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800551 install);
552 }
553
Jian Liea1b9662018-03-02 18:07:32 +0900554 /**
555 * Obtains the VLAN ID from the given instance port.
556 *
557 * @param instPort instance port object
558 * @return VLAN ID
559 */
daniel parka792cf72017-04-14 16:25:35 +0900560 private VlanId getVlanId(InstancePort instPort) {
561 Network osNet = osNetworkService.network(instPort.networkId());
562
563 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900564 final String error =
565 String.format(ERR_SET_FLOWS_VNI,
566 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900567 throw new IllegalStateException(error);
568 }
569
570 return VlanId.vlanId(osNet.getProviderSegID());
571 }
572
Jian Liea1b9662018-03-02 18:07:32 +0900573 /**
574 * Obtains the VNI from the given instance port.
575 *
576 * @param instPort instance port object
577 * @return VXLAN Network Identifier (VNI)
578 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900579 private Long getVni(InstancePort instPort) {
580 Network osNet = osNetworkService.network(instPort.networkId());
581 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900582 final String error =
583 String.format(ERR_SET_FLOWS_VNI,
584 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900585 throw new IllegalStateException(error);
586 }
587 return Long.valueOf(osNet.getProviderSegID());
588 }
589
Jian Liea1b9662018-03-02 18:07:32 +0900590 /**
591 * An internal instance port listener which listens the port events generated
592 * from VM. The corresponding L2 forwarding rules will be generated and
593 * inserted to integration bridge only if a new VM port is detected. If the
594 * existing detected VM port is removed due to VM purge, we will remove the
595 * corresponding L2 forwarding to as well for the sake of resource saving.
596 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900597 private class InternalInstancePortListener implements InstancePortListener {
598
599 @Override
600 public boolean isRelevant(InstancePortEvent event) {
601 InstancePort instPort = event.subject();
602 return mastershipService.isLocalMaster(instPort.deviceId());
603 }
604
605 @Override
606 public void event(InstancePortEvent event) {
607 InstancePort instPort = event.subject();
Jian Li9a921b42018-06-18 02:44:50 +0900608
Hyunsun Moon44aac662017-02-18 02:07:01 +0900609 switch (event.type()) {
610 case OPENSTACK_INSTANCE_PORT_UPDATED:
611 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li9a921b42018-06-18 02:44:50 +0900612 log.info("Instance port detected MAC:{} IP:{}",
613 instPort.macAddress(),
614 instPort.ipAddress());
615 eventExecutor.execute(() ->
616 instPortDetected(instPort)
617 );
618
Hyunsun Moon44aac662017-02-18 02:07:01 +0900619 break;
620 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li9a921b42018-06-18 02:44:50 +0900621 log.info("Instance port vanished MAC:{} IP:{}",
622 instPort.macAddress(),
623 instPort.ipAddress());
624 eventExecutor.execute(() ->
625 instPortRemoved(instPort)
626 );
627
Hyunsun Moon44aac662017-02-18 02:07:01 +0900628 break;
Jian Li9a921b42018-06-18 02:44:50 +0900629
630 // we do not consider MIGRATION_STARTED case, because the rules
631 // will be installed to corresponding switches at
632 // OPENSTACK_INSTANCE_PORT_UPDATED phase
633
634 // TODO: we may need to consider to refactor the VM migration
635 // event detection logic for better code readability
Jian Li24ec59f2018-05-23 19:01:25 +0900636 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li9a921b42018-06-18 02:44:50 +0900637 log.info("Instance port vanished MAC:{} IP:{}, " +
638 "due to VM migration", instPort.macAddress(),
639 instPort.ipAddress());
640 eventExecutor.execute(() ->
641 removeVportRules(instPort)
642 );
Jian Li24ec59f2018-05-23 19:01:25 +0900643 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900644 default:
645 break;
646 }
647 }
648
649 private void instPortDetected(InstancePort instPort) {
650 setNetworkRules(instPort, true);
651 // TODO add something else if needed
652 }
653
654 private void instPortRemoved(InstancePort instPort) {
655 setNetworkRules(instPort, false);
656 // TODO add something else if needed
657 }
658 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900659}