blob: 3ac981a6271b6226500ea5943e04062a31315b6c [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 Li91be8cd2018-07-22 00:44:46 +090027import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.LeadershipService;
29import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.mastership.MastershipService;
daniel park796c2eb2018-03-22 17:01:51 +090033import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.net.device.DeviceService;
sangho1aaa7882017-05-31 13:22:47 +090035import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
sangho1aaa7882017-05-31 13:22:47 +090040import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.openstacknetworking.api.InstancePort;
42import org.onosproject.openstacknetworking.api.InstancePortEvent;
43import org.onosproject.openstacknetworking.api.InstancePortListener;
44import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090045import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Li91be8cd2018-07-22 00:44:46 +090046import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
47import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghoe6457a32017-08-24 14:31:19 +090049import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090050import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
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;
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 Li70a2c3f2018-04-13 17:26:31 +090064import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
65import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
sanghodc375372017-06-08 10:41:30 +090066import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
67import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080068import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Daniel Parkd1b14d32018-06-12 16:10:28 +090069import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_DOWNSTREAM_RULE;
70import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE;
71import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
72import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_UPSTREAM_RULE;
sanghodc375372017-06-08 10:41:30 +090073import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
74import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li960ae512018-07-03 22:50:56 +090075import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090076import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Liec5c32b2018-07-13 14:28:58 +090077import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090078import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090079import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import static org.slf4j.LoggerFactory.getLogger;
81
82
83/**
84 * Populates switching flow rules on OVS for the basic connectivity among the
85 * virtual instances in the same network.
86 */
87@Component(immediate = true)
88public final class OpenstackSwitchingHandler {
89
90 private final Logger log = getLogger(getClass());
91
Jian Li71670d12018-03-02 21:31:07 +090092 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 +090093
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +090095 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090096
Ray Milkeyd84f89b2018-08-17 14:54:17 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +090098 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090099
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900101 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900104 protected DriverService driverService;
105
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900107 protected ClusterService clusterService;
108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li91be8cd2018-07-22 00:44:46 +0900110 protected LeadershipService leadershipService;
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900113 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900116 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900119 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liea1b9662018-03-02 18:07:32 +0900122 protected OpenstackNodeService osNodeService;
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 OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900126
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127 private final ExecutorService eventExecutor = newSingleThreadExecutor(
128 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
129 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Jian Li91be8cd2018-07-22 00:44:46 +0900130 private final InternalOpenstackNetworkListener osNetworkListener =
131 new InternalOpenstackNetworkListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 private ApplicationId appId;
Jian Li91be8cd2018-07-22 00:44:46 +0900133 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134
135 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800136 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
Jian Li91be8cd2018-07-22 00:44:46 +0900138 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 instancePortService.addListener(instancePortListener);
Jian Li91be8cd2018-07-22 00:44:46 +0900140 osNetworkService.addListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141
142 log.info("Started");
143 }
144
145 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800146 void deactivate() {
Jian Li91be8cd2018-07-22 00:44:46 +0900147 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 instancePortService.removeListener(instancePortListener);
149 eventExecutor.shutdown();
150
151 log.info("Stopped");
152 }
153
Jian Liea1b9662018-03-02 18:07:32 +0900154 /**
155 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900156 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900157 *
158 * @param instPort instance port object
159 * @param install install flag, add the rule if true, remove it otherwise
160 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900162 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
163 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900164 case VXLAN:
165 setTunnelTagFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900166 setForwardingRulesForVxlan(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900167 break;
168 case VLAN:
169 setVlanTagFlowRules(instPort, install);
170 setForwardingRulesForVlan(instPort, install);
171 break;
daniel park796c2eb2018-03-22 17:01:51 +0900172 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900173 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900174 setDownstreamRulesForFlat(instPort, install);
175 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900176 break;
daniel parka792cf72017-04-14 16:25:35 +0900177 default:
Jian Liea1b9662018-03-02 18:07:32 +0900178 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900179 break;
180 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 }
182
Jian Li24ec59f2018-05-23 19:01:25 +0900183 /**
184 * Removes virtual port.
185 *
186 * @param instPort instance port
187 */
188 private void removeVportRules(InstancePort instPort) {
189 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
190
191 switch (type) {
192 case VXLAN:
193 setTunnelTagFlowRules(instPort, false);
194 break;
195 case VLAN:
196 setVlanTagFlowRules(instPort, false);
197 break;
Jian Li9a921b42018-06-18 02:44:50 +0900198 case FLAT:
199 setFlatJumpRules(instPort, false);
200 setUpstreamRulesForFlat(instPort, false);
201 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700202 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900203 default:
Jian Li9a921b42018-06-18 02:44:50 +0900204 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900205 break;
206 }
207 }
208
Jian Li70a2c3f2018-04-13 17:26:31 +0900209 private void setFlatJumpRules(InstancePort port, boolean install) {
210 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
211 selector.matchInPort(port.portNumber());
212
213 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900214 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900215
216 osFlowRuleService.setRule(
217 appId,
218 port.deviceId(),
219 selector.build(),
220 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900221 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900222 DHCP_ARP_TABLE,
223 install);
224
225 Network network = osNetworkService.network(port.networkId());
226
227 if (network == null) {
228 log.warn("The network does not exist");
229 return;
230 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900231 PortNumber portNumber = osNodeService.node(port.deviceId())
232 .phyIntfPortNum(network.getProviderPhyNet());
233
234 if (portNumber == null) {
235 log.warn("The port number does not exist");
236 return;
237 }
238
239 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900240 selector.matchInPort(portNumber)
241 .matchEthType(Ethernet.TYPE_IPV4)
242 .matchIPDst(port.ipAddress().toIpPrefix());
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_DOWNSTREAM_RULE,
250 DHCP_ARP_TABLE,
251 install);
252
253 selector = DefaultTrafficSelector.builder();
254 selector.matchInPort(portNumber)
255 .matchEthType(Ethernet.TYPE_ARP)
256 .matchArpTpa(port.ipAddress().getIp4Address());
257
258 osFlowRuleService.setRule(
259 appId,
260 port.deviceId(),
261 selector.build(),
262 treatment.build(),
263 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900264 DHCP_ARP_TABLE,
265 install);
266 }
267
Jian Li9a921b42018-06-18 02:44:50 +0900268 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900269 TrafficSelector selector = DefaultTrafficSelector.builder()
270 .matchEthType(Ethernet.TYPE_IPV4)
271 .matchIPDst(instPort.ipAddress().toIpPrefix())
272 .build();
273 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
274 .setOutput(instPort.portNumber())
275 .build();
276
277 osFlowRuleService.setRule(
278 appId,
279 instPort.deviceId(),
280 selector,
281 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900282 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900283 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900284 install);
285
286 selector = DefaultTrafficSelector.builder()
287 .matchEthType(Ethernet.TYPE_ARP)
288 .matchArpTpa(instPort.ipAddress().getIp4Address())
289 .build();
290
291 osFlowRuleService.setRule(
292 appId,
293 instPort.deviceId(),
294 selector,
295 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900296 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900297 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900298 install);
299 }
300
Jian Li9a921b42018-06-18 02:44:50 +0900301 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900302 TrafficSelector selector = DefaultTrafficSelector.builder()
303 .matchInPort(instPort.portNumber())
304 .build();
305
306 Network network = osNetworkService.network(instPort.networkId());
307
308 if (network == null) {
309 log.warn("The network does not exist");
310 return;
311 }
312
313 PortNumber portNumber = osNodeService.node(instPort.deviceId())
314 .phyIntfPortNum(network.getProviderPhyNet());
315
316 if (portNumber == null) {
317 log.warn("The port number does not exist");
318 return;
319 }
320
321 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
322 .setOutput(portNumber)
323 .build();
324
325 osFlowRuleService.setRule(
326 appId,
327 instPort.deviceId(),
328 selector,
329 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900330 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900331 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900332 install);
333 }
334
Jian Liea1b9662018-03-02 18:07:32 +0900335 /**
336 * Configures the flow rules which are used for L2 packet switching.
337 * Note that these rules will be inserted in switching table (table 5).
338 *
339 * @param instPort instance port object
340 * @param install install flag, add the rule if true, remove it otherwise
341 */
Jian Li9a921b42018-06-18 02:44:50 +0900342 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900343 // switching rules for the instPorts in the same node
344 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900345 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 .matchEthType(Ethernet.TYPE_IPV4)
347 .matchIPDst(instPort.ipAddress().toIpPrefix())
348 .matchTunnelId(getVni(instPort))
349 .build();
350
351 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900352 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900353 .setEthDst(instPort.macAddress())
354 .setOutput(instPort.portNumber())
355 .build();
356
sanghodc375372017-06-08 10:41:30 +0900357 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 appId,
359 instPort.deviceId(),
360 selector,
361 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900362 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900363 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 install);
365
366 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900367 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
368 if (localNode == null) {
369 final String error = String.format("Cannot find openstack node for %s",
370 instPort.deviceId());
371 throw new IllegalStateException(error);
372 }
373 osNodeService.completeNodes(COMPUTE).stream()
374 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
375 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900376 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
377 .extension(buildExtension(
378 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900379 remoteNode.intgBridge(),
380 localNode.dataIp().getIp4Address()),
381 remoteNode.intgBridge())
382 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900383 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384
sanghodc375372017-06-08 10:41:30 +0900385 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900386 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900387 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900388 selector,
389 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900390 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900391 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900392 install);
393 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394 }
395
Jian Liea1b9662018-03-02 18:07:32 +0900396 /**
397 * Configures the flow rules which are used for L2 VLAN packet switching.
398 * Note that these rules will be inserted in switching table (table 5).
399 *
400 * @param instPort instance port object
401 * @param install install flag, add the rule if true, remove it otherwise
402 */
daniel parka792cf72017-04-14 16:25:35 +0900403 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
404 // switching rules for the instPorts in the same node
405 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900406 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900407 .matchEthType(Ethernet.TYPE_IPV4)
408 .matchIPDst(instPort.ipAddress().toIpPrefix())
409 .matchVlanId(getVlanId(instPort))
410 .build();
411
412 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
413 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900414 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900415 .setEthDst(instPort.macAddress())
416 .setOutput(instPort.portNumber())
417 .build();
418
sanghodc375372017-06-08 10:41:30 +0900419 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900420 appId,
421 instPort.deviceId(),
422 selector,
423 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900424 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900425 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900426 install);
427
428 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900429 osNodeService.completeNodes(COMPUTE).stream()
430 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
431 remoteNode.vlanIntf() != null)
432 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900433 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900434 .setEthDst(instPort.macAddress())
435 .setOutput(remoteNode.vlanPortNum())
436 .build();
daniel parka792cf72017-04-14 16:25:35 +0900437
sanghodc375372017-06-08 10:41:30 +0900438 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900439 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900440 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900441 selector,
442 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900443 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900444 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900445 install);
446 });
daniel parka792cf72017-04-14 16:25:35 +0900447 }
448
Jian Liea1b9662018-03-02 18:07:32 +0900449 /**
450 * Configures the flow rule which is for using VXLAN to tag the packet
451 * based on the in_port number of a virtual instance.
452 * Note that this rule will be inserted in VNI table (table 0).
453 *
454 * @param instPort instance port object
455 * @param install install flag, add the rule if true, remove it otherwise
456 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900457 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
458 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900459 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900460 .matchEthType(Ethernet.TYPE_IPV4)
461 .matchInPort(instPort.portNumber())
462 .build();
463
Jian Liea1b9662018-03-02 18:07:32 +0900464 // XXX All egress traffic needs to go through connection tracking module,
465 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900466 ExtensionTreatment ctTreatment =
467 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
468 .commit(true).build();
469
sanghoe6457a32017-08-24 14:31:19 +0900470 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900471 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900472 .transition(ACL_TABLE);
473
474 if (securityGroupService.isSecurityGroupEnabled()) {
475 tb.extension(ctTreatment, instPort.deviceId());
476 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900477
sanghodc375372017-06-08 10:41:30 +0900478 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900479 appId,
480 instPort.deviceId(),
481 selector,
sanghoe6457a32017-08-24 14:31:19 +0900482 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900483 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900484 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485 install);
486 }
487
Jian Liea1b9662018-03-02 18:07:32 +0900488 /**
489 * Configures the flow rule which is for using VLAN to tag the packet
490 * based on the in_port number of a virtual instance.
491 * Note that this rule will be inserted in VNI table (table 0).
492 *
493 * @param instPort instance port object
494 * @param install install flag, add the rule if true, remove it otherwise
495 */
daniel parka792cf72017-04-14 16:25:35 +0900496 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
497 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900498 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900499 .matchEthType(Ethernet.TYPE_IPV4)
500 .matchInPort(instPort.portNumber())
501 .build();
502
503 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
504 .pushVlan()
505 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900506 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900507 .build();
508
sanghodc375372017-06-08 10:41:30 +0900509 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900510 appId,
511 instPort.deviceId(),
512 selector,
513 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900514 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900515 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900516 install);
daniel parka792cf72017-04-14 16:25:35 +0900517 }
518
Jian Li91be8cd2018-07-22 00:44:46 +0900519 private void setNetworkBlockRules(Network network, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800520
Jian Li91be8cd2018-07-22 00:44:46 +0900521 NetworkType type = network.getNetworkType();
522
523 // TODO: we block a network traffic by referring to segment ID for now
524 // we might need to find a better way to block the traffic of a network
525 // in case the segment ID is overlapped in different types network (VXLAN, VLAN)
526 switch (type) {
527 case VXLAN:
528 setNetworkBlockRulesForVxlan(network.getProviderSegID(), install);
529 break;
530 case VLAN:
531 setNetworkBlockRulesForVlan(network.getProviderSegID(), install);
532 break;
533 case FLAT:
534 // TODO: need to find a way to block flat typed network
535 break;
536 default:
537 break;
Frank Wangf9571662017-06-06 18:01:29 +0800538 }
Jian Li91be8cd2018-07-22 00:44:46 +0900539 }
540
541 private void setNetworkBlockRulesForVxlan(String segmentId, boolean install) {
542 TrafficSelector selector = DefaultTrafficSelector.builder()
543 .matchTunnelId(Long.valueOf(segmentId))
544 .build();
Frank Wangf9571662017-06-06 18:01:29 +0800545
546 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
547 .drop()
548 .build();
549
Jian Li91be8cd2018-07-22 00:44:46 +0900550 osNodeService.completeNodes(COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900551 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800552 osFlowRuleService.setRule(
Jian Li91be8cd2018-07-22 00:44:46 +0900553 appId,
554 osNode.intgBridge(),
555 selector,
556 treatment,
557 PRIORITY_ADMIN_RULE,
558 ACL_TABLE,
559 install)
Jian Liea1b9662018-03-02 18:07:32 +0900560 );
Frank Wangf9571662017-06-06 18:01:29 +0800561 }
562
Jian Li91be8cd2018-07-22 00:44:46 +0900563 private void setNetworkBlockRulesForVlan(String segmentId, boolean install) {
Frank Wangf9571662017-06-06 18:01:29 +0800564 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li91be8cd2018-07-22 00:44:46 +0900565 .matchTunnelId(Long.valueOf(segmentId))
566 .build();
567
568 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
569 .drop()
570 .build();
571
572 osNodeService.completeNodes(COMPUTE)
573 .forEach(osNode ->
574 osFlowRuleService.setRule(
575 appId,
576 osNode.intgBridge(),
577 selector,
578 treatment,
579 PRIORITY_ADMIN_RULE,
580 ACL_TABLE,
581 install)
582 );
583 }
584
585 private void setPortBlockRules(InstancePort instPort, boolean install) {
586 TrafficSelector selector = DefaultTrafficSelector.builder()
587 .matchInPort(instPort.portNumber())
Frank Wangf9571662017-06-06 18:01:29 +0800588 .build();
589
590 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
591 .drop()
592 .build();
593
594 osFlowRuleService.setRule(
595 appId,
Jian Li91be8cd2018-07-22 00:44:46 +0900596 instPort.deviceId(),
Frank Wangf9571662017-06-06 18:01:29 +0800597 selector,
598 treatment,
599 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900600 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800601 install);
602 }
603
Jian Liea1b9662018-03-02 18:07:32 +0900604 /**
605 * Obtains the VLAN ID from the given instance port.
606 *
607 * @param instPort instance port object
608 * @return VLAN ID
609 */
daniel parka792cf72017-04-14 16:25:35 +0900610 private VlanId getVlanId(InstancePort instPort) {
611 Network osNet = osNetworkService.network(instPort.networkId());
612
613 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900614 final String error =
615 String.format(ERR_SET_FLOWS_VNI,
616 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900617 throw new IllegalStateException(error);
618 }
619
620 return VlanId.vlanId(osNet.getProviderSegID());
621 }
622
Jian Liea1b9662018-03-02 18:07:32 +0900623 /**
624 * Obtains the VNI from the given instance port.
625 *
626 * @param instPort instance port object
627 * @return VXLAN Network Identifier (VNI)
628 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900629 private Long getVni(InstancePort instPort) {
630 Network osNet = osNetworkService.network(instPort.networkId());
631 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900632 final String error =
633 String.format(ERR_SET_FLOWS_VNI,
634 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900635 throw new IllegalStateException(error);
636 }
637 return Long.valueOf(osNet.getProviderSegID());
638 }
639
Jian Liea1b9662018-03-02 18:07:32 +0900640 /**
641 * An internal instance port listener which listens the port events generated
642 * from VM. The corresponding L2 forwarding rules will be generated and
643 * inserted to integration bridge only if a new VM port is detected. If the
644 * existing detected VM port is removed due to VM purge, we will remove the
645 * corresponding L2 forwarding to as well for the sake of resource saving.
646 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900647 private class InternalInstancePortListener implements InstancePortListener {
648
649 @Override
650 public boolean isRelevant(InstancePortEvent event) {
651 InstancePort instPort = event.subject();
652 return mastershipService.isLocalMaster(instPort.deviceId());
653 }
654
655 @Override
656 public void event(InstancePortEvent event) {
657 InstancePort instPort = event.subject();
Jian Li91be8cd2018-07-22 00:44:46 +0900658 Port osPort = osNetworkService.port(instPort.portId());
Jian Li9a921b42018-06-18 02:44:50 +0900659
Hyunsun Moon44aac662017-02-18 02:07:01 +0900660 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900661 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900662 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900663 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900664 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900665 instPort.macAddress(),
666 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900667
668 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900669
Jian Li91be8cd2018-07-22 00:44:46 +0900670 if (osPort != null) {
671 eventExecutor.execute(() ->
672 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
673 }
674
Hyunsun Moon44aac662017-02-18 02:07:01 +0900675 break;
Jian Li46b74002018-07-15 18:39:08 +0900676 case OPENSTACK_INSTANCE_TERMINATED:
677 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
678 instPort.macAddress(),
679 instPort.ipAddress());
680 eventExecutor.execute(() -> removeVportRules(instPort));
681
682 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900683 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900684 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900685 instPort.macAddress(),
686 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900687
688 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900689
Jian Li91be8cd2018-07-22 00:44:46 +0900690 if (osPort != null) {
691 setPortBlockRules(instPort, false);
692 }
693
Hyunsun Moon44aac662017-02-18 02:07:01 +0900694 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900695 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
696 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
697 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900698 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900699
700 eventExecutor.execute(() -> instPortDetected(instPort));
701
Jian Li91be8cd2018-07-22 00:44:46 +0900702 if (osPort != null) {
703 eventExecutor.execute(() ->
704 setPortBlockRules(instPort, !osPort.isAdminStateUp()));
705 }
706
Jian Liec5c32b2018-07-13 14:28:58 +0900707 break;
708 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
709 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
710 instPort.macAddress(),
711 instPort.ipAddress());
712
713 InstancePort revisedInstPort = swapStaleLocation(instPort);
714 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
715
Jian Li24ec59f2018-05-23 19:01:25 +0900716 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900717 default:
718 break;
719 }
720 }
721
722 private void instPortDetected(InstancePort instPort) {
723 setNetworkRules(instPort, true);
724 // TODO add something else if needed
725 }
726
727 private void instPortRemoved(InstancePort instPort) {
728 setNetworkRules(instPort, false);
729 // TODO add something else if needed
730 }
731 }
Jian Li91be8cd2018-07-22 00:44:46 +0900732
733 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
734
735 @Override
736 public boolean isRelevant(OpenstackNetworkEvent event) {
737
738 // do not allow to proceed without leadership
739 NodeId leader = leadershipService.getLeader(appId.name());
740 return Objects.equals(localNodeId, leader);
741 }
742
743 @Override
744 public void event(OpenstackNetworkEvent event) {
745
746 if (event.subject() == null || event.port() == null) {
747 return;
748 }
749
750 boolean isNwAdminStateUp = event.subject().isAdminStateUp();
751 boolean isPortAdminStateUp = event.port().isAdminStateUp();
752
753 InstancePort instPort = instancePortService.instancePort(event.port().getId());
754
755 switch (event.type()) {
756 case OPENSTACK_NETWORK_CREATED:
757 case OPENSTACK_NETWORK_UPDATED:
758 eventExecutor.execute(() ->
759 setNetworkBlockRules(event.subject(), !isNwAdminStateUp));
760
761 break;
762 case OPENSTACK_NETWORK_REMOVED:
763 eventExecutor.execute(() ->
764 setNetworkBlockRules(event.subject(), false));
765 break;
766 case OPENSTACK_PORT_CREATED:
767 case OPENSTACK_PORT_UPDATED:
768
769 if (instPort != null) {
770 eventExecutor.execute(() ->
771 setPortBlockRules(instPort, !isPortAdminStateUp));
772 }
773
774 break;
775 case OPENSTACK_PORT_REMOVED:
776
777 if (instPort != null) {
778 eventExecutor.execute(() ->
779 setPortBlockRules(instPort, false));
780 }
781
782 break;
783 default:
784 break;
785 }
786 }
787 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900788}