blob: e63444f0350de34b2496b10e31b599b81e975650 [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;
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
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900100 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900103 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900106 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li91be8cd2018-07-22 00:44:46 +0900109 protected DriverService driverService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected ClusterService clusterService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li5c09e212018-10-24 18:23:58 +0900115 protected ComponentConfigService configService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li91be8cd2018-07-22 00:44:46 +0900118 protected LeadershipService leadershipService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900121 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900124 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900127 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900130 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
sangho1aaa7882017-05-31 13:22:47 +0900132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900133 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900134
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 private final ExecutorService eventExecutor = newSingleThreadExecutor(
136 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
137 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Jian Li91be8cd2018-07-22 00:44:46 +0900138 private final InternalOpenstackNetworkListener osNetworkListener =
139 new InternalOpenstackNetworkListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140 private ApplicationId appId;
Jian Li91be8cd2018-07-22 00:44:46 +0900141 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142
143 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800144 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
Jian Li91be8cd2018-07-22 00:44:46 +0900146 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147 instancePortService.addListener(instancePortListener);
Jian Li91be8cd2018-07-22 00:44:46 +0900148 osNetworkService.addListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149
150 log.info("Started");
151 }
152
153 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800154 void deactivate() {
Jian Li91be8cd2018-07-22 00:44:46 +0900155 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 instancePortService.removeListener(instancePortListener);
157 eventExecutor.shutdown();
158
159 log.info("Stopped");
160 }
161
Jian Liea1b9662018-03-02 18:07:32 +0900162 /**
163 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900164 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900165 *
166 * @param instPort instance port object
167 * @param install install flag, add the rule if true, remove it otherwise
168 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900170 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
171 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900172 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900173 setTunnelTagIpFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900174 setForwardingRulesForVxlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900175
176 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
177 setTunnelTagArpFlowRules(instPort, install);
178 }
179
daniel parka792cf72017-04-14 16:25:35 +0900180 break;
181 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900182 setVlanTagIpFlowRules(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900183 setForwardingRulesForVlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900184
185 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
186 setVlanTagArpFlowRules(instPort, install);
187 }
188
daniel parka792cf72017-04-14 16:25:35 +0900189 break;
daniel park796c2eb2018-03-22 17:01:51 +0900190 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900191 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900192 setDownstreamRulesForFlat(instPort, install);
193 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900194 break;
daniel parka792cf72017-04-14 16:25:35 +0900195 default:
Jian Liea1b9662018-03-02 18:07:32 +0900196 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900197 break;
198 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 }
200
Jian Li24ec59f2018-05-23 19:01:25 +0900201 /**
202 * Removes virtual port.
203 *
204 * @param instPort instance port
205 */
206 private void removeVportRules(InstancePort instPort) {
207 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
208
209 switch (type) {
210 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900211 setTunnelTagIpFlowRules(instPort, false);
212
213 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
214 setTunnelTagArpFlowRules(instPort, false);
215 }
216
Jian Li24ec59f2018-05-23 19:01:25 +0900217 break;
218 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900219 setVlanTagIpFlowRules(instPort, false);
220
221 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
222 setVlanTagArpFlowRules(instPort, false);
223 }
224
Jian Li24ec59f2018-05-23 19:01:25 +0900225 break;
Jian Li9a921b42018-06-18 02:44:50 +0900226 case FLAT:
227 setFlatJumpRules(instPort, false);
228 setUpstreamRulesForFlat(instPort, false);
229 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700230 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900231 default:
Jian Li9a921b42018-06-18 02:44:50 +0900232 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900233 break;
234 }
235 }
236
Jian Li70a2c3f2018-04-13 17:26:31 +0900237 private void setFlatJumpRules(InstancePort port, boolean install) {
238 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
239 selector.matchInPort(port.portNumber());
240
241 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900242 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900243
244 osFlowRuleService.setRule(
245 appId,
246 port.deviceId(),
247 selector.build(),
248 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900249 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900250 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900251 install);
252
253 Network network = osNetworkService.network(port.networkId());
254
255 if (network == null) {
256 log.warn("The network does not exist");
257 return;
258 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900259 PortNumber portNumber = osNodeService.node(port.deviceId())
260 .phyIntfPortNum(network.getProviderPhyNet());
261
262 if (portNumber == null) {
263 log.warn("The port number does not exist");
264 return;
265 }
266
267 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900268 selector.matchInPort(portNumber)
269 .matchEthType(Ethernet.TYPE_IPV4)
270 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900271
272 osFlowRuleService.setRule(
273 appId,
274 port.deviceId(),
275 selector.build(),
276 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900277 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900278 DHCP_TABLE,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900279 install);
280
281 selector = DefaultTrafficSelector.builder();
282 selector.matchInPort(portNumber)
283 .matchEthType(Ethernet.TYPE_ARP)
284 .matchArpTpa(port.ipAddress().getIp4Address());
285
286 osFlowRuleService.setRule(
287 appId,
288 port.deviceId(),
289 selector.build(),
290 treatment.build(),
291 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900292 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900293 install);
294 }
295
Jian Li9a921b42018-06-18 02:44:50 +0900296 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900297 TrafficSelector selector = DefaultTrafficSelector.builder()
298 .matchEthType(Ethernet.TYPE_IPV4)
299 .matchIPDst(instPort.ipAddress().toIpPrefix())
300 .build();
301 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
302 .setOutput(instPort.portNumber())
303 .build();
304
305 osFlowRuleService.setRule(
306 appId,
307 instPort.deviceId(),
308 selector,
309 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900310 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900311 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900312 install);
313
314 selector = DefaultTrafficSelector.builder()
315 .matchEthType(Ethernet.TYPE_ARP)
316 .matchArpTpa(instPort.ipAddress().getIp4Address())
317 .build();
318
319 osFlowRuleService.setRule(
320 appId,
321 instPort.deviceId(),
322 selector,
323 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900324 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900325 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900326 install);
327 }
328
Jian Li9a921b42018-06-18 02:44:50 +0900329 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900330 TrafficSelector selector = DefaultTrafficSelector.builder()
331 .matchInPort(instPort.portNumber())
332 .build();
333
334 Network network = osNetworkService.network(instPort.networkId());
335
336 if (network == null) {
337 log.warn("The network does not exist");
338 return;
339 }
340
341 PortNumber portNumber = osNodeService.node(instPort.deviceId())
342 .phyIntfPortNum(network.getProviderPhyNet());
343
344 if (portNumber == null) {
345 log.warn("The port number does not exist");
346 return;
347 }
348
349 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
350 .setOutput(portNumber)
351 .build();
352
353 osFlowRuleService.setRule(
354 appId,
355 instPort.deviceId(),
356 selector,
357 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900358 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900359 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900360 install);
361 }
362
Jian Liea1b9662018-03-02 18:07:32 +0900363 /**
364 * Configures the flow rules which are used for L2 packet switching.
365 * Note that these rules will be inserted in switching table (table 5).
366 *
367 * @param instPort instance port object
368 * @param install install flag, add the rule if true, remove it otherwise
369 */
Jian Li9a921b42018-06-18 02:44:50 +0900370 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 // switching rules for the instPorts in the same node
372 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900373 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900374 .matchEthType(Ethernet.TYPE_IPV4)
375 .matchIPDst(instPort.ipAddress().toIpPrefix())
376 .matchTunnelId(getVni(instPort))
377 .build();
378
379 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900380 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900381 .setEthDst(instPort.macAddress())
382 .setOutput(instPort.portNumber())
383 .build();
384
sanghodc375372017-06-08 10:41:30 +0900385 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900386 appId,
387 instPort.deviceId(),
388 selector,
389 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900390 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900391 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900392 install);
393
394 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900395 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
396 if (localNode == null) {
397 final String error = String.format("Cannot find openstack node for %s",
398 instPort.deviceId());
399 throw new IllegalStateException(error);
400 }
401 osNodeService.completeNodes(COMPUTE).stream()
402 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
403 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900404 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
405 .extension(buildExtension(
406 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900407 remoteNode.intgBridge(),
408 localNode.dataIp().getIp4Address()),
409 remoteNode.intgBridge())
410 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900411 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900412
sanghodc375372017-06-08 10:41:30 +0900413 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900414 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900415 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900416 selector,
417 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900418 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900419 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900420 install);
421 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900422 }
423
Jian Liea1b9662018-03-02 18:07:32 +0900424 /**
425 * Configures the flow rules which are used for L2 VLAN packet switching.
426 * Note that these rules will be inserted in switching table (table 5).
427 *
428 * @param instPort instance port object
429 * @param install install flag, add the rule if true, remove it otherwise
430 */
daniel parka792cf72017-04-14 16:25:35 +0900431 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
432 // switching rules for the instPorts in the same node
433 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900434 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900435 .matchEthType(Ethernet.TYPE_IPV4)
436 .matchIPDst(instPort.ipAddress().toIpPrefix())
437 .matchVlanId(getVlanId(instPort))
438 .build();
439
440 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
441 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900442 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900443 .setEthDst(instPort.macAddress())
444 .setOutput(instPort.portNumber())
445 .build();
446
sanghodc375372017-06-08 10:41:30 +0900447 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900448 appId,
449 instPort.deviceId(),
450 selector,
451 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900452 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900453 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900454 install);
455
456 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900457 osNodeService.completeNodes(COMPUTE).stream()
458 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
459 remoteNode.vlanIntf() != null)
460 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900461 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900462 .setEthDst(instPort.macAddress())
463 .setOutput(remoteNode.vlanPortNum())
464 .build();
daniel parka792cf72017-04-14 16:25:35 +0900465
sanghodc375372017-06-08 10:41:30 +0900466 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900467 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900468 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900469 selector,
470 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900471 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900472 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900473 install);
474 });
daniel parka792cf72017-04-14 16:25:35 +0900475 }
476
Jian Li5c09e212018-10-24 18:23:58 +0900477 private void setTunnelTagArpFlowRules(InstancePort instPort, boolean install) {
478 setTunnelTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
479 }
480
481 private void setTunnelTagIpFlowRules(InstancePort instPort, boolean install) {
482 setTunnelTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
483 }
484
Jian Liea1b9662018-03-02 18:07:32 +0900485 /**
486 * Configures the flow rule which is for using VXLAN to tag the packet
487 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900488 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900489 *
490 * @param instPort instance port object
491 * @param install install flag, add the rule if true, remove it otherwise
492 */
Jian Li5c09e212018-10-24 18:23:58 +0900493 private void setTunnelTagFlowRules(InstancePort instPort,
494 short ethType,
495 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900496 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900497 .matchEthType(ethType)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900498 .matchInPort(instPort.portNumber())
499 .build();
500
Jian Li28ec77f2018-10-31 07:07:25 +0900501 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
502 .setTunnelId(getVni(instPort));
sangho1aaa7882017-05-31 13:22:47 +0900503
sanghoe6457a32017-08-24 14:31:19 +0900504
Jian Li28ec77f2018-10-31 07:07:25 +0900505 if (ethType == Ethernet.TYPE_ARP) {
506 tBuilder.transition(ARP_TABLE);
507 } else if (ethType == Ethernet.TYPE_IPV4) {
508 tBuilder.transition(ACL_TABLE);
sanghoe6457a32017-08-24 14:31:19 +0900509 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900510
sanghodc375372017-06-08 10:41:30 +0900511 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900512 appId,
513 instPort.deviceId(),
514 selector,
Jian Li28ec77f2018-10-31 07:07:25 +0900515 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900517 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900518 install);
519 }
520
Jian Li5c09e212018-10-24 18:23:58 +0900521 private void setVlanTagIpFlowRules(InstancePort instPort, boolean install) {
522 setVlanTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
523 }
524
525 private void setVlanTagArpFlowRules(InstancePort instPort, boolean install) {
526 setVlanTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
527 }
528
Jian Liea1b9662018-03-02 18:07:32 +0900529 /**
530 * Configures the flow rule which is for using VLAN to tag the packet
531 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900532 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900533 *
534 * @param instPort instance port object
535 * @param install install flag, add the rule if true, remove it otherwise
536 */
Jian Li5c09e212018-10-24 18:23:58 +0900537 private void setVlanTagFlowRules(InstancePort instPort,
538 short ethType,
539 boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900540 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900541 .matchEthType(ethType)
daniel parka792cf72017-04-14 16:25:35 +0900542 .matchInPort(instPort.portNumber())
543 .build();
544
545 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
546 .pushVlan()
547 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900548 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900549 .build();
550
sanghodc375372017-06-08 10:41:30 +0900551 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900552 appId,
553 instPort.deviceId(),
554 selector,
555 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900556 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900557 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900558 install);
daniel parka792cf72017-04-14 16:25:35 +0900559 }
560
Jian Li91be8cd2018-07-22 00:44:46 +0900561 private void setNetworkBlockRules(Network network, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800562
Jian Li91be8cd2018-07-22 00:44:46 +0900563 NetworkType type = network.getNetworkType();
564
565 // TODO: we block a network traffic by referring to segment ID for now
566 // we might need to find a better way to block the traffic of a network
567 // in case the segment ID is overlapped in different types network (VXLAN, VLAN)
568 switch (type) {
569 case VXLAN:
570 setNetworkBlockRulesForVxlan(network.getProviderSegID(), install);
571 break;
572 case VLAN:
573 setNetworkBlockRulesForVlan(network.getProviderSegID(), install);
574 break;
575 case FLAT:
576 // TODO: need to find a way to block flat typed network
577 break;
578 default:
579 break;
Frank Wangf9571662017-06-06 18:01:29 +0800580 }
Jian Li91be8cd2018-07-22 00:44:46 +0900581 }
582
583 private void setNetworkBlockRulesForVxlan(String segmentId, boolean install) {
584 TrafficSelector selector = DefaultTrafficSelector.builder()
585 .matchTunnelId(Long.valueOf(segmentId))
586 .build();
Frank Wangf9571662017-06-06 18:01:29 +0800587
588 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
589 .drop()
590 .build();
591
Jian Li91be8cd2018-07-22 00:44:46 +0900592 osNodeService.completeNodes(COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900593 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800594 osFlowRuleService.setRule(
Jian Li91be8cd2018-07-22 00:44:46 +0900595 appId,
596 osNode.intgBridge(),
597 selector,
598 treatment,
599 PRIORITY_ADMIN_RULE,
600 ACL_TABLE,
601 install)
Jian Liea1b9662018-03-02 18:07:32 +0900602 );
Frank Wangf9571662017-06-06 18:01:29 +0800603 }
604
Jian Li91be8cd2018-07-22 00:44:46 +0900605 private void setNetworkBlockRulesForVlan(String segmentId, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800606 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li91be8cd2018-07-22 00:44:46 +0900607 .matchTunnelId(Long.valueOf(segmentId))
608 .build();
609
610 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
611 .drop()
612 .build();
613
614 osNodeService.completeNodes(COMPUTE)
615 .forEach(osNode ->
616 osFlowRuleService.setRule(
617 appId,
618 osNode.intgBridge(),
619 selector,
620 treatment,
621 PRIORITY_ADMIN_RULE,
622 ACL_TABLE,
623 install)
624 );
625 }
626
627 private void setPortBlockRules(InstancePort instPort, boolean install) {
628 TrafficSelector selector = DefaultTrafficSelector.builder()
629 .matchInPort(instPort.portNumber())
Frank Wangf9571662017-06-06 18:01:29 +0800630 .build();
631
632 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
633 .drop()
634 .build();
635
636 osFlowRuleService.setRule(
637 appId,
Jian Li91be8cd2018-07-22 00:44:46 +0900638 instPort.deviceId(),
Frank Wangf9571662017-06-06 18:01:29 +0800639 selector,
640 treatment,
641 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900642 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800643 install);
644 }
645
Jian Liea1b9662018-03-02 18:07:32 +0900646 /**
647 * Obtains the VLAN ID from the given instance port.
648 *
649 * @param instPort instance port object
650 * @return VLAN ID
651 */
daniel parka792cf72017-04-14 16:25:35 +0900652 private VlanId getVlanId(InstancePort instPort) {
653 Network osNet = osNetworkService.network(instPort.networkId());
654
655 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900656 final String error =
657 String.format(ERR_SET_FLOWS_VNI,
658 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900659 throw new IllegalStateException(error);
660 }
661
662 return VlanId.vlanId(osNet.getProviderSegID());
663 }
664
Jian Liea1b9662018-03-02 18:07:32 +0900665 /**
666 * Obtains the VNI from the given instance port.
667 *
668 * @param instPort instance port object
669 * @return VXLAN Network Identifier (VNI)
670 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900671 private Long getVni(InstancePort instPort) {
672 Network osNet = osNetworkService.network(instPort.networkId());
673 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900674 final String error =
675 String.format(ERR_SET_FLOWS_VNI,
676 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900677 throw new IllegalStateException(error);
678 }
679 return Long.valueOf(osNet.getProviderSegID());
680 }
681
Jian Li5c09e212018-10-24 18:23:58 +0900682 private String getArpMode() {
683 Set<ConfigProperty> properties = configService.getProperties(OpenstackSwitchingArpHandler.class.getName());
684 return getPropertyValue(properties, ARP_MODE);
685 }
686
Jian Liea1b9662018-03-02 18:07:32 +0900687 /**
688 * An internal instance port listener which listens the port events generated
689 * from VM. The corresponding L2 forwarding rules will be generated and
690 * inserted to integration bridge only if a new VM port is detected. If the
691 * existing detected VM port is removed due to VM purge, we will remove the
692 * corresponding L2 forwarding to as well for the sake of resource saving.
693 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900694 private class InternalInstancePortListener implements InstancePortListener {
695
696 @Override
697 public boolean isRelevant(InstancePortEvent event) {
698 InstancePort instPort = event.subject();
699 return mastershipService.isLocalMaster(instPort.deviceId());
700 }
701
702 @Override
703 public void event(InstancePortEvent event) {
704 InstancePort instPort = event.subject();
Jian Li91be8cd2018-07-22 00:44:46 +0900705 Port osPort = osNetworkService.port(instPort.portId());
Jian Li9a921b42018-06-18 02:44:50 +0900706
Hyunsun Moon44aac662017-02-18 02:07:01 +0900707 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900708 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900709 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900710 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900711 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900712 instPort.macAddress(),
713 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900714
715 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900716
Jian Li91be8cd2018-07-22 00:44:46 +0900717 if (osPort != null) {
718 eventExecutor.execute(() ->
719 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
720 }
721
Hyunsun Moon44aac662017-02-18 02:07:01 +0900722 break;
Jian Li46b74002018-07-15 18:39:08 +0900723 case OPENSTACK_INSTANCE_TERMINATED:
724 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
725 instPort.macAddress(),
726 instPort.ipAddress());
727 eventExecutor.execute(() -> removeVportRules(instPort));
728
729 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900730 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900731 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900732 instPort.macAddress(),
733 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900734
735 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900736
Jian Li91be8cd2018-07-22 00:44:46 +0900737 if (osPort != null) {
738 setPortBlockRules(instPort, false);
739 }
740
Hyunsun Moon44aac662017-02-18 02:07:01 +0900741 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900742 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
743 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
744 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900745 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900746
747 eventExecutor.execute(() -> instPortDetected(instPort));
748
Jian Li91be8cd2018-07-22 00:44:46 +0900749 if (osPort != null) {
750 eventExecutor.execute(() ->
751 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
752 }
753
Jian Liec5c32b2018-07-13 14:28:58 +0900754 break;
755 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
756 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
757 instPort.macAddress(),
758 instPort.ipAddress());
759
760 InstancePort revisedInstPort = swapStaleLocation(instPort);
761 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
762
Jian Li24ec59f2018-05-23 19:01:25 +0900763 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900764 default:
765 break;
766 }
767 }
768
769 private void instPortDetected(InstancePort instPort) {
770 setNetworkRules(instPort, true);
771 // TODO add something else if needed
772 }
773
774 private void instPortRemoved(InstancePort instPort) {
775 setNetworkRules(instPort, false);
776 // TODO add something else if needed
777 }
778 }
Jian Li91be8cd2018-07-22 00:44:46 +0900779
780 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
781
782 @Override
783 public boolean isRelevant(OpenstackNetworkEvent event) {
784
785 // do not allow to proceed without leadership
786 NodeId leader = leadershipService.getLeader(appId.name());
787 return Objects.equals(localNodeId, leader);
788 }
789
790 @Override
791 public void event(OpenstackNetworkEvent event) {
792
793 if (event.subject() == null || event.port() == null) {
794 return;
795 }
796
797 boolean isNwAdminStateUp = event.subject().isAdminStateUp();
798 boolean isPortAdminStateUp = event.port().isAdminStateUp();
799
800 InstancePort instPort = instancePortService.instancePort(event.port().getId());
801
802 switch (event.type()) {
803 case OPENSTACK_NETWORK_CREATED:
804 case OPENSTACK_NETWORK_UPDATED:
805 eventExecutor.execute(() ->
806 setNetworkBlockRules(event.subject(), !isNwAdminStateUp));
807
808 break;
809 case OPENSTACK_NETWORK_REMOVED:
810 eventExecutor.execute(() ->
811 setNetworkBlockRules(event.subject(), false));
812 break;
813 case OPENSTACK_PORT_CREATED:
814 case OPENSTACK_PORT_UPDATED:
815
816 if (instPort != null) {
817 eventExecutor.execute(() ->
818 setPortBlockRules(instPort, !isPortAdminStateUp));
819 }
820
821 break;
822 case OPENSTACK_PORT_REMOVED:
823
824 if (instPort != null) {
825 eventExecutor.execute(() ->
826 setPortBlockRules(instPort, false));
827 }
828
829 break;
830 default:
831 break;
832 }
833 }
834 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900835}