blob: 1d74e9af3125d5aaa512369b628be93b1759bede [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;
daniel parka792cf72017-04-14 16:25:35 +090026import org.onlab.packet.VlanId;
Jian Li5c09e212018-10-24 18:23:58 +090027import org.onosproject.cfg.ComponentConfigService;
28import org.onosproject.cfg.ConfigProperty;
Jian Li91be8cd2018-07-22 00:44:46 +090029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.mastership.MastershipService;
daniel park796c2eb2018-03-22 17:01:51 +090035import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.device.DeviceService;
sangho1aaa7882017-05-31 13:22:47 +090037import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
sangho1aaa7882017-05-31 13:22:47 +090042import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.openstacknetworking.api.InstancePort;
44import org.onosproject.openstacknetworking.api.InstancePortEvent;
45import org.onosproject.openstacknetworking.api.InstancePortListener;
46import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090047import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Li91be8cd2018-07-22 00:44:46 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
49import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghoe6457a32017-08-24 14:31:19 +090051import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090052import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090053import org.onosproject.openstacknode.api.OpenstackNode;
54import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.Network;
Frank Wangf9571662017-06-06 18:01:29 +080056import org.openstack4j.model.network.NetworkType;
57import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.slf4j.Logger;
59
Jian Li91be8cd2018-07-22 00:44:46 +090060import java.util.Objects;
Jian Li5c09e212018-10-24 18:23:58 +090061import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062import java.util.concurrent.ExecutorService;
63
64import static java.util.concurrent.Executors.newSingleThreadExecutor;
65import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090066import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
Jian Li5c09e212018-10-24 18:23:58 +090067import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
68import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
69import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090070import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
sanghodc375372017-06-08 10:41:30 +090071import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
72import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080073import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Daniel Parkd1b14d32018-06-12 16:10:28 +090074import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_DOWNSTREAM_RULE;
75import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE;
76import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
77import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_UPSTREAM_RULE;
sanghodc375372017-06-08 10:41:30 +090078import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
79import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li960ae512018-07-03 22:50:56 +090080import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090081import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Li5c09e212018-10-24 18:23:58 +090082import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090083import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090084import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090085import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090086import static org.slf4j.LoggerFactory.getLogger;
87
88
89/**
90 * Populates switching flow rules on OVS for the basic connectivity among the
91 * virtual instances in the same network.
92 */
93@Component(immediate = true)
94public final class OpenstackSwitchingHandler {
95
96 private final Logger log = getLogger(getClass());
97
Jian Li5c09e212018-10-24 18:23:58 +090098 private static final String ARP_MODE = "arpMode";
Jian Li71670d12018-03-02 21:31:07 +090099 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 +0900100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900102 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900105 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900108 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li91be8cd2018-07-22 00:44:46 +0900111 protected DriverService driverService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected ClusterService clusterService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li5c09e212018-10-24 18:23:58 +0900117 protected ComponentConfigService configService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li91be8cd2018-07-22 00:44:46 +0900120 protected LeadershipService leadershipService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900123 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900126 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900129 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900132 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900133
sangho1aaa7882017-05-31 13:22:47 +0900134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900135 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900136
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 private final ExecutorService eventExecutor = newSingleThreadExecutor(
138 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
139 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Jian Li91be8cd2018-07-22 00:44:46 +0900140 private final InternalOpenstackNetworkListener osNetworkListener =
141 new InternalOpenstackNetworkListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 private ApplicationId appId;
Jian Li91be8cd2018-07-22 00:44:46 +0900143 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144
145 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800146 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
Jian Li91be8cd2018-07-22 00:44:46 +0900148 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 instancePortService.addListener(instancePortListener);
Jian Li91be8cd2018-07-22 00:44:46 +0900150 osNetworkService.addListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151
152 log.info("Started");
153 }
154
155 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800156 void deactivate() {
Jian Li91be8cd2018-07-22 00:44:46 +0900157 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 instancePortService.removeListener(instancePortListener);
159 eventExecutor.shutdown();
160
161 log.info("Stopped");
162 }
163
Jian Liea1b9662018-03-02 18:07:32 +0900164 /**
165 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900166 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900167 *
168 * @param instPort instance port object
169 * @param install install flag, add the rule if true, remove it otherwise
170 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900172 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
173 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900174 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900175 setTunnelTagIpFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900176 setForwardingRulesForVxlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900177
178 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
179 setTunnelTagArpFlowRules(instPort, install);
180 }
181
daniel parka792cf72017-04-14 16:25:35 +0900182 break;
183 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900184 setVlanTagIpFlowRules(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900185 setForwardingRulesForVlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900186
187 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
188 setVlanTagArpFlowRules(instPort, install);
189 }
190
daniel parka792cf72017-04-14 16:25:35 +0900191 break;
daniel park796c2eb2018-03-22 17:01:51 +0900192 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900193 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900194 setDownstreamRulesForFlat(instPort, install);
195 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900196 break;
daniel parka792cf72017-04-14 16:25:35 +0900197 default:
Jian Liea1b9662018-03-02 18:07:32 +0900198 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900199 break;
200 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 }
202
Jian Li24ec59f2018-05-23 19:01:25 +0900203 /**
204 * Removes virtual port.
205 *
206 * @param instPort instance port
207 */
208 private void removeVportRules(InstancePort instPort) {
209 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
210
211 switch (type) {
212 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900213 setTunnelTagIpFlowRules(instPort, false);
214
215 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
216 setTunnelTagArpFlowRules(instPort, false);
217 }
218
Jian Li24ec59f2018-05-23 19:01:25 +0900219 break;
220 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900221 setVlanTagIpFlowRules(instPort, false);
222
223 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
224 setVlanTagArpFlowRules(instPort, false);
225 }
226
Jian Li24ec59f2018-05-23 19:01:25 +0900227 break;
Jian Li9a921b42018-06-18 02:44:50 +0900228 case FLAT:
229 setFlatJumpRules(instPort, false);
230 setUpstreamRulesForFlat(instPort, false);
231 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700232 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900233 default:
Jian Li9a921b42018-06-18 02:44:50 +0900234 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900235 break;
236 }
237 }
238
Jian Li70a2c3f2018-04-13 17:26:31 +0900239 private void setFlatJumpRules(InstancePort port, boolean install) {
240 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
241 selector.matchInPort(port.portNumber());
242
243 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900244 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900245
246 osFlowRuleService.setRule(
247 appId,
248 port.deviceId(),
249 selector.build(),
250 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900251 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900252 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900253 install);
254
255 Network network = osNetworkService.network(port.networkId());
256
257 if (network == null) {
258 log.warn("The network does not exist");
259 return;
260 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900261 PortNumber portNumber = osNodeService.node(port.deviceId())
262 .phyIntfPortNum(network.getProviderPhyNet());
263
264 if (portNumber == null) {
265 log.warn("The port number does not exist");
266 return;
267 }
268
269 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900270 selector.matchInPort(portNumber)
271 .matchEthType(Ethernet.TYPE_IPV4)
272 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900273
274 osFlowRuleService.setRule(
275 appId,
276 port.deviceId(),
277 selector.build(),
278 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900279 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900280 DHCP_TABLE,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900281 install);
282
283 selector = DefaultTrafficSelector.builder();
284 selector.matchInPort(portNumber)
285 .matchEthType(Ethernet.TYPE_ARP)
286 .matchArpTpa(port.ipAddress().getIp4Address());
287
288 osFlowRuleService.setRule(
289 appId,
290 port.deviceId(),
291 selector.build(),
292 treatment.build(),
293 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900294 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900295 install);
296 }
297
Jian Li9a921b42018-06-18 02:44:50 +0900298 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900299 TrafficSelector selector = DefaultTrafficSelector.builder()
300 .matchEthType(Ethernet.TYPE_IPV4)
301 .matchIPDst(instPort.ipAddress().toIpPrefix())
302 .build();
303 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
304 .setOutput(instPort.portNumber())
305 .build();
306
307 osFlowRuleService.setRule(
308 appId,
309 instPort.deviceId(),
310 selector,
311 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900312 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900313 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900314 install);
315
316 selector = DefaultTrafficSelector.builder()
317 .matchEthType(Ethernet.TYPE_ARP)
318 .matchArpTpa(instPort.ipAddress().getIp4Address())
319 .build();
320
321 osFlowRuleService.setRule(
322 appId,
323 instPort.deviceId(),
324 selector,
325 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900326 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900327 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900328 install);
329 }
330
Jian Li9a921b42018-06-18 02:44:50 +0900331 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900332 TrafficSelector selector = DefaultTrafficSelector.builder()
333 .matchInPort(instPort.portNumber())
334 .build();
335
336 Network network = osNetworkService.network(instPort.networkId());
337
338 if (network == null) {
339 log.warn("The network does not exist");
340 return;
341 }
342
343 PortNumber portNumber = osNodeService.node(instPort.deviceId())
344 .phyIntfPortNum(network.getProviderPhyNet());
345
346 if (portNumber == null) {
347 log.warn("The port number does not exist");
348 return;
349 }
350
351 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
352 .setOutput(portNumber)
353 .build();
354
355 osFlowRuleService.setRule(
356 appId,
357 instPort.deviceId(),
358 selector,
359 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900360 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900361 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900362 install);
363 }
364
Jian Liea1b9662018-03-02 18:07:32 +0900365 /**
366 * Configures the flow rules which are used for L2 packet switching.
367 * Note that these rules will be inserted in switching table (table 5).
368 *
369 * @param instPort instance port object
370 * @param install install flag, add the rule if true, remove it otherwise
371 */
Jian Li9a921b42018-06-18 02:44:50 +0900372 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900373 // switching rules for the instPorts in the same node
374 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900375 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900376 .matchEthType(Ethernet.TYPE_IPV4)
377 .matchIPDst(instPort.ipAddress().toIpPrefix())
378 .matchTunnelId(getVni(instPort))
379 .build();
380
381 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900382 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900383 .setEthDst(instPort.macAddress())
384 .setOutput(instPort.portNumber())
385 .build();
386
sanghodc375372017-06-08 10:41:30 +0900387 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900388 appId,
389 instPort.deviceId(),
390 selector,
391 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900392 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900393 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394 install);
395
396 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900397 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
398 if (localNode == null) {
399 final String error = String.format("Cannot find openstack node for %s",
400 instPort.deviceId());
401 throw new IllegalStateException(error);
402 }
403 osNodeService.completeNodes(COMPUTE).stream()
404 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
405 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900406 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
407 .extension(buildExtension(
408 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900409 remoteNode.intgBridge(),
410 localNode.dataIp().getIp4Address()),
411 remoteNode.intgBridge())
412 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900413 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900414
sanghodc375372017-06-08 10:41:30 +0900415 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900416 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900417 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900418 selector,
419 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900420 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900421 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900422 install);
423 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900424 }
425
Jian Liea1b9662018-03-02 18:07:32 +0900426 /**
427 * Configures the flow rules which are used for L2 VLAN packet switching.
428 * Note that these rules will be inserted in switching table (table 5).
429 *
430 * @param instPort instance port object
431 * @param install install flag, add the rule if true, remove it otherwise
432 */
daniel parka792cf72017-04-14 16:25:35 +0900433 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
434 // switching rules for the instPorts in the same node
435 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900436 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900437 .matchEthType(Ethernet.TYPE_IPV4)
438 .matchIPDst(instPort.ipAddress().toIpPrefix())
439 .matchVlanId(getVlanId(instPort))
440 .build();
441
442 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
443 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900444 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900445 .setEthDst(instPort.macAddress())
446 .setOutput(instPort.portNumber())
447 .build();
448
sanghodc375372017-06-08 10:41:30 +0900449 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900450 appId,
451 instPort.deviceId(),
452 selector,
453 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900454 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900455 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900456 install);
457
458 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900459 osNodeService.completeNodes(COMPUTE).stream()
460 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
461 remoteNode.vlanIntf() != null)
462 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900463 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900464 .setEthDst(instPort.macAddress())
465 .setOutput(remoteNode.vlanPortNum())
466 .build();
daniel parka792cf72017-04-14 16:25:35 +0900467
sanghodc375372017-06-08 10:41:30 +0900468 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900469 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900470 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900471 selector,
472 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900473 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900474 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900475 install);
476 });
daniel parka792cf72017-04-14 16:25:35 +0900477 }
478
Jian Li5c09e212018-10-24 18:23:58 +0900479 private void setTunnelTagArpFlowRules(InstancePort instPort, boolean install) {
480 setTunnelTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
481 }
482
483 private void setTunnelTagIpFlowRules(InstancePort instPort, boolean install) {
484 setTunnelTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
485 }
486
Jian Liea1b9662018-03-02 18:07:32 +0900487 /**
488 * Configures the flow rule which is for using VXLAN to tag the packet
489 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900490 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900491 *
492 * @param instPort instance port object
493 * @param install install flag, add the rule if true, remove it otherwise
494 */
Jian Li5c09e212018-10-24 18:23:58 +0900495 private void setTunnelTagFlowRules(InstancePort instPort,
496 short ethType,
497 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900498 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900499 .matchEthType(ethType)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900500 .matchInPort(instPort.portNumber())
501 .build();
502
Jian Liea1b9662018-03-02 18:07:32 +0900503 // XXX All egress traffic needs to go through connection tracking module,
504 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900505 ExtensionTreatment ctTreatment =
506 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
507 .commit(true).build();
508
sanghoe6457a32017-08-24 14:31:19 +0900509 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900510 .setTunnelId(getVni(instPort))
Jian Li5c09e212018-10-24 18:23:58 +0900511 .transition(ARP_TABLE);
sanghoe6457a32017-08-24 14:31:19 +0900512
Jian Li5c09e212018-10-24 18:23:58 +0900513 if (securityGroupService.isSecurityGroupEnabled() && ethType == Ethernet.TYPE_IPV4) {
sanghoe6457a32017-08-24 14:31:19 +0900514 tb.extension(ctTreatment, instPort.deviceId());
515 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516
sanghodc375372017-06-08 10:41:30 +0900517 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900518 appId,
519 instPort.deviceId(),
520 selector,
sanghoe6457a32017-08-24 14:31:19 +0900521 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900523 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900524 install);
525 }
526
Jian Li5c09e212018-10-24 18:23:58 +0900527 private void setVlanTagIpFlowRules(InstancePort instPort, boolean install) {
528 setVlanTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
529 }
530
531 private void setVlanTagArpFlowRules(InstancePort instPort, boolean install) {
532 setVlanTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
533 }
534
Jian Liea1b9662018-03-02 18:07:32 +0900535 /**
536 * Configures the flow rule which is for using VLAN to tag the packet
537 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900538 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900539 *
540 * @param instPort instance port object
541 * @param install install flag, add the rule if true, remove it otherwise
542 */
Jian Li5c09e212018-10-24 18:23:58 +0900543 private void setVlanTagFlowRules(InstancePort instPort,
544 short ethType,
545 boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900546 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900547 .matchEthType(ethType)
daniel parka792cf72017-04-14 16:25:35 +0900548 .matchInPort(instPort.portNumber())
549 .build();
550
551 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
552 .pushVlan()
553 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900554 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900555 .build();
556
sanghodc375372017-06-08 10:41:30 +0900557 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900558 appId,
559 instPort.deviceId(),
560 selector,
561 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900562 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900563 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900564 install);
daniel parka792cf72017-04-14 16:25:35 +0900565 }
566
Jian Li91be8cd2018-07-22 00:44:46 +0900567 private void setNetworkBlockRules(Network network, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800568
Jian Li91be8cd2018-07-22 00:44:46 +0900569 NetworkType type = network.getNetworkType();
570
571 // TODO: we block a network traffic by referring to segment ID for now
572 // we might need to find a better way to block the traffic of a network
573 // in case the segment ID is overlapped in different types network (VXLAN, VLAN)
574 switch (type) {
575 case VXLAN:
576 setNetworkBlockRulesForVxlan(network.getProviderSegID(), install);
577 break;
578 case VLAN:
579 setNetworkBlockRulesForVlan(network.getProviderSegID(), install);
580 break;
581 case FLAT:
582 // TODO: need to find a way to block flat typed network
583 break;
584 default:
585 break;
Frank Wangf9571662017-06-06 18:01:29 +0800586 }
Jian Li91be8cd2018-07-22 00:44:46 +0900587 }
588
589 private void setNetworkBlockRulesForVxlan(String segmentId, boolean install) {
590 TrafficSelector selector = DefaultTrafficSelector.builder()
591 .matchTunnelId(Long.valueOf(segmentId))
592 .build();
Frank Wangf9571662017-06-06 18:01:29 +0800593
594 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
595 .drop()
596 .build();
597
Jian Li91be8cd2018-07-22 00:44:46 +0900598 osNodeService.completeNodes(COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900599 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800600 osFlowRuleService.setRule(
Jian Li91be8cd2018-07-22 00:44:46 +0900601 appId,
602 osNode.intgBridge(),
603 selector,
604 treatment,
605 PRIORITY_ADMIN_RULE,
606 ACL_TABLE,
607 install)
Jian Liea1b9662018-03-02 18:07:32 +0900608 );
Frank Wangf9571662017-06-06 18:01:29 +0800609 }
610
Jian Li91be8cd2018-07-22 00:44:46 +0900611 private void setNetworkBlockRulesForVlan(String segmentId, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800612 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li91be8cd2018-07-22 00:44:46 +0900613 .matchTunnelId(Long.valueOf(segmentId))
614 .build();
615
616 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
617 .drop()
618 .build();
619
620 osNodeService.completeNodes(COMPUTE)
621 .forEach(osNode ->
622 osFlowRuleService.setRule(
623 appId,
624 osNode.intgBridge(),
625 selector,
626 treatment,
627 PRIORITY_ADMIN_RULE,
628 ACL_TABLE,
629 install)
630 );
631 }
632
633 private void setPortBlockRules(InstancePort instPort, boolean install) {
634 TrafficSelector selector = DefaultTrafficSelector.builder()
635 .matchInPort(instPort.portNumber())
Frank Wangf9571662017-06-06 18:01:29 +0800636 .build();
637
638 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
639 .drop()
640 .build();
641
642 osFlowRuleService.setRule(
643 appId,
Jian Li91be8cd2018-07-22 00:44:46 +0900644 instPort.deviceId(),
Frank Wangf9571662017-06-06 18:01:29 +0800645 selector,
646 treatment,
647 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900648 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800649 install);
650 }
651
Jian Liea1b9662018-03-02 18:07:32 +0900652 /**
653 * Obtains the VLAN ID from the given instance port.
654 *
655 * @param instPort instance port object
656 * @return VLAN ID
657 */
daniel parka792cf72017-04-14 16:25:35 +0900658 private VlanId getVlanId(InstancePort instPort) {
659 Network osNet = osNetworkService.network(instPort.networkId());
660
661 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900662 final String error =
663 String.format(ERR_SET_FLOWS_VNI,
664 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900665 throw new IllegalStateException(error);
666 }
667
668 return VlanId.vlanId(osNet.getProviderSegID());
669 }
670
Jian Liea1b9662018-03-02 18:07:32 +0900671 /**
672 * Obtains the VNI from the given instance port.
673 *
674 * @param instPort instance port object
675 * @return VXLAN Network Identifier (VNI)
676 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900677 private Long getVni(InstancePort instPort) {
678 Network osNet = osNetworkService.network(instPort.networkId());
679 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900680 final String error =
681 String.format(ERR_SET_FLOWS_VNI,
682 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900683 throw new IllegalStateException(error);
684 }
685 return Long.valueOf(osNet.getProviderSegID());
686 }
687
Jian Li5c09e212018-10-24 18:23:58 +0900688 private String getArpMode() {
689 Set<ConfigProperty> properties = configService.getProperties(OpenstackSwitchingArpHandler.class.getName());
690 return getPropertyValue(properties, ARP_MODE);
691 }
692
Jian Liea1b9662018-03-02 18:07:32 +0900693 /**
694 * An internal instance port listener which listens the port events generated
695 * from VM. The corresponding L2 forwarding rules will be generated and
696 * inserted to integration bridge only if a new VM port is detected. If the
697 * existing detected VM port is removed due to VM purge, we will remove the
698 * corresponding L2 forwarding to as well for the sake of resource saving.
699 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900700 private class InternalInstancePortListener implements InstancePortListener {
701
702 @Override
703 public boolean isRelevant(InstancePortEvent event) {
704 InstancePort instPort = event.subject();
705 return mastershipService.isLocalMaster(instPort.deviceId());
706 }
707
708 @Override
709 public void event(InstancePortEvent event) {
710 InstancePort instPort = event.subject();
Jian Li91be8cd2018-07-22 00:44:46 +0900711 Port osPort = osNetworkService.port(instPort.portId());
Jian Li9a921b42018-06-18 02:44:50 +0900712
Hyunsun Moon44aac662017-02-18 02:07:01 +0900713 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900714 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900715 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900716 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900717 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900718 instPort.macAddress(),
719 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900720
721 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900722
Jian Li91be8cd2018-07-22 00:44:46 +0900723 if (osPort != null) {
724 eventExecutor.execute(() ->
725 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
726 }
727
Hyunsun Moon44aac662017-02-18 02:07:01 +0900728 break;
Jian Li46b74002018-07-15 18:39:08 +0900729 case OPENSTACK_INSTANCE_TERMINATED:
730 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
731 instPort.macAddress(),
732 instPort.ipAddress());
733 eventExecutor.execute(() -> removeVportRules(instPort));
734
735 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900736 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900737 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900738 instPort.macAddress(),
739 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900740
741 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900742
Jian Li91be8cd2018-07-22 00:44:46 +0900743 if (osPort != null) {
744 setPortBlockRules(instPort, false);
745 }
746
Hyunsun Moon44aac662017-02-18 02:07:01 +0900747 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900748 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
749 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
750 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900751 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900752
753 eventExecutor.execute(() -> instPortDetected(instPort));
754
Jian Li91be8cd2018-07-22 00:44:46 +0900755 if (osPort != null) {
756 eventExecutor.execute(() ->
757 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
758 }
759
Jian Liec5c32b2018-07-13 14:28:58 +0900760 break;
761 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
762 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
763 instPort.macAddress(),
764 instPort.ipAddress());
765
766 InstancePort revisedInstPort = swapStaleLocation(instPort);
767 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
768
Jian Li24ec59f2018-05-23 19:01:25 +0900769 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900770 default:
771 break;
772 }
773 }
774
775 private void instPortDetected(InstancePort instPort) {
776 setNetworkRules(instPort, true);
777 // TODO add something else if needed
778 }
779
780 private void instPortRemoved(InstancePort instPort) {
781 setNetworkRules(instPort, false);
782 // TODO add something else if needed
783 }
784 }
Jian Li91be8cd2018-07-22 00:44:46 +0900785
786 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
787
788 @Override
789 public boolean isRelevant(OpenstackNetworkEvent event) {
790
791 // do not allow to proceed without leadership
792 NodeId leader = leadershipService.getLeader(appId.name());
793 return Objects.equals(localNodeId, leader);
794 }
795
796 @Override
797 public void event(OpenstackNetworkEvent event) {
798
799 if (event.subject() == null || event.port() == null) {
800 return;
801 }
802
803 boolean isNwAdminStateUp = event.subject().isAdminStateUp();
804 boolean isPortAdminStateUp = event.port().isAdminStateUp();
805
806 InstancePort instPort = instancePortService.instancePort(event.port().getId());
807
808 switch (event.type()) {
809 case OPENSTACK_NETWORK_CREATED:
810 case OPENSTACK_NETWORK_UPDATED:
811 eventExecutor.execute(() ->
812 setNetworkBlockRules(event.subject(), !isNwAdminStateUp));
813
814 break;
815 case OPENSTACK_NETWORK_REMOVED:
816 eventExecutor.execute(() ->
817 setNetworkBlockRules(event.subject(), false));
818 break;
819 case OPENSTACK_PORT_CREATED:
820 case OPENSTACK_PORT_UPDATED:
821
822 if (instPort != null) {
823 eventExecutor.execute(() ->
824 setPortBlockRules(instPort, !isPortAdminStateUp));
825 }
826
827 break;
828 case OPENSTACK_PORT_REMOVED:
829
830 if (instPort != null) {
831 eventExecutor.execute(() ->
832 setPortBlockRules(instPort, false));
833 }
834
835 break;
836 default:
837 break;
838 }
839 }
840 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900841}