blob: b348d4903f303ab894b8c13b21f0e56c4c4f7f69 [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;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070020import org.osgi.service.component.annotations.Activate;
21import org.osgi.service.component.annotations.Component;
22import org.osgi.service.component.annotations.Deactivate;
23import org.osgi.service.component.annotations.Reference;
24import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090025import 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
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900102 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900105 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900108 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900111 protected DriverService driverService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900114 protected ClusterService clusterService;
115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li5c09e212018-10-24 18:23:58 +0900117 protected ComponentConfigService configService;
118
Ray Milkey956bb162018-10-26 10:53:44 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
120
Jian Li91be8cd2018-07-22 00:44:46 +0900121 protected LeadershipService leadershipService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900124 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900127 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900130 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900133 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900136 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900137
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 private final ExecutorService eventExecutor = newSingleThreadExecutor(
139 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
140 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Jian Li91be8cd2018-07-22 00:44:46 +0900141 private final InternalOpenstackNetworkListener osNetworkListener =
142 new InternalOpenstackNetworkListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private ApplicationId appId;
Jian Li91be8cd2018-07-22 00:44:46 +0900144 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145
146 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800147 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
Jian Li91be8cd2018-07-22 00:44:46 +0900149 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150 instancePortService.addListener(instancePortListener);
Jian Li91be8cd2018-07-22 00:44:46 +0900151 osNetworkService.addListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900152
153 log.info("Started");
154 }
155
156 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800157 void deactivate() {
Jian Li91be8cd2018-07-22 00:44:46 +0900158 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 instancePortService.removeListener(instancePortListener);
160 eventExecutor.shutdown();
161
162 log.info("Stopped");
163 }
164
Jian Liea1b9662018-03-02 18:07:32 +0900165 /**
166 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900167 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900168 *
169 * @param instPort instance port object
170 * @param install install flag, add the rule if true, remove it otherwise
171 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900173 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
174 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900175 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900176 setTunnelTagIpFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900177 setForwardingRulesForVxlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900178
179 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
180 setTunnelTagArpFlowRules(instPort, install);
181 }
182
daniel parka792cf72017-04-14 16:25:35 +0900183 break;
184 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900185 setVlanTagIpFlowRules(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900186 setForwardingRulesForVlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900187
188 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
189 setVlanTagArpFlowRules(instPort, install);
190 }
191
daniel parka792cf72017-04-14 16:25:35 +0900192 break;
daniel park796c2eb2018-03-22 17:01:51 +0900193 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900194 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900195 setDownstreamRulesForFlat(instPort, install);
196 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900197 break;
daniel parka792cf72017-04-14 16:25:35 +0900198 default:
Jian Liea1b9662018-03-02 18:07:32 +0900199 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900200 break;
201 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900202 }
203
Jian Li24ec59f2018-05-23 19:01:25 +0900204 /**
205 * Removes virtual port.
206 *
207 * @param instPort instance port
208 */
209 private void removeVportRules(InstancePort instPort) {
210 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
211
212 switch (type) {
213 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900214 setTunnelTagIpFlowRules(instPort, false);
215
216 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
217 setTunnelTagArpFlowRules(instPort, false);
218 }
219
Jian Li24ec59f2018-05-23 19:01:25 +0900220 break;
221 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900222 setVlanTagIpFlowRules(instPort, false);
223
224 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
225 setVlanTagArpFlowRules(instPort, false);
226 }
227
Jian Li24ec59f2018-05-23 19:01:25 +0900228 break;
Jian Li9a921b42018-06-18 02:44:50 +0900229 case FLAT:
230 setFlatJumpRules(instPort, false);
231 setUpstreamRulesForFlat(instPort, false);
232 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700233 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900234 default:
Jian Li9a921b42018-06-18 02:44:50 +0900235 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900236 break;
237 }
238 }
239
Jian Li70a2c3f2018-04-13 17:26:31 +0900240 private void setFlatJumpRules(InstancePort port, boolean install) {
241 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
242 selector.matchInPort(port.portNumber());
243
244 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900245 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900246
247 osFlowRuleService.setRule(
248 appId,
249 port.deviceId(),
250 selector.build(),
251 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900252 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900253 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900254 install);
255
256 Network network = osNetworkService.network(port.networkId());
257
258 if (network == null) {
259 log.warn("The network does not exist");
260 return;
261 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900262 PortNumber portNumber = osNodeService.node(port.deviceId())
263 .phyIntfPortNum(network.getProviderPhyNet());
264
265 if (portNumber == null) {
266 log.warn("The port number does not exist");
267 return;
268 }
269
270 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900271 selector.matchInPort(portNumber)
272 .matchEthType(Ethernet.TYPE_IPV4)
273 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900274
275 osFlowRuleService.setRule(
276 appId,
277 port.deviceId(),
278 selector.build(),
279 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900280 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900281 DHCP_TABLE,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900282 install);
283
284 selector = DefaultTrafficSelector.builder();
285 selector.matchInPort(portNumber)
286 .matchEthType(Ethernet.TYPE_ARP)
287 .matchArpTpa(port.ipAddress().getIp4Address());
288
289 osFlowRuleService.setRule(
290 appId,
291 port.deviceId(),
292 selector.build(),
293 treatment.build(),
294 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900295 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900296 install);
297 }
298
Jian Li9a921b42018-06-18 02:44:50 +0900299 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900300 TrafficSelector selector = DefaultTrafficSelector.builder()
301 .matchEthType(Ethernet.TYPE_IPV4)
302 .matchIPDst(instPort.ipAddress().toIpPrefix())
303 .build();
304 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
305 .setOutput(instPort.portNumber())
306 .build();
307
308 osFlowRuleService.setRule(
309 appId,
310 instPort.deviceId(),
311 selector,
312 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900313 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900314 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900315 install);
316
317 selector = DefaultTrafficSelector.builder()
318 .matchEthType(Ethernet.TYPE_ARP)
319 .matchArpTpa(instPort.ipAddress().getIp4Address())
320 .build();
321
322 osFlowRuleService.setRule(
323 appId,
324 instPort.deviceId(),
325 selector,
326 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900327 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900328 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900329 install);
330 }
331
Jian Li9a921b42018-06-18 02:44:50 +0900332 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900333 TrafficSelector selector = DefaultTrafficSelector.builder()
334 .matchInPort(instPort.portNumber())
335 .build();
336
337 Network network = osNetworkService.network(instPort.networkId());
338
339 if (network == null) {
340 log.warn("The network does not exist");
341 return;
342 }
343
344 PortNumber portNumber = osNodeService.node(instPort.deviceId())
345 .phyIntfPortNum(network.getProviderPhyNet());
346
347 if (portNumber == null) {
348 log.warn("The port number does not exist");
349 return;
350 }
351
352 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
353 .setOutput(portNumber)
354 .build();
355
356 osFlowRuleService.setRule(
357 appId,
358 instPort.deviceId(),
359 selector,
360 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900361 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900362 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900363 install);
364 }
365
Jian Liea1b9662018-03-02 18:07:32 +0900366 /**
367 * Configures the flow rules which are used for L2 packet switching.
368 * Note that these rules will be inserted in switching table (table 5).
369 *
370 * @param instPort instance port object
371 * @param install install flag, add the rule if true, remove it otherwise
372 */
Jian Li9a921b42018-06-18 02:44:50 +0900373 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900374 // switching rules for the instPorts in the same node
375 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900376 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377 .matchEthType(Ethernet.TYPE_IPV4)
378 .matchIPDst(instPort.ipAddress().toIpPrefix())
379 .matchTunnelId(getVni(instPort))
380 .build();
381
382 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900383 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 .setEthDst(instPort.macAddress())
385 .setOutput(instPort.portNumber())
386 .build();
387
sanghodc375372017-06-08 10:41:30 +0900388 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 appId,
390 instPort.deviceId(),
391 selector,
392 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900393 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900394 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900395 install);
396
397 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900398 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
399 if (localNode == null) {
400 final String error = String.format("Cannot find openstack node for %s",
401 instPort.deviceId());
402 throw new IllegalStateException(error);
403 }
404 osNodeService.completeNodes(COMPUTE).stream()
405 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
406 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900407 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
408 .extension(buildExtension(
409 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900410 remoteNode.intgBridge(),
411 localNode.dataIp().getIp4Address()),
412 remoteNode.intgBridge())
413 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900414 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900415
sanghodc375372017-06-08 10:41:30 +0900416 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900417 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900418 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900419 selector,
420 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900421 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900422 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900423 install);
424 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900425 }
426
Jian Liea1b9662018-03-02 18:07:32 +0900427 /**
428 * Configures the flow rules which are used for L2 VLAN packet switching.
429 * Note that these rules will be inserted in switching table (table 5).
430 *
431 * @param instPort instance port object
432 * @param install install flag, add the rule if true, remove it otherwise
433 */
daniel parka792cf72017-04-14 16:25:35 +0900434 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
435 // switching rules for the instPorts in the same node
436 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900437 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900438 .matchEthType(Ethernet.TYPE_IPV4)
439 .matchIPDst(instPort.ipAddress().toIpPrefix())
440 .matchVlanId(getVlanId(instPort))
441 .build();
442
443 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
444 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900445 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900446 .setEthDst(instPort.macAddress())
447 .setOutput(instPort.portNumber())
448 .build();
449
sanghodc375372017-06-08 10:41:30 +0900450 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900451 appId,
452 instPort.deviceId(),
453 selector,
454 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900455 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900456 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900457 install);
458
459 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900460 osNodeService.completeNodes(COMPUTE).stream()
461 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
462 remoteNode.vlanIntf() != null)
463 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900464 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900465 .setEthDst(instPort.macAddress())
466 .setOutput(remoteNode.vlanPortNum())
467 .build();
daniel parka792cf72017-04-14 16:25:35 +0900468
sanghodc375372017-06-08 10:41:30 +0900469 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900470 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900471 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900472 selector,
473 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900474 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900475 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900476 install);
477 });
daniel parka792cf72017-04-14 16:25:35 +0900478 }
479
Jian Li5c09e212018-10-24 18:23:58 +0900480 private void setTunnelTagArpFlowRules(InstancePort instPort, boolean install) {
481 setTunnelTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
482 }
483
484 private void setTunnelTagIpFlowRules(InstancePort instPort, boolean install) {
485 setTunnelTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
486 }
487
Jian Liea1b9662018-03-02 18:07:32 +0900488 /**
489 * Configures the flow rule which is for using VXLAN to tag the packet
490 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900491 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900492 *
493 * @param instPort instance port object
494 * @param install install flag, add the rule if true, remove it otherwise
495 */
Jian Li5c09e212018-10-24 18:23:58 +0900496 private void setTunnelTagFlowRules(InstancePort instPort,
497 short ethType,
498 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900500 .matchEthType(ethType)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900501 .matchInPort(instPort.portNumber())
502 .build();
503
Jian Liea1b9662018-03-02 18:07:32 +0900504 // XXX All egress traffic needs to go through connection tracking module,
505 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900506 ExtensionTreatment ctTreatment =
507 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
508 .commit(true).build();
509
sanghoe6457a32017-08-24 14:31:19 +0900510 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900511 .setTunnelId(getVni(instPort))
Jian Li5c09e212018-10-24 18:23:58 +0900512 .transition(ARP_TABLE);
sanghoe6457a32017-08-24 14:31:19 +0900513
Jian Li5c09e212018-10-24 18:23:58 +0900514 if (securityGroupService.isSecurityGroupEnabled() && ethType == Ethernet.TYPE_IPV4) {
sanghoe6457a32017-08-24 14:31:19 +0900515 tb.extension(ctTreatment, instPort.deviceId());
516 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517
sanghodc375372017-06-08 10:41:30 +0900518 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519 appId,
520 instPort.deviceId(),
521 selector,
sanghoe6457a32017-08-24 14:31:19 +0900522 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900524 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525 install);
526 }
527
Jian Li5c09e212018-10-24 18:23:58 +0900528 private void setVlanTagIpFlowRules(InstancePort instPort, boolean install) {
529 setVlanTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
530 }
531
532 private void setVlanTagArpFlowRules(InstancePort instPort, boolean install) {
533 setVlanTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
534 }
535
Jian Liea1b9662018-03-02 18:07:32 +0900536 /**
537 * Configures the flow rule which is for using VLAN to tag the packet
538 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900539 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900540 *
541 * @param instPort instance port object
542 * @param install install flag, add the rule if true, remove it otherwise
543 */
Jian Li5c09e212018-10-24 18:23:58 +0900544 private void setVlanTagFlowRules(InstancePort instPort,
545 short ethType,
546 boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900547 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900548 .matchEthType(ethType)
daniel parka792cf72017-04-14 16:25:35 +0900549 .matchInPort(instPort.portNumber())
550 .build();
551
552 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
553 .pushVlan()
554 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900555 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900556 .build();
557
sanghodc375372017-06-08 10:41:30 +0900558 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900559 appId,
560 instPort.deviceId(),
561 selector,
562 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900563 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900564 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900565 install);
daniel parka792cf72017-04-14 16:25:35 +0900566 }
567
Jian Li91be8cd2018-07-22 00:44:46 +0900568 private void setNetworkBlockRules(Network network, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800569
Jian Li91be8cd2018-07-22 00:44:46 +0900570 NetworkType type = network.getNetworkType();
571
572 // TODO: we block a network traffic by referring to segment ID for now
573 // we might need to find a better way to block the traffic of a network
574 // in case the segment ID is overlapped in different types network (VXLAN, VLAN)
575 switch (type) {
576 case VXLAN:
577 setNetworkBlockRulesForVxlan(network.getProviderSegID(), install);
578 break;
579 case VLAN:
580 setNetworkBlockRulesForVlan(network.getProviderSegID(), install);
581 break;
582 case FLAT:
583 // TODO: need to find a way to block flat typed network
584 break;
585 default:
586 break;
Frank Wangf9571662017-06-06 18:01:29 +0800587 }
Jian Li91be8cd2018-07-22 00:44:46 +0900588 }
589
590 private void setNetworkBlockRulesForVxlan(String segmentId, boolean install) {
591 TrafficSelector selector = DefaultTrafficSelector.builder()
592 .matchTunnelId(Long.valueOf(segmentId))
593 .build();
Frank Wangf9571662017-06-06 18:01:29 +0800594
595 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
596 .drop()
597 .build();
598
Jian Li91be8cd2018-07-22 00:44:46 +0900599 osNodeService.completeNodes(COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900600 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800601 osFlowRuleService.setRule(
Jian Li91be8cd2018-07-22 00:44:46 +0900602 appId,
603 osNode.intgBridge(),
604 selector,
605 treatment,
606 PRIORITY_ADMIN_RULE,
607 ACL_TABLE,
608 install)
Jian Liea1b9662018-03-02 18:07:32 +0900609 );
Frank Wangf9571662017-06-06 18:01:29 +0800610 }
611
Jian Li91be8cd2018-07-22 00:44:46 +0900612 private void setNetworkBlockRulesForVlan(String segmentId, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800613 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li91be8cd2018-07-22 00:44:46 +0900614 .matchTunnelId(Long.valueOf(segmentId))
615 .build();
616
617 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
618 .drop()
619 .build();
620
621 osNodeService.completeNodes(COMPUTE)
622 .forEach(osNode ->
623 osFlowRuleService.setRule(
624 appId,
625 osNode.intgBridge(),
626 selector,
627 treatment,
628 PRIORITY_ADMIN_RULE,
629 ACL_TABLE,
630 install)
631 );
632 }
633
634 private void setPortBlockRules(InstancePort instPort, boolean install) {
635 TrafficSelector selector = DefaultTrafficSelector.builder()
636 .matchInPort(instPort.portNumber())
Frank Wangf9571662017-06-06 18:01:29 +0800637 .build();
638
639 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
640 .drop()
641 .build();
642
643 osFlowRuleService.setRule(
644 appId,
Jian Li91be8cd2018-07-22 00:44:46 +0900645 instPort.deviceId(),
Frank Wangf9571662017-06-06 18:01:29 +0800646 selector,
647 treatment,
648 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900649 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800650 install);
651 }
652
Jian Liea1b9662018-03-02 18:07:32 +0900653 /**
654 * Obtains the VLAN ID from the given instance port.
655 *
656 * @param instPort instance port object
657 * @return VLAN ID
658 */
daniel parka792cf72017-04-14 16:25:35 +0900659 private VlanId getVlanId(InstancePort instPort) {
660 Network osNet = osNetworkService.network(instPort.networkId());
661
662 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900663 final String error =
664 String.format(ERR_SET_FLOWS_VNI,
665 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900666 throw new IllegalStateException(error);
667 }
668
669 return VlanId.vlanId(osNet.getProviderSegID());
670 }
671
Jian Liea1b9662018-03-02 18:07:32 +0900672 /**
673 * Obtains the VNI from the given instance port.
674 *
675 * @param instPort instance port object
676 * @return VXLAN Network Identifier (VNI)
677 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 private Long getVni(InstancePort instPort) {
679 Network osNet = osNetworkService.network(instPort.networkId());
680 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900681 final String error =
682 String.format(ERR_SET_FLOWS_VNI,
683 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900684 throw new IllegalStateException(error);
685 }
686 return Long.valueOf(osNet.getProviderSegID());
687 }
688
Jian Li5c09e212018-10-24 18:23:58 +0900689 private String getArpMode() {
690 Set<ConfigProperty> properties = configService.getProperties(OpenstackSwitchingArpHandler.class.getName());
691 return getPropertyValue(properties, ARP_MODE);
692 }
693
Jian Liea1b9662018-03-02 18:07:32 +0900694 /**
695 * An internal instance port listener which listens the port events generated
696 * from VM. The corresponding L2 forwarding rules will be generated and
697 * inserted to integration bridge only if a new VM port is detected. If the
698 * existing detected VM port is removed due to VM purge, we will remove the
699 * corresponding L2 forwarding to as well for the sake of resource saving.
700 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900701 private class InternalInstancePortListener implements InstancePortListener {
702
703 @Override
704 public boolean isRelevant(InstancePortEvent event) {
705 InstancePort instPort = event.subject();
706 return mastershipService.isLocalMaster(instPort.deviceId());
707 }
708
709 @Override
710 public void event(InstancePortEvent event) {
711 InstancePort instPort = event.subject();
Jian Li91be8cd2018-07-22 00:44:46 +0900712 Port osPort = osNetworkService.port(instPort.portId());
Jian Li9a921b42018-06-18 02:44:50 +0900713
Hyunsun Moon44aac662017-02-18 02:07:01 +0900714 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900715 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900716 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900717 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900718 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900719 instPort.macAddress(),
720 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900721
722 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900723
Jian Li91be8cd2018-07-22 00:44:46 +0900724 if (osPort != null) {
725 eventExecutor.execute(() ->
726 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
727 }
728
Hyunsun Moon44aac662017-02-18 02:07:01 +0900729 break;
Jian Li46b74002018-07-15 18:39:08 +0900730 case OPENSTACK_INSTANCE_TERMINATED:
731 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
732 instPort.macAddress(),
733 instPort.ipAddress());
734 eventExecutor.execute(() -> removeVportRules(instPort));
735
736 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900737 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900738 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900739 instPort.macAddress(),
740 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900741
742 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900743
Jian Li91be8cd2018-07-22 00:44:46 +0900744 if (osPort != null) {
745 setPortBlockRules(instPort, false);
746 }
747
Hyunsun Moon44aac662017-02-18 02:07:01 +0900748 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900749 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
750 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
751 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900752 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900753
754 eventExecutor.execute(() -> instPortDetected(instPort));
755
Jian Li91be8cd2018-07-22 00:44:46 +0900756 if (osPort != null) {
757 eventExecutor.execute(() ->
758 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
759 }
760
Jian Liec5c32b2018-07-13 14:28:58 +0900761 break;
762 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
763 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
764 instPort.macAddress(),
765 instPort.ipAddress());
766
767 InstancePort revisedInstPort = swapStaleLocation(instPort);
768 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
769
Jian Li24ec59f2018-05-23 19:01:25 +0900770 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900771 default:
772 break;
773 }
774 }
775
776 private void instPortDetected(InstancePort instPort) {
777 setNetworkRules(instPort, true);
778 // TODO add something else if needed
779 }
780
781 private void instPortRemoved(InstancePort instPort) {
782 setNetworkRules(instPort, false);
783 // TODO add something else if needed
784 }
785 }
Jian Li91be8cd2018-07-22 00:44:46 +0900786
787 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
788
789 @Override
790 public boolean isRelevant(OpenstackNetworkEvent event) {
791
792 // do not allow to proceed without leadership
793 NodeId leader = leadershipService.getLeader(appId.name());
794 return Objects.equals(localNodeId, leader);
795 }
796
797 @Override
798 public void event(OpenstackNetworkEvent event) {
799
800 if (event.subject() == null || event.port() == null) {
801 return;
802 }
803
804 boolean isNwAdminStateUp = event.subject().isAdminStateUp();
805 boolean isPortAdminStateUp = event.port().isAdminStateUp();
806
807 InstancePort instPort = instancePortService.instancePort(event.port().getId());
808
809 switch (event.type()) {
810 case OPENSTACK_NETWORK_CREATED:
811 case OPENSTACK_NETWORK_UPDATED:
812 eventExecutor.execute(() ->
813 setNetworkBlockRules(event.subject(), !isNwAdminStateUp));
814
815 break;
816 case OPENSTACK_NETWORK_REMOVED:
817 eventExecutor.execute(() ->
818 setNetworkBlockRules(event.subject(), false));
819 break;
820 case OPENSTACK_PORT_CREATED:
821 case OPENSTACK_PORT_UPDATED:
822
823 if (instPort != null) {
824 eventExecutor.execute(() ->
825 setPortBlockRules(instPort, !isPortAdminStateUp));
826 }
827
828 break;
829 case OPENSTACK_PORT_REMOVED:
830
831 if (instPort != null) {
832 eventExecutor.execute(() ->
833 setPortBlockRules(instPort, false));
834 }
835
836 break;
837 default:
838 break;
839 }
840 }
841 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900842}