blob: 47fad9d0366aff95cd3ae60cdaa48d58013b6b25 [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;
Hyunsun Moon0d457362017-06-27 17:19:41 +090050import org.onosproject.openstacknode.api.OpenstackNode;
51import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.openstack4j.model.network.Network;
Frank Wangf9571662017-06-06 18:01:29 +080053import org.openstack4j.model.network.NetworkType;
54import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.slf4j.Logger;
56
Jian Li91be8cd2018-07-22 00:44:46 +090057import java.util.Objects;
Jian Li5c09e212018-10-24 18:23:58 +090058import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import java.util.concurrent.ExecutorService;
60
61import static java.util.concurrent.Executors.newSingleThreadExecutor;
62import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090063import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
Jian Li5c09e212018-10-24 18:23:58 +090064import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
65import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
66import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090067import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
sanghodc375372017-06-08 10:41:30 +090068import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
69import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080070import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Daniel Parkd1b14d32018-06-12 16:10:28 +090071import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_DOWNSTREAM_RULE;
72import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE;
73import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
74import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_UPSTREAM_RULE;
sanghodc375372017-06-08 10:41:30 +090075import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
76import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li960ae512018-07-03 22:50:56 +090077import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090078import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Li5c09e212018-10-24 18:23:58 +090079import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090080import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090081import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090082import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083import static org.slf4j.LoggerFactory.getLogger;
84
85
86/**
87 * Populates switching flow rules on OVS for the basic connectivity among the
88 * virtual instances in the same network.
89 */
90@Component(immediate = true)
91public final class OpenstackSwitchingHandler {
92
93 private final Logger log = getLogger(getClass());
94
Jian Li5c09e212018-10-24 18:23:58 +090095 private static final String ARP_MODE = "arpMode";
Jian Li71670d12018-03-02 21:31:07 +090096 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 +090097
Ray Milkeyd84f89b2018-08-17 14:54:17 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +090099 protected CoreService coreService;
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 MastershipService mastershipService;
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 DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900108 protected DriverService driverService;
109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900111 protected ClusterService clusterService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li5c09e212018-10-24 18:23:58 +0900114 protected ComponentConfigService configService;
115
Ray Milkey956bb162018-10-26 10:53:44 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
117
Jian Li91be8cd2018-07-22 00:44:46 +0900118 protected LeadershipService leadershipService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900121 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900124 protected InstancePortService instancePortService;
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 OpenstackNetworkService osNetworkService;
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 OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
132 private final ExecutorService eventExecutor = newSingleThreadExecutor(
133 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
134 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Jian Li91be8cd2018-07-22 00:44:46 +0900135 private final InternalOpenstackNetworkListener osNetworkListener =
136 new InternalOpenstackNetworkListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 private ApplicationId appId;
Jian Li91be8cd2018-07-22 00:44:46 +0900138 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139
140 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800141 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
Jian Li91be8cd2018-07-22 00:44:46 +0900143 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 instancePortService.addListener(instancePortListener);
Jian Li91be8cd2018-07-22 00:44:46 +0900145 osNetworkService.addListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146
147 log.info("Started");
148 }
149
150 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800151 void deactivate() {
Jian Li91be8cd2018-07-22 00:44:46 +0900152 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900153 instancePortService.removeListener(instancePortListener);
154 eventExecutor.shutdown();
155
156 log.info("Stopped");
157 }
158
Jian Liea1b9662018-03-02 18:07:32 +0900159 /**
160 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900161 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900162 *
163 * @param instPort instance port object
164 * @param install install flag, add the rule if true, remove it otherwise
165 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900167 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
168 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900169 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900170 setTunnelTagIpFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900171 setForwardingRulesForVxlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900172
173 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
174 setTunnelTagArpFlowRules(instPort, install);
175 }
176
daniel parka792cf72017-04-14 16:25:35 +0900177 break;
178 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900179 setVlanTagIpFlowRules(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900180 setForwardingRulesForVlan(instPort, install);
Jian Li5c09e212018-10-24 18:23:58 +0900181
182 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
183 setVlanTagArpFlowRules(instPort, install);
184 }
185
daniel parka792cf72017-04-14 16:25:35 +0900186 break;
daniel park796c2eb2018-03-22 17:01:51 +0900187 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900188 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900189 setDownstreamRulesForFlat(instPort, install);
190 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900191 break;
daniel parka792cf72017-04-14 16:25:35 +0900192 default:
Jian Liea1b9662018-03-02 18:07:32 +0900193 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900194 break;
195 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900196 }
197
Jian Li24ec59f2018-05-23 19:01:25 +0900198 /**
199 * Removes virtual port.
200 *
201 * @param instPort instance port
202 */
203 private void removeVportRules(InstancePort instPort) {
204 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
205
206 switch (type) {
207 case VXLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900208 setTunnelTagIpFlowRules(instPort, false);
209
210 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
211 setTunnelTagArpFlowRules(instPort, false);
212 }
213
Jian Li24ec59f2018-05-23 19:01:25 +0900214 break;
215 case VLAN:
Jian Li5c09e212018-10-24 18:23:58 +0900216 setVlanTagIpFlowRules(instPort, false);
217
218 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
219 setVlanTagArpFlowRules(instPort, false);
220 }
221
Jian Li24ec59f2018-05-23 19:01:25 +0900222 break;
Jian Li9a921b42018-06-18 02:44:50 +0900223 case FLAT:
224 setFlatJumpRules(instPort, false);
225 setUpstreamRulesForFlat(instPort, false);
226 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700227 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900228 default:
Jian Li9a921b42018-06-18 02:44:50 +0900229 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900230 break;
231 }
232 }
233
Jian Li70a2c3f2018-04-13 17:26:31 +0900234 private void setFlatJumpRules(InstancePort port, boolean install) {
235 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
236 selector.matchInPort(port.portNumber());
237
238 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900239 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900240
241 osFlowRuleService.setRule(
242 appId,
243 port.deviceId(),
244 selector.build(),
245 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900246 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900247 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900248 install);
249
250 Network network = osNetworkService.network(port.networkId());
251
252 if (network == null) {
253 log.warn("The network does not exist");
254 return;
255 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900256 PortNumber portNumber = osNodeService.node(port.deviceId())
257 .phyIntfPortNum(network.getProviderPhyNet());
258
259 if (portNumber == null) {
260 log.warn("The port number does not exist");
261 return;
262 }
263
264 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900265 selector.matchInPort(portNumber)
266 .matchEthType(Ethernet.TYPE_IPV4)
267 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900268
269 osFlowRuleService.setRule(
270 appId,
271 port.deviceId(),
272 selector.build(),
273 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900274 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900275 DHCP_TABLE,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900276 install);
277
278 selector = DefaultTrafficSelector.builder();
279 selector.matchInPort(portNumber)
280 .matchEthType(Ethernet.TYPE_ARP)
281 .matchArpTpa(port.ipAddress().getIp4Address());
282
283 osFlowRuleService.setRule(
284 appId,
285 port.deviceId(),
286 selector.build(),
287 treatment.build(),
288 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900289 DHCP_TABLE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900290 install);
291 }
292
Jian Li9a921b42018-06-18 02:44:50 +0900293 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900294 TrafficSelector selector = DefaultTrafficSelector.builder()
295 .matchEthType(Ethernet.TYPE_IPV4)
296 .matchIPDst(instPort.ipAddress().toIpPrefix())
297 .build();
298 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
299 .setOutput(instPort.portNumber())
300 .build();
301
302 osFlowRuleService.setRule(
303 appId,
304 instPort.deviceId(),
305 selector,
306 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900307 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900308 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900309 install);
310
311 selector = DefaultTrafficSelector.builder()
312 .matchEthType(Ethernet.TYPE_ARP)
313 .matchArpTpa(instPort.ipAddress().getIp4Address())
314 .build();
315
316 osFlowRuleService.setRule(
317 appId,
318 instPort.deviceId(),
319 selector,
320 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900321 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900322 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900323 install);
324 }
325
Jian Li9a921b42018-06-18 02:44:50 +0900326 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900327 TrafficSelector selector = DefaultTrafficSelector.builder()
328 .matchInPort(instPort.portNumber())
329 .build();
330
331 Network network = osNetworkService.network(instPort.networkId());
332
333 if (network == null) {
334 log.warn("The network does not exist");
335 return;
336 }
337
338 PortNumber portNumber = osNodeService.node(instPort.deviceId())
339 .phyIntfPortNum(network.getProviderPhyNet());
340
341 if (portNumber == null) {
342 log.warn("The port number does not exist");
343 return;
344 }
345
346 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
347 .setOutput(portNumber)
348 .build();
349
350 osFlowRuleService.setRule(
351 appId,
352 instPort.deviceId(),
353 selector,
354 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900355 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900356 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900357 install);
358 }
359
Jian Liea1b9662018-03-02 18:07:32 +0900360 /**
361 * Configures the flow rules which are used for L2 packet switching.
362 * Note that these rules will be inserted in switching table (table 5).
363 *
364 * @param instPort instance port object
365 * @param install install flag, add the rule if true, remove it otherwise
366 */
Jian Li9a921b42018-06-18 02:44:50 +0900367 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900368 // switching rules for the instPorts in the same node
369 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900370 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 .matchEthType(Ethernet.TYPE_IPV4)
372 .matchIPDst(instPort.ipAddress().toIpPrefix())
373 .matchTunnelId(getVni(instPort))
374 .build();
375
376 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900377 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900378 .setEthDst(instPort.macAddress())
379 .setOutput(instPort.portNumber())
380 .build();
381
sanghodc375372017-06-08 10:41:30 +0900382 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900383 appId,
384 instPort.deviceId(),
385 selector,
386 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900387 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900388 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 install);
390
391 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900392 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
393 if (localNode == null) {
394 final String error = String.format("Cannot find openstack node for %s",
395 instPort.deviceId());
396 throw new IllegalStateException(error);
397 }
398 osNodeService.completeNodes(COMPUTE).stream()
399 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
400 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900401 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
402 .extension(buildExtension(
403 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900404 remoteNode.intgBridge(),
405 localNode.dataIp().getIp4Address()),
406 remoteNode.intgBridge())
407 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900408 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900409
sanghodc375372017-06-08 10:41:30 +0900410 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900411 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900412 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900413 selector,
414 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900415 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900416 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900417 install);
418 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900419 }
420
Jian Liea1b9662018-03-02 18:07:32 +0900421 /**
422 * Configures the flow rules which are used for L2 VLAN packet switching.
423 * Note that these rules will be inserted in switching table (table 5).
424 *
425 * @param instPort instance port object
426 * @param install install flag, add the rule if true, remove it otherwise
427 */
daniel parka792cf72017-04-14 16:25:35 +0900428 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
429 // switching rules for the instPorts in the same node
430 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900431 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900432 .matchEthType(Ethernet.TYPE_IPV4)
433 .matchIPDst(instPort.ipAddress().toIpPrefix())
434 .matchVlanId(getVlanId(instPort))
435 .build();
436
437 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
438 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900439 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900440 .setEthDst(instPort.macAddress())
441 .setOutput(instPort.portNumber())
442 .build();
443
sanghodc375372017-06-08 10:41:30 +0900444 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900445 appId,
446 instPort.deviceId(),
447 selector,
448 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900449 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900450 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900451 install);
452
453 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900454 osNodeService.completeNodes(COMPUTE).stream()
455 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
456 remoteNode.vlanIntf() != null)
457 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900458 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900459 .setEthDst(instPort.macAddress())
460 .setOutput(remoteNode.vlanPortNum())
461 .build();
daniel parka792cf72017-04-14 16:25:35 +0900462
sanghodc375372017-06-08 10:41:30 +0900463 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900464 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900465 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900466 selector,
467 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900468 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900469 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900470 install);
471 });
daniel parka792cf72017-04-14 16:25:35 +0900472 }
473
Jian Li5c09e212018-10-24 18:23:58 +0900474 private void setTunnelTagArpFlowRules(InstancePort instPort, boolean install) {
475 setTunnelTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
476 }
477
478 private void setTunnelTagIpFlowRules(InstancePort instPort, boolean install) {
479 setTunnelTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
480 }
481
Jian Liea1b9662018-03-02 18:07:32 +0900482 /**
483 * Configures the flow rule which is for using VXLAN to tag the packet
484 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900485 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900486 *
487 * @param instPort instance port object
488 * @param install install flag, add the rule if true, remove it otherwise
489 */
Jian Li5c09e212018-10-24 18:23:58 +0900490 private void setTunnelTagFlowRules(InstancePort instPort,
491 short ethType,
492 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900493 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900494 .matchEthType(ethType)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900495 .matchInPort(instPort.portNumber())
496 .build();
497
Jian Li28ec77f2018-10-31 07:07:25 +0900498 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
499 .setTunnelId(getVni(instPort));
sangho1aaa7882017-05-31 13:22:47 +0900500
sanghoe6457a32017-08-24 14:31:19 +0900501
Jian Li28ec77f2018-10-31 07:07:25 +0900502 if (ethType == Ethernet.TYPE_ARP) {
503 tBuilder.transition(ARP_TABLE);
504 } else if (ethType == Ethernet.TYPE_IPV4) {
505 tBuilder.transition(ACL_TABLE);
sanghoe6457a32017-08-24 14:31:19 +0900506 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900507
sanghodc375372017-06-08 10:41:30 +0900508 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900509 appId,
510 instPort.deviceId(),
511 selector,
Jian Li28ec77f2018-10-31 07:07:25 +0900512 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900513 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900514 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900515 install);
516 }
517
Jian Li5c09e212018-10-24 18:23:58 +0900518 private void setVlanTagIpFlowRules(InstancePort instPort, boolean install) {
519 setVlanTagFlowRules(instPort, Ethernet.TYPE_IPV4, install);
520 }
521
522 private void setVlanTagArpFlowRules(InstancePort instPort, boolean install) {
523 setVlanTagFlowRules(instPort, Ethernet.TYPE_ARP, install);
524 }
525
Jian Liea1b9662018-03-02 18:07:32 +0900526 /**
527 * Configures the flow rule which is for using VLAN to tag the packet
528 * based on the in_port number of a virtual instance.
Jian Li5c09e212018-10-24 18:23:58 +0900529 * Note that this rule will be inserted in vTag table.
Jian Liea1b9662018-03-02 18:07:32 +0900530 *
531 * @param instPort instance port object
532 * @param install install flag, add the rule if true, remove it otherwise
533 */
Jian Li5c09e212018-10-24 18:23:58 +0900534 private void setVlanTagFlowRules(InstancePort instPort,
535 short ethType,
536 boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900537 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li5c09e212018-10-24 18:23:58 +0900538 .matchEthType(ethType)
daniel parka792cf72017-04-14 16:25:35 +0900539 .matchInPort(instPort.portNumber())
540 .build();
541
542 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
543 .pushVlan()
544 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900545 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900546 .build();
547
sanghodc375372017-06-08 10:41:30 +0900548 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900549 appId,
550 instPort.deviceId(),
551 selector,
552 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900553 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900554 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900555 install);
daniel parka792cf72017-04-14 16:25:35 +0900556 }
557
Jian Li91be8cd2018-07-22 00:44:46 +0900558 private void setNetworkBlockRules(Network network, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800559
Jian Li91be8cd2018-07-22 00:44:46 +0900560 NetworkType type = network.getNetworkType();
561
562 // TODO: we block a network traffic by referring to segment ID for now
563 // we might need to find a better way to block the traffic of a network
564 // in case the segment ID is overlapped in different types network (VXLAN, VLAN)
565 switch (type) {
566 case VXLAN:
567 setNetworkBlockRulesForVxlan(network.getProviderSegID(), install);
568 break;
569 case VLAN:
570 setNetworkBlockRulesForVlan(network.getProviderSegID(), install);
571 break;
572 case FLAT:
573 // TODO: need to find a way to block flat typed network
574 break;
575 default:
576 break;
Frank Wangf9571662017-06-06 18:01:29 +0800577 }
Jian Li91be8cd2018-07-22 00:44:46 +0900578 }
579
580 private void setNetworkBlockRulesForVxlan(String segmentId, boolean install) {
581 TrafficSelector selector = DefaultTrafficSelector.builder()
582 .matchTunnelId(Long.valueOf(segmentId))
583 .build();
Frank Wangf9571662017-06-06 18:01:29 +0800584
585 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
586 .drop()
587 .build();
588
Jian Li91be8cd2018-07-22 00:44:46 +0900589 osNodeService.completeNodes(COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900590 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800591 osFlowRuleService.setRule(
Jian Li91be8cd2018-07-22 00:44:46 +0900592 appId,
593 osNode.intgBridge(),
594 selector,
595 treatment,
596 PRIORITY_ADMIN_RULE,
597 ACL_TABLE,
598 install)
Jian Liea1b9662018-03-02 18:07:32 +0900599 );
Frank Wangf9571662017-06-06 18:01:29 +0800600 }
601
Jian Li91be8cd2018-07-22 00:44:46 +0900602 private void setNetworkBlockRulesForVlan(String segmentId, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800603 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li91be8cd2018-07-22 00:44:46 +0900604 .matchTunnelId(Long.valueOf(segmentId))
605 .build();
606
607 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
608 .drop()
609 .build();
610
611 osNodeService.completeNodes(COMPUTE)
612 .forEach(osNode ->
613 osFlowRuleService.setRule(
614 appId,
615 osNode.intgBridge(),
616 selector,
617 treatment,
618 PRIORITY_ADMIN_RULE,
619 ACL_TABLE,
620 install)
621 );
622 }
623
624 private void setPortBlockRules(InstancePort instPort, boolean install) {
625 TrafficSelector selector = DefaultTrafficSelector.builder()
626 .matchInPort(instPort.portNumber())
Frank Wangf9571662017-06-06 18:01:29 +0800627 .build();
628
629 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
630 .drop()
631 .build();
632
633 osFlowRuleService.setRule(
634 appId,
Jian Li91be8cd2018-07-22 00:44:46 +0900635 instPort.deviceId(),
Frank Wangf9571662017-06-06 18:01:29 +0800636 selector,
637 treatment,
638 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900639 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800640 install);
641 }
642
Jian Liea1b9662018-03-02 18:07:32 +0900643 /**
644 * Obtains the VLAN ID from the given instance port.
645 *
646 * @param instPort instance port object
647 * @return VLAN ID
648 */
daniel parka792cf72017-04-14 16:25:35 +0900649 private VlanId getVlanId(InstancePort instPort) {
650 Network osNet = osNetworkService.network(instPort.networkId());
651
652 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900653 final String error =
654 String.format(ERR_SET_FLOWS_VNI,
655 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900656 throw new IllegalStateException(error);
657 }
658
659 return VlanId.vlanId(osNet.getProviderSegID());
660 }
661
Jian Liea1b9662018-03-02 18:07:32 +0900662 /**
663 * Obtains the VNI from the given instance port.
664 *
665 * @param instPort instance port object
666 * @return VXLAN Network Identifier (VNI)
667 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900668 private Long getVni(InstancePort instPort) {
669 Network osNet = osNetworkService.network(instPort.networkId());
670 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900671 final String error =
672 String.format(ERR_SET_FLOWS_VNI,
673 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900674 throw new IllegalStateException(error);
675 }
676 return Long.valueOf(osNet.getProviderSegID());
677 }
678
Jian Li5c09e212018-10-24 18:23:58 +0900679 private String getArpMode() {
680 Set<ConfigProperty> properties = configService.getProperties(OpenstackSwitchingArpHandler.class.getName());
681 return getPropertyValue(properties, ARP_MODE);
682 }
683
Jian Liea1b9662018-03-02 18:07:32 +0900684 /**
685 * An internal instance port listener which listens the port events generated
686 * from VM. The corresponding L2 forwarding rules will be generated and
687 * inserted to integration bridge only if a new VM port is detected. If the
688 * existing detected VM port is removed due to VM purge, we will remove the
689 * corresponding L2 forwarding to as well for the sake of resource saving.
690 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900691 private class InternalInstancePortListener implements InstancePortListener {
692
693 @Override
694 public boolean isRelevant(InstancePortEvent event) {
695 InstancePort instPort = event.subject();
696 return mastershipService.isLocalMaster(instPort.deviceId());
697 }
698
699 @Override
700 public void event(InstancePortEvent event) {
701 InstancePort instPort = event.subject();
Jian Li91be8cd2018-07-22 00:44:46 +0900702 Port osPort = osNetworkService.port(instPort.portId());
Jian Li9a921b42018-06-18 02:44:50 +0900703
Hyunsun Moon44aac662017-02-18 02:07:01 +0900704 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900705 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900706 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900707 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900708 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900709 instPort.macAddress(),
710 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900711
712 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900713
Jian Li91be8cd2018-07-22 00:44:46 +0900714 if (osPort != null) {
715 eventExecutor.execute(() ->
716 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
717 }
718
Hyunsun Moon44aac662017-02-18 02:07:01 +0900719 break;
Jian Li46b74002018-07-15 18:39:08 +0900720 case OPENSTACK_INSTANCE_TERMINATED:
721 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
722 instPort.macAddress(),
723 instPort.ipAddress());
724 eventExecutor.execute(() -> removeVportRules(instPort));
725
726 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900727 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900728 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900729 instPort.macAddress(),
730 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900731
732 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900733
Jian Li91be8cd2018-07-22 00:44:46 +0900734 if (osPort != null) {
735 setPortBlockRules(instPort, false);
736 }
737
Hyunsun Moon44aac662017-02-18 02:07:01 +0900738 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900739 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
740 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
741 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900742 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900743
744 eventExecutor.execute(() -> instPortDetected(instPort));
745
Jian Li91be8cd2018-07-22 00:44:46 +0900746 if (osPort != null) {
747 eventExecutor.execute(() ->
748 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
749 }
750
Jian Liec5c32b2018-07-13 14:28:58 +0900751 break;
752 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
753 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
754 instPort.macAddress(),
755 instPort.ipAddress());
756
757 InstancePort revisedInstPort = swapStaleLocation(instPort);
758 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
759
Jian Li24ec59f2018-05-23 19:01:25 +0900760 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 default:
762 break;
763 }
764 }
765
766 private void instPortDetected(InstancePort instPort) {
767 setNetworkRules(instPort, true);
768 // TODO add something else if needed
769 }
770
771 private void instPortRemoved(InstancePort instPort) {
772 setNetworkRules(instPort, false);
773 // TODO add something else if needed
774 }
775 }
Jian Li91be8cd2018-07-22 00:44:46 +0900776
777 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
778
779 @Override
780 public boolean isRelevant(OpenstackNetworkEvent event) {
781
782 // do not allow to proceed without leadership
783 NodeId leader = leadershipService.getLeader(appId.name());
784 return Objects.equals(localNodeId, leader);
785 }
786
787 @Override
788 public void event(OpenstackNetworkEvent event) {
789
790 if (event.subject() == null || event.port() == null) {
791 return;
792 }
793
794 boolean isNwAdminStateUp = event.subject().isAdminStateUp();
795 boolean isPortAdminStateUp = event.port().isAdminStateUp();
796
Jian Li32b03622018-11-06 17:54:24 +0900797 String portId = event.port().getId();
Jian Li91be8cd2018-07-22 00:44:46 +0900798
799 switch (event.type()) {
800 case OPENSTACK_NETWORK_CREATED:
801 case OPENSTACK_NETWORK_UPDATED:
802 eventExecutor.execute(() ->
803 setNetworkBlockRules(event.subject(), !isNwAdminStateUp));
804
805 break;
806 case OPENSTACK_NETWORK_REMOVED:
807 eventExecutor.execute(() ->
808 setNetworkBlockRules(event.subject(), false));
809 break;
810 case OPENSTACK_PORT_CREATED:
811 case OPENSTACK_PORT_UPDATED:
Jian Li32b03622018-11-06 17:54:24 +0900812 eventExecutor.execute(() -> {
813 InstancePort instPort = instancePortService.instancePort(portId);
814 if (instPort != null) {
815 setPortBlockRules(instPort, !isPortAdminStateUp);
816 }
817 });
Jian Li91be8cd2018-07-22 00:44:46 +0900818 break;
819 case OPENSTACK_PORT_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +0900820 eventExecutor.execute(() -> {
821 InstancePort instPort = instancePortService.instancePort(portId);
822 if (instPort != null) {
823 setPortBlockRules(instPort, false);
824 }
825 });
Jian Li91be8cd2018-07-22 00:44:46 +0900826 break;
827 default:
828 break;
829 }
830 }
831 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900832}