blob: f6977a3d3bab2c16e721684f016ad46aef984868 [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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.openstacknetworking.api.InstancePort;
43import org.onosproject.openstacknetworking.api.InstancePortEvent;
44import org.onosproject.openstacknetworking.api.InstancePortListener;
45import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090046import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Li91be8cd2018-07-22 00:44:46 +090047import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
48import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghoe6457a32017-08-24 14:31:19 +090050import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090051import org.onosproject.openstacknode.api.OpenstackNode;
52import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.openstack4j.model.network.Network;
Frank Wangf9571662017-06-06 18:01:29 +080054import org.openstack4j.model.network.NetworkType;
55import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.slf4j.Logger;
57
Jian Li91be8cd2018-07-22 00:44:46 +090058import java.util.Objects;
Jian Li5c09e212018-10-24 18:23:58 +090059import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import java.util.concurrent.ExecutorService;
61
62import static java.util.concurrent.Executors.newSingleThreadExecutor;
63import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090064import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
Jian Li5c09e212018-10-24 18:23:58 +090065import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
66import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
67import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090068import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
sanghodc375372017-06-08 10:41:30 +090069import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
70import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080071import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Daniel Parkd1b14d32018-06-12 16:10:28 +090072import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_DOWNSTREAM_RULE;
73import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE;
74import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
75import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_UPSTREAM_RULE;
sanghodc375372017-06-08 10:41:30 +090076import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
77import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li960ae512018-07-03 22:50:56 +090078import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090079import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Li5c09e212018-10-24 18:23:58 +090080import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090081import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090082import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090083import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090084import static org.slf4j.LoggerFactory.getLogger;
85
86
87/**
88 * Populates switching flow rules on OVS for the basic connectivity among the
89 * virtual instances in the same network.
90 */
91@Component(immediate = true)
92public final class OpenstackSwitchingHandler {
93
94 private final Logger log = getLogger(getClass());
95
Jian Li5c09e212018-10-24 18:23:58 +090096 private static final String ARP_MODE = "arpMode";
Jian Li71670d12018-03-02 21:31:07 +090097 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 +090098
Ray Milkeyd84f89b2018-08-17 14:54:17 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900100 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900103 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900106 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900109 protected DriverService driverService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900112 protected ClusterService clusterService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li5c09e212018-10-24 18:23:58 +0900115 protected ComponentConfigService configService;
116
Ray Milkey956bb162018-10-26 10:53:44 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
118
Jian Li91be8cd2018-07-22 00:44:46 +0900119 protected LeadershipService leadershipService;
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900122 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900125 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900128 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900131 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900134 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900135
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136 private final ExecutorService eventExecutor = newSingleThreadExecutor(
137 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
138 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Jian Li91be8cd2018-07-22 00:44:46 +0900139 private final InternalOpenstackNetworkListener osNetworkListener =
140 new InternalOpenstackNetworkListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 private ApplicationId appId;
Jian Li91be8cd2018-07-22 00:44:46 +0900142 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143
144 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800145 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
Jian Li91be8cd2018-07-22 00:44:46 +0900147 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 instancePortService.addListener(instancePortListener);
Jian Li91be8cd2018-07-22 00:44:46 +0900149 osNetworkService.addListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150
151 log.info("Started");
152 }
153
154 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800155 void deactivate() {
Jian Li91be8cd2018-07-22 00:44:46 +0900156 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 instancePortService.removeListener(instancePortListener);
158 eventExecutor.shutdown();
159
160 log.info("Stopped");
161 }
162
Jian Liea1b9662018-03-02 18:07:32 +0900163 /**
164 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900165 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900166 *
167 * @param instPort instance port object
168 * @param install install flag, add the rule if true, remove it otherwise
169 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900170 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900171 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
172 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900173 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900174 setTunnelTagIpFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900175 setForwardingRulesForVxlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900176
177 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
178 setTunnelTagArpFlowRules(instPort, install);
179 }
180
daniel parka792cf72017-04-14 16:25:35 +0900181 break;
182 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900183 setVlanTagIpFlowRules(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900184 setForwardingRulesForVlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900185
186 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
187 setVlanTagArpFlowRules(instPort, install);
188 }
189
daniel parka792cf72017-04-14 16:25:35 +0900190 break;
daniel park796c2eb2018-03-22 17:01:51 +0900191 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900192 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900193 setDownstreamRulesForFlat(instPort, install);
194 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900195 break;
daniel parka792cf72017-04-14 16:25:35 +0900196 default:
Jian Liea1b9662018-03-02 18:07:32 +0900197 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900198 break;
199 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900200 }
201
Jian Li24ec59f2018-05-23 19:01:25 +0900202 /**
203 * Removes virtual port.
204 *
205 * @param instPort instance port
206 */
207 private void removeVportRules(InstancePort instPort) {
208 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
209
210 switch (type) {
211 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900212 setTunnelTagIpFlowRules(instPort, false);
213
214 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
215 setTunnelTagArpFlowRules(instPort, false);
216 }
217
Jian Li24ec59f2018-05-23 19:01:25 +0900218 break;
219 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900220 setVlanTagIpFlowRules(instPort, false);
221
222 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
223 setVlanTagArpFlowRules(instPort, false);
224 }
225
Jian Li24ec59f2018-05-23 19:01:25 +0900226 break;
Jian Li9a921b42018-06-18 02:44:50 +0900227 case FLAT:
228 setFlatJumpRules(instPort, false);
229 setUpstreamRulesForFlat(instPort, false);
230 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700231 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900232 default:
Jian Li9a921b42018-06-18 02:44:50 +0900233 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900234 break;
235 }
236 }
237
Jian Li70a2c3f2018-04-13 17:26:31 +0900238 private void setFlatJumpRules(InstancePort port, boolean install) {
239 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
240 selector.matchInPort(port.portNumber());
241
242 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900243 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900244
245 osFlowRuleService.setRule(
246 appId,
247 port.deviceId(),
248 selector.build(),
249 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900250 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900251 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900252 install);
253
254 Network network = osNetworkService.network(port.networkId());
255
256 if (network == null) {
257 log.warn("The network does not exist");
258 return;
259 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900260 PortNumber portNumber = osNodeService.node(port.deviceId())
261 .phyIntfPortNum(network.getProviderPhyNet());
262
263 if (portNumber == null) {
264 log.warn("The port number does not exist");
265 return;
266 }
267
268 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900269 selector.matchInPort(portNumber)
270 .matchEthType(Ethernet.TYPE_IPV4)
271 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900272
273 osFlowRuleService.setRule(
274 appId,
275 port.deviceId(),
276 selector.build(),
277 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900278 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900279 DHCP_TABLE,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900280 install);
281
282 selector = DefaultTrafficSelector.builder();
283 selector.matchInPort(portNumber)
284 .matchEthType(Ethernet.TYPE_ARP)
285 .matchArpTpa(port.ipAddress().getIp4Address());
286
287 osFlowRuleService.setRule(
288 appId,
289 port.deviceId(),
290 selector.build(),
291 treatment.build(),
292 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900293 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900294 install);
295 }
296
Jian Li9a921b42018-06-18 02:44:50 +0900297 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900298 TrafficSelector selector = DefaultTrafficSelector.builder()
299 .matchEthType(Ethernet.TYPE_IPV4)
300 .matchIPDst(instPort.ipAddress().toIpPrefix())
301 .build();
302 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
303 .setOutput(instPort.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_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900312 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900313 install);
314
315 selector = DefaultTrafficSelector.builder()
316 .matchEthType(Ethernet.TYPE_ARP)
317 .matchArpTpa(instPort.ipAddress().getIp4Address())
318 .build();
319
320 osFlowRuleService.setRule(
321 appId,
322 instPort.deviceId(),
323 selector,
324 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900325 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900326 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900327 install);
328 }
329
Jian Li9a921b42018-06-18 02:44:50 +0900330 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900331 TrafficSelector selector = DefaultTrafficSelector.builder()
332 .matchInPort(instPort.portNumber())
333 .build();
334
335 Network network = osNetworkService.network(instPort.networkId());
336
337 if (network == null) {
338 log.warn("The network does not exist");
339 return;
340 }
341
342 PortNumber portNumber = osNodeService.node(instPort.deviceId())
343 .phyIntfPortNum(network.getProviderPhyNet());
344
345 if (portNumber == null) {
346 log.warn("The port number does not exist");
347 return;
348 }
349
350 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
351 .setOutput(portNumber)
352 .build();
353
354 osFlowRuleService.setRule(
355 appId,
356 instPort.deviceId(),
357 selector,
358 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900359 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900360 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900361 install);
362 }
363
Jian Liea1b9662018-03-02 18:07:32 +0900364 /**
365 * Configures the flow rules which are used for L2 packet switching.
366 * Note that these rules will be inserted in switching table (table 5).
367 *
368 * @param instPort instance port object
369 * @param install install flag, add the rule if true, remove it otherwise
370 */
Jian Li9a921b42018-06-18 02:44:50 +0900371 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372 // switching rules for the instPorts in the same node
373 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900374 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900375 .matchEthType(Ethernet.TYPE_IPV4)
376 .matchIPDst(instPort.ipAddress().toIpPrefix())
377 .matchTunnelId(getVni(instPort))
378 .build();
379
380 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900381 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900382 .setEthDst(instPort.macAddress())
383 .setOutput(instPort.portNumber())
384 .build();
385
sanghodc375372017-06-08 10:41:30 +0900386 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900387 appId,
388 instPort.deviceId(),
389 selector,
390 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900392 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900393 install);
394
395 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900396 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
397 if (localNode == null) {
398 final String error = String.format("Cannot find openstack node for %s",
399 instPort.deviceId());
400 throw new IllegalStateException(error);
401 }
402 osNodeService.completeNodes(COMPUTE).stream()
403 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
404 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900405 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
406 .extension(buildExtension(
407 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900408 remoteNode.intgBridge(),
409 localNode.dataIp().getIp4Address()),
410 remoteNode.intgBridge())
411 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900412 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900413
sanghodc375372017-06-08 10:41:30 +0900414 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900415 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900416 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900417 selector,
418 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900419 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900420 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900421 install);
422 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900423 }
424
Jian Liea1b9662018-03-02 18:07:32 +0900425 /**
426 * Configures the flow rules which are used for L2 VLAN packet switching.
427 * Note that these rules will be inserted in switching table (table 5).
428 *
429 * @param instPort instance port object
430 * @param install install flag, add the rule if true, remove it otherwise
431 */
daniel parka792cf72017-04-14 16:25:35 +0900432 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
433 // switching rules for the instPorts in the same node
434 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900435 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900436 .matchEthType(Ethernet.TYPE_IPV4)
437 .matchIPDst(instPort.ipAddress().toIpPrefix())
438 .matchVlanId(getVlanId(instPort))
439 .build();
440
441 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
442 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900443 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900444 .setEthDst(instPort.macAddress())
445 .setOutput(instPort.portNumber())
446 .build();
447
sanghodc375372017-06-08 10:41:30 +0900448 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900449 appId,
450 instPort.deviceId(),
451 selector,
452 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900453 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900454 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900455 install);
456
457 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900458 osNodeService.completeNodes(COMPUTE).stream()
459 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
460 remoteNode.vlanIntf() != null)
461 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900462 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900463 .setEthDst(instPort.macAddress())
464 .setOutput(remoteNode.vlanPortNum())
465 .build();
daniel parka792cf72017-04-14 16:25:35 +0900466
sanghodc375372017-06-08 10:41:30 +0900467 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900468 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900469 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900470 selector,
471 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900472 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900473 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900474 install);
475 });
daniel parka792cf72017-04-14 16:25:35 +0900476 }
477
Jian Li5c09e212018-10-24 18:23:58 +0900478 private void setTunnelTagArpFlowRules(InstancePort instPort, boolean install) {
479 setTunnelTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
480 }
481
482 private void setTunnelTagIpFlowRules(InstancePort instPort, boolean install) {
483 setTunnelTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
484 }
485
Jian Liea1b9662018-03-02 18:07:32 +0900486 /**
487 * Configures the flow rule which is for using VXLAN to tag the packet
488 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900489 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900490 *
491 * @param instPort instance port object
492 * @param install install flag, add the rule if true, remove it otherwise
493 */
Jian Li5c09e212018-10-24 18:23:58 +0900494 private void setTunnelTagFlowRules(InstancePort instPort,
495 short ethType,
496 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900497 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900498 .matchEthType(ethType)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 .matchInPort(instPort.portNumber())
500 .build();
501
Jian Li28ec77f2018-10-31 07:07:25 +0900502 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
503 .setTunnelId(getVni(instPort));
sangho1aaa7882017-05-31 13:22:47 +0900504
sanghoe6457a32017-08-24 14:31:19 +0900505
Jian Li28ec77f2018-10-31 07:07:25 +0900506 if (ethType == Ethernet.TYPE_ARP) {
507 tBuilder.transition(ARP_TABLE);
508 } else if (ethType == Ethernet.TYPE_IPV4) {
509 tBuilder.transition(ACL_TABLE);
sanghoe6457a32017-08-24 14:31:19 +0900510 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900511
sanghodc375372017-06-08 10:41:30 +0900512 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900513 appId,
514 instPort.deviceId(),
515 selector,
Jian Li28ec77f2018-10-31 07:07:25 +0900516 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900518 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519 install);
520 }
521
Jian Li5c09e212018-10-24 18:23:58 +0900522 private void setVlanTagIpFlowRules(InstancePort instPort, boolean install) {
523 setVlanTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
524 }
525
526 private void setVlanTagArpFlowRules(InstancePort instPort, boolean install) {
527 setVlanTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
528 }
529
Jian Liea1b9662018-03-02 18:07:32 +0900530 /**
531 * Configures the flow rule which is for using VLAN to tag the packet
532 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900533 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900534 *
535 * @param instPort instance port object
536 * @param install install flag, add the rule if true, remove it otherwise
537 */
Jian Li5c09e212018-10-24 18:23:58 +0900538 private void setVlanTagFlowRules(InstancePort instPort,
539 short ethType,
540 boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900541 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900542 .matchEthType(ethType)
daniel parka792cf72017-04-14 16:25:35 +0900543 .matchInPort(instPort.portNumber())
544 .build();
545
546 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
547 .pushVlan()
548 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900549 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900550 .build();
551
sanghodc375372017-06-08 10:41:30 +0900552 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900553 appId,
554 instPort.deviceId(),
555 selector,
556 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900557 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900558 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900559 install);
daniel parka792cf72017-04-14 16:25:35 +0900560 }
561
Jian Li91be8cd2018-07-22 00:44:46 +0900562 private void setNetworkBlockRules(Network network, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800563
Jian Li91be8cd2018-07-22 00:44:46 +0900564 NetworkType type = network.getNetworkType();
565
566 // TODO: we block a network traffic by referring to segment ID for now
567 // we might need to find a better way to block the traffic of a network
568 // in case the segment ID is overlapped in different types network (VXLAN, VLAN)
569 switch (type) {
570 case VXLAN:
571 setNetworkBlockRulesForVxlan(network.getProviderSegID(), install);
572 break;
573 case VLAN:
574 setNetworkBlockRulesForVlan(network.getProviderSegID(), install);
575 break;
576 case FLAT:
577 // TODO: need to find a way to block flat typed network
578 break;
579 default:
580 break;
Frank Wangf9571662017-06-06 18:01:29 +0800581 }
Jian Li91be8cd2018-07-22 00:44:46 +0900582 }
583
584 private void setNetworkBlockRulesForVxlan(String segmentId, boolean install) {
585 TrafficSelector selector = DefaultTrafficSelector.builder()
586 .matchTunnelId(Long.valueOf(segmentId))
587 .build();
Frank Wangf9571662017-06-06 18:01:29 +0800588
589 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
590 .drop()
591 .build();
592
Jian Li91be8cd2018-07-22 00:44:46 +0900593 osNodeService.completeNodes(COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900594 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800595 osFlowRuleService.setRule(
Jian Li91be8cd2018-07-22 00:44:46 +0900596 appId,
597 osNode.intgBridge(),
598 selector,
599 treatment,
600 PRIORITY_ADMIN_RULE,
601 ACL_TABLE,
602 install)
Jian Liea1b9662018-03-02 18:07:32 +0900603 );
Frank Wangf9571662017-06-06 18:01:29 +0800604 }
605
Jian Li91be8cd2018-07-22 00:44:46 +0900606 private void setNetworkBlockRulesForVlan(String segmentId, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800607 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li91be8cd2018-07-22 00:44:46 +0900608 .matchTunnelId(Long.valueOf(segmentId))
609 .build();
610
611 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
612 .drop()
613 .build();
614
615 osNodeService.completeNodes(COMPUTE)
616 .forEach(osNode ->
617 osFlowRuleService.setRule(
618 appId,
619 osNode.intgBridge(),
620 selector,
621 treatment,
622 PRIORITY_ADMIN_RULE,
623 ACL_TABLE,
624 install)
625 );
626 }
627
628 private void setPortBlockRules(InstancePort instPort, boolean install) {
629 TrafficSelector selector = DefaultTrafficSelector.builder()
630 .matchInPort(instPort.portNumber())
Frank Wangf9571662017-06-06 18:01:29 +0800631 .build();
632
633 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
634 .drop()
635 .build();
636
637 osFlowRuleService.setRule(
638 appId,
Jian Li91be8cd2018-07-22 00:44:46 +0900639 instPort.deviceId(),
Frank Wangf9571662017-06-06 18:01:29 +0800640 selector,
641 treatment,
642 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900643 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800644 install);
645 }
646
Jian Liea1b9662018-03-02 18:07:32 +0900647 /**
648 * Obtains the VLAN ID from the given instance port.
649 *
650 * @param instPort instance port object
651 * @return VLAN ID
652 */
daniel parka792cf72017-04-14 16:25:35 +0900653 private VlanId getVlanId(InstancePort instPort) {
654 Network osNet = osNetworkService.network(instPort.networkId());
655
656 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900657 final String error =
658 String.format(ERR_SET_FLOWS_VNI,
659 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900660 throw new IllegalStateException(error);
661 }
662
663 return VlanId.vlanId(osNet.getProviderSegID());
664 }
665
Jian Liea1b9662018-03-02 18:07:32 +0900666 /**
667 * Obtains the VNI from the given instance port.
668 *
669 * @param instPort instance port object
670 * @return VXLAN Network Identifier (VNI)
671 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 private Long getVni(InstancePort instPort) {
673 Network osNet = osNetworkService.network(instPort.networkId());
674 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900675 final String error =
676 String.format(ERR_SET_FLOWS_VNI,
677 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 throw new IllegalStateException(error);
679 }
680 return Long.valueOf(osNet.getProviderSegID());
681 }
682
Jian Li5c09e212018-10-24 18:23:58 +0900683 private String getArpMode() {
684 Set<ConfigProperty> properties = configService.getProperties(OpenstackSwitchingArpHandler.class.getName());
685 return getPropertyValue(properties, ARP_MODE);
686 }
687
Jian Liea1b9662018-03-02 18:07:32 +0900688 /**
689 * An internal instance port listener which listens the port events generated
690 * from VM. The corresponding L2 forwarding rules will be generated and
691 * inserted to integration bridge only if a new VM port is detected. If the
692 * existing detected VM port is removed due to VM purge, we will remove the
693 * corresponding L2 forwarding to as well for the sake of resource saving.
694 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900695 private class InternalInstancePortListener implements InstancePortListener {
696
697 @Override
698 public boolean isRelevant(InstancePortEvent event) {
699 InstancePort instPort = event.subject();
700 return mastershipService.isLocalMaster(instPort.deviceId());
701 }
702
703 @Override
704 public void event(InstancePortEvent event) {
705 InstancePort instPort = event.subject();
Jian Li91be8cd2018-07-22 00:44:46 +0900706 Port osPort = osNetworkService.port(instPort.portId());
Jian Li9a921b42018-06-18 02:44:50 +0900707
Hyunsun Moon44aac662017-02-18 02:07:01 +0900708 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900709 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900710 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900711 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900712 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900713 instPort.macAddress(),
714 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900715
716 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900717
Jian Li91be8cd2018-07-22 00:44:46 +0900718 if (osPort != null) {
719 eventExecutor.execute(() ->
720 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
721 }
722
Hyunsun Moon44aac662017-02-18 02:07:01 +0900723 break;
Jian Li46b74002018-07-15 18:39:08 +0900724 case OPENSTACK_INSTANCE_TERMINATED:
725 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
726 instPort.macAddress(),
727 instPort.ipAddress());
728 eventExecutor.execute(() -> removeVportRules(instPort));
729
730 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900731 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900732 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900733 instPort.macAddress(),
734 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900735
736 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900737
Jian Li91be8cd2018-07-22 00:44:46 +0900738 if (osPort != null) {
739 setPortBlockRules(instPort, false);
740 }
741
Hyunsun Moon44aac662017-02-18 02:07:01 +0900742 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900743 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
744 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
745 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900746 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900747
748 eventExecutor.execute(() -> instPortDetected(instPort));
749
Jian Li91be8cd2018-07-22 00:44:46 +0900750 if (osPort != null) {
751 eventExecutor.execute(() ->
752 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
753 }
754
Jian Liec5c32b2018-07-13 14:28:58 +0900755 break;
756 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
757 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
758 instPort.macAddress(),
759 instPort.ipAddress());
760
761 InstancePort revisedInstPort = swapStaleLocation(instPort);
762 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
763
Jian Li24ec59f2018-05-23 19:01:25 +0900764 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900765 default:
766 break;
767 }
768 }
769
770 private void instPortDetected(InstancePort instPort) {
771 setNetworkRules(instPort, true);
772 // TODO add something else if needed
773 }
774
775 private void instPortRemoved(InstancePort instPort) {
776 setNetworkRules(instPort, false);
777 // TODO add something else if needed
778 }
779 }
Jian Li91be8cd2018-07-22 00:44:46 +0900780
781 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
782
783 @Override
784 public boolean isRelevant(OpenstackNetworkEvent event) {
785
786 // do not allow to proceed without leadership
787 NodeId leader = leadershipService.getLeader(appId.name());
788 return Objects.equals(localNodeId, leader);
789 }
790
791 @Override
792 public void event(OpenstackNetworkEvent event) {
793
794 if (event.subject() == null || event.port() == null) {
795 return;
796 }
797
798 boolean isNwAdminStateUp = event.subject().isAdminStateUp();
799 boolean isPortAdminStateUp = event.port().isAdminStateUp();
800
801 InstancePort instPort = instancePortService.instancePort(event.port().getId());
802
803 switch (event.type()) {
804 case OPENSTACK_NETWORK_CREATED:
805 case OPENSTACK_NETWORK_UPDATED:
806 eventExecutor.execute(() ->
807 setNetworkBlockRules(event.subject(), !isNwAdminStateUp));
808
809 break;
810 case OPENSTACK_NETWORK_REMOVED:
811 eventExecutor.execute(() ->
812 setNetworkBlockRules(event.subject(), false));
813 break;
814 case OPENSTACK_PORT_CREATED:
815 case OPENSTACK_PORT_UPDATED:
816
817 if (instPort != null) {
818 eventExecutor.execute(() ->
819 setPortBlockRules(instPort, !isPortAdminStateUp));
820 }
821
822 break;
823 case OPENSTACK_PORT_REMOVED:
824
825 if (instPort != null) {
826 eventExecutor.execute(() ->
827 setPortBlockRules(instPort, false));
828 }
829
830 break;
831 default:
832 break;
833 }
834 }
835 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900836}