blob: 5519f370d4fc192ab7863448e1a6d9cf81b6caf1 [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;
Frank Wangf9571662017-06-06 18:01:29 +080026import org.onlab.packet.MacAddress;
daniel parka792cf72017-04-14 16:25:35 +090027import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
30import org.onosproject.mastership.MastershipService;
daniel park796c2eb2018-03-22 17:01:51 +090031import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.net.device.DeviceService;
sangho1aaa7882017-05-31 13:22:47 +090033import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
sangho1aaa7882017-05-31 13:22:47 +090038import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.openstacknetworking.api.InstancePort;
40import org.onosproject.openstacknetworking.api.InstancePortEvent;
41import org.onosproject.openstacknetworking.api.InstancePortListener;
42import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090043import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghoe6457a32017-08-24 14:31:19 +090045import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090046import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import org.onosproject.openstacknode.api.OpenstackNode;
48import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.openstack4j.model.network.Network;
Frank Wangf9571662017-06-06 18:01:29 +080050import org.openstack4j.model.network.NetworkType;
51import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.slf4j.Logger;
53
54import java.util.concurrent.ExecutorService;
55
56import static java.util.concurrent.Executors.newSingleThreadExecutor;
57import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090058import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090059import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
60import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
sanghodc375372017-06-08 10:41:30 +090061import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
62import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Frank Wangf9571662017-06-06 18:01:29 +080063import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Daniel Parkd1b14d32018-06-12 16:10:28 +090064import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_DOWNSTREAM_RULE;
65import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE;
66import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
67import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_UPSTREAM_RULE;
sanghodc375372017-06-08 10:41:30 +090068import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
69import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li960ae512018-07-03 22:50:56 +090070import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li70a2c3f2018-04-13 17:26:31 +090071import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Liec5c32b2018-07-13 14:28:58 +090072import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090073import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090074import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import static org.slf4j.LoggerFactory.getLogger;
76
77
78/**
79 * Populates switching flow rules on OVS for the basic connectivity among the
80 * virtual instances in the same network.
81 */
82@Component(immediate = true)
83public final class OpenstackSwitchingHandler {
84
85 private final Logger log = getLogger(getClass());
86
Jian Li71670d12018-03-02 21:31:07 +090087 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 +090088
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090090 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090091
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090093 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090096 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090097
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090099 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900102 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900105 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900108 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109
sangho1aaa7882017-05-31 13:22:47 +0900110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900111 protected DriverService driverService;
sangho1aaa7882017-05-31 13:22:47 +0900112
sanghoe6457a32017-08-24 14:31:19 +0900113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900114 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900115
Hyunsun Moon44aac662017-02-18 02:07:01 +0900116 private final ExecutorService eventExecutor = newSingleThreadExecutor(
117 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
118 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
119 private ApplicationId appId;
120
121 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800122 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
124 instancePortService.addListener(instancePortListener);
125
126 log.info("Started");
127 }
128
129 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800130 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131 instancePortService.removeListener(instancePortListener);
132 eventExecutor.shutdown();
133
134 log.info("Stopped");
135 }
136
Jian Liea1b9662018-03-02 18:07:32 +0900137 /**
138 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900139 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900140 *
141 * @param instPort instance port object
142 * @param install install flag, add the rule if true, remove it otherwise
143 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900145 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
146 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900147 case VXLAN:
148 setTunnelTagFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900149 setForwardingRulesForVxlan(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900150 break;
151 case VLAN:
152 setVlanTagFlowRules(instPort, install);
153 setForwardingRulesForVlan(instPort, install);
154 break;
daniel park796c2eb2018-03-22 17:01:51 +0900155 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900156 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900157 setDownstreamRulesForFlat(instPort, install);
158 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900159 break;
daniel parka792cf72017-04-14 16:25:35 +0900160 default:
Jian Liea1b9662018-03-02 18:07:32 +0900161 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900162 break;
163 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 }
165
Jian Li24ec59f2018-05-23 19:01:25 +0900166 /**
167 * Removes virtual port.
168 *
169 * @param instPort instance port
170 */
171 private void removeVportRules(InstancePort instPort) {
172 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
173
174 switch (type) {
175 case VXLAN:
176 setTunnelTagFlowRules(instPort, false);
177 break;
178 case VLAN:
179 setVlanTagFlowRules(instPort, false);
180 break;
Jian Li9a921b42018-06-18 02:44:50 +0900181 case FLAT:
182 setFlatJumpRules(instPort, false);
183 setUpstreamRulesForFlat(instPort, false);
184 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700185 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900186 default:
Jian Li9a921b42018-06-18 02:44:50 +0900187 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900188 break;
189 }
190 }
191
Jian Li70a2c3f2018-04-13 17:26:31 +0900192 private void setFlatJumpRules(InstancePort port, boolean install) {
193 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
194 selector.matchInPort(port.portNumber());
195
196 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900197 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900198
199 osFlowRuleService.setRule(
200 appId,
201 port.deviceId(),
202 selector.build(),
203 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900204 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900205 DHCP_ARP_TABLE,
206 install);
207
208 Network network = osNetworkService.network(port.networkId());
209
210 if (network == null) {
211 log.warn("The network does not exist");
212 return;
213 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900214 PortNumber portNumber = osNodeService.node(port.deviceId())
215 .phyIntfPortNum(network.getProviderPhyNet());
216
217 if (portNumber == null) {
218 log.warn("The port number does not exist");
219 return;
220 }
221
222 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900223 selector.matchInPort(portNumber)
224 .matchEthType(Ethernet.TYPE_IPV4)
225 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900226
227 osFlowRuleService.setRule(
228 appId,
229 port.deviceId(),
230 selector.build(),
231 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900232 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
233 DHCP_ARP_TABLE,
234 install);
235
236 selector = DefaultTrafficSelector.builder();
237 selector.matchInPort(portNumber)
238 .matchEthType(Ethernet.TYPE_ARP)
239 .matchArpTpa(port.ipAddress().getIp4Address());
240
241 osFlowRuleService.setRule(
242 appId,
243 port.deviceId(),
244 selector.build(),
245 treatment.build(),
246 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900247 DHCP_ARP_TABLE,
248 install);
249 }
250
Jian Li9a921b42018-06-18 02:44:50 +0900251 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900252 TrafficSelector selector = DefaultTrafficSelector.builder()
253 .matchEthType(Ethernet.TYPE_IPV4)
254 .matchIPDst(instPort.ipAddress().toIpPrefix())
255 .build();
256 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
257 .setOutput(instPort.portNumber())
258 .build();
259
260 osFlowRuleService.setRule(
261 appId,
262 instPort.deviceId(),
263 selector,
264 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900265 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900266 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900267 install);
268
269 selector = DefaultTrafficSelector.builder()
270 .matchEthType(Ethernet.TYPE_ARP)
271 .matchArpTpa(instPort.ipAddress().getIp4Address())
272 .build();
273
274 osFlowRuleService.setRule(
275 appId,
276 instPort.deviceId(),
277 selector,
278 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900279 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900280 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900281 install);
282 }
283
Jian Li9a921b42018-06-18 02:44:50 +0900284 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900285 TrafficSelector selector = DefaultTrafficSelector.builder()
286 .matchInPort(instPort.portNumber())
287 .build();
288
289 Network network = osNetworkService.network(instPort.networkId());
290
291 if (network == null) {
292 log.warn("The network does not exist");
293 return;
294 }
295
296 PortNumber portNumber = osNodeService.node(instPort.deviceId())
297 .phyIntfPortNum(network.getProviderPhyNet());
298
299 if (portNumber == null) {
300 log.warn("The port number does not exist");
301 return;
302 }
303
304 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
305 .setOutput(portNumber)
306 .build();
307
308 osFlowRuleService.setRule(
309 appId,
310 instPort.deviceId(),
311 selector,
312 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900313 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900314 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900315 install);
316 }
317
318
Jian Liea1b9662018-03-02 18:07:32 +0900319 /**
320 * Configures the flow rules which are used for L2 packet switching.
321 * Note that these rules will be inserted in switching table (table 5).
322 *
323 * @param instPort instance port object
324 * @param install install flag, add the rule if true, remove it otherwise
325 */
Jian Li9a921b42018-06-18 02:44:50 +0900326 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900327 // switching rules for the instPorts in the same node
328 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900329 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900330 .matchEthType(Ethernet.TYPE_IPV4)
331 .matchIPDst(instPort.ipAddress().toIpPrefix())
332 .matchTunnelId(getVni(instPort))
333 .build();
334
335 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900336 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 .setEthDst(instPort.macAddress())
338 .setOutput(instPort.portNumber())
339 .build();
340
sanghodc375372017-06-08 10:41:30 +0900341 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342 appId,
343 instPort.deviceId(),
344 selector,
345 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900347 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900348 install);
349
350 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900351 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
352 if (localNode == null) {
353 final String error = String.format("Cannot find openstack node for %s",
354 instPort.deviceId());
355 throw new IllegalStateException(error);
356 }
357 osNodeService.completeNodes(COMPUTE).stream()
358 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
359 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900360 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
361 .extension(buildExtension(
362 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900363 remoteNode.intgBridge(),
364 localNode.dataIp().getIp4Address()),
365 remoteNode.intgBridge())
366 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900367 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900368
sanghodc375372017-06-08 10:41:30 +0900369 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900370 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900371 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900372 selector,
373 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900374 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900375 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900376 install);
377 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900378 }
379
Jian Liea1b9662018-03-02 18:07:32 +0900380 /**
381 * Configures the flow rules which are used for L2 VLAN packet switching.
382 * Note that these rules will be inserted in switching table (table 5).
383 *
384 * @param instPort instance port object
385 * @param install install flag, add the rule if true, remove it otherwise
386 */
daniel parka792cf72017-04-14 16:25:35 +0900387 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
388 // switching rules for the instPorts in the same node
389 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900390 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900391 .matchEthType(Ethernet.TYPE_IPV4)
392 .matchIPDst(instPort.ipAddress().toIpPrefix())
393 .matchVlanId(getVlanId(instPort))
394 .build();
395
396 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
397 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900398 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900399 .setEthDst(instPort.macAddress())
400 .setOutput(instPort.portNumber())
401 .build();
402
sanghodc375372017-06-08 10:41:30 +0900403 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900404 appId,
405 instPort.deviceId(),
406 selector,
407 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900408 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900409 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900410 install);
411
412 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900413 osNodeService.completeNodes(COMPUTE).stream()
414 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
415 remoteNode.vlanIntf() != null)
416 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900417 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900418 .setEthDst(instPort.macAddress())
419 .setOutput(remoteNode.vlanPortNum())
420 .build();
daniel parka792cf72017-04-14 16:25:35 +0900421
sanghodc375372017-06-08 10:41:30 +0900422 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900423 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900424 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900425 selector,
426 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900427 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900428 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900429 install);
430 });
daniel parka792cf72017-04-14 16:25:35 +0900431 }
432
Jian Liea1b9662018-03-02 18:07:32 +0900433 /**
434 * Configures the flow rule which is for using VXLAN to tag the packet
435 * based on the in_port number of a virtual instance.
436 * Note that this rule will be inserted in VNI table (table 0).
437 *
438 * @param instPort instance port object
439 * @param install install flag, add the rule if true, remove it otherwise
440 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
442 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900443 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900444 .matchEthType(Ethernet.TYPE_IPV4)
445 .matchInPort(instPort.portNumber())
446 .build();
447
Jian Liea1b9662018-03-02 18:07:32 +0900448 // XXX All egress traffic needs to go through connection tracking module,
449 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900450 ExtensionTreatment ctTreatment =
451 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
452 .commit(true).build();
453
sanghoe6457a32017-08-24 14:31:19 +0900454 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900455 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900456 .transition(ACL_TABLE);
457
458 if (securityGroupService.isSecurityGroupEnabled()) {
459 tb.extension(ctTreatment, instPort.deviceId());
460 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900461
sanghodc375372017-06-08 10:41:30 +0900462 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900463 appId,
464 instPort.deviceId(),
465 selector,
sanghoe6457a32017-08-24 14:31:19 +0900466 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900467 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900468 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900469 install);
470 }
471
Jian Liea1b9662018-03-02 18:07:32 +0900472 /**
473 * Configures the flow rule which is for using VLAN to tag the packet
474 * based on the in_port number of a virtual instance.
475 * Note that this rule will be inserted in VNI table (table 0).
476 *
477 * @param instPort instance port object
478 * @param install install flag, add the rule if true, remove it otherwise
479 */
daniel parka792cf72017-04-14 16:25:35 +0900480 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
481 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900482 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900483 .matchEthType(Ethernet.TYPE_IPV4)
484 .matchInPort(instPort.portNumber())
485 .build();
486
487 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
488 .pushVlan()
489 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900490 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900491 .build();
492
sanghodc375372017-06-08 10:41:30 +0900493 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900494 appId,
495 instPort.deviceId(),
496 selector,
497 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900498 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900499 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900500 install);
daniel parka792cf72017-04-14 16:25:35 +0900501 }
502
Frank Wangf9571662017-06-06 18:01:29 +0800503 private void setNetworkAdminRules(Network network, boolean install) {
504 TrafficSelector selector;
505 if (network.getNetworkType() == NetworkType.VXLAN) {
506
507 selector = DefaultTrafficSelector.builder()
508 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
509 .build();
510 } else {
511 selector = DefaultTrafficSelector.builder()
512 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
513 .build();
514 }
515
516 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
517 .drop()
518 .build();
519
520 osNodeService.completeNodes().stream()
521 .filter(osNode -> osNode.type() == COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900522 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800523 osFlowRuleService.setRule(
524 appId,
525 osNode.intgBridge(),
526 selector,
527 treatment,
528 PRIORITY_ADMIN_RULE,
529 ACL_TABLE,
Jian Liea1b9662018-03-02 18:07:32 +0900530 install)
531 );
Frank Wangf9571662017-06-06 18:01:29 +0800532 }
533
Jian Li70a2c3f2018-04-13 17:26:31 +0900534 // TODO: need to be purged sooner or later
Frank Wangf9571662017-06-06 18:01:29 +0800535 private void setPortAdminRules(Port port, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900536 InstancePort instancePort =
537 instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
Frank Wangf9571662017-06-06 18:01:29 +0800538 TrafficSelector selector = DefaultTrafficSelector.builder()
539 .matchInPort(instancePort.portNumber())
540 .build();
541
542 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
543 .drop()
544 .build();
545
546 osFlowRuleService.setRule(
547 appId,
548 instancePort.deviceId(),
549 selector,
550 treatment,
551 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900552 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800553 install);
554 }
555
Jian Liea1b9662018-03-02 18:07:32 +0900556 /**
557 * Obtains the VLAN ID from the given instance port.
558 *
559 * @param instPort instance port object
560 * @return VLAN ID
561 */
daniel parka792cf72017-04-14 16:25:35 +0900562 private VlanId getVlanId(InstancePort instPort) {
563 Network osNet = osNetworkService.network(instPort.networkId());
564
565 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900566 final String error =
567 String.format(ERR_SET_FLOWS_VNI,
568 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900569 throw new IllegalStateException(error);
570 }
571
572 return VlanId.vlanId(osNet.getProviderSegID());
573 }
574
Jian Liea1b9662018-03-02 18:07:32 +0900575 /**
576 * Obtains the VNI from the given instance port.
577 *
578 * @param instPort instance port object
579 * @return VXLAN Network Identifier (VNI)
580 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581 private Long getVni(InstancePort instPort) {
582 Network osNet = osNetworkService.network(instPort.networkId());
583 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900584 final String error =
585 String.format(ERR_SET_FLOWS_VNI,
586 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900587 throw new IllegalStateException(error);
588 }
589 return Long.valueOf(osNet.getProviderSegID());
590 }
591
Jian Liea1b9662018-03-02 18:07:32 +0900592 /**
593 * An internal instance port listener which listens the port events generated
594 * from VM. The corresponding L2 forwarding rules will be generated and
595 * inserted to integration bridge only if a new VM port is detected. If the
596 * existing detected VM port is removed due to VM purge, we will remove the
597 * corresponding L2 forwarding to as well for the sake of resource saving.
598 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900599 private class InternalInstancePortListener implements InstancePortListener {
600
601 @Override
602 public boolean isRelevant(InstancePortEvent event) {
603 InstancePort instPort = event.subject();
604 return mastershipService.isLocalMaster(instPort.deviceId());
605 }
606
607 @Override
608 public void event(InstancePortEvent event) {
609 InstancePort instPort = event.subject();
Jian Li9a921b42018-06-18 02:44:50 +0900610
Hyunsun Moon44aac662017-02-18 02:07:01 +0900611 switch (event.type()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900612 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900613 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li46b74002018-07-15 18:39:08 +0900614 case OPENSTACK_INSTANCE_RESTARTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900615 log.info("SwitchingHandler: Instance port detected MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900616 instPort.macAddress(),
617 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900618
619 eventExecutor.execute(() -> instPortDetected(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900620
Hyunsun Moon44aac662017-02-18 02:07:01 +0900621 break;
Jian Li46b74002018-07-15 18:39:08 +0900622 case OPENSTACK_INSTANCE_TERMINATED:
623 log.info("SwitchingHandler: Instance port terminated MAC:{} IP:{}",
624 instPort.macAddress(),
625 instPort.ipAddress());
626 eventExecutor.execute(() -> removeVportRules(instPort));
627
628 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900629 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +0900630 log.info("SwitchingHandler: Instance port vanished MAC:{} IP:{}",
Jian Li9a921b42018-06-18 02:44:50 +0900631 instPort.macAddress(),
632 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900633
634 eventExecutor.execute(() -> instPortRemoved(instPort));
Jian Li9a921b42018-06-18 02:44:50 +0900635
Hyunsun Moon44aac662017-02-18 02:07:01 +0900636 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900637 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
638 log.info("SwitchingHandler: Migration started for MAC:{} IP:{}",
639 instPort.macAddress(),
Jian Li9a921b42018-06-18 02:44:50 +0900640 instPort.ipAddress());
Jian Liec5c32b2018-07-13 14:28:58 +0900641
642 eventExecutor.execute(() -> instPortDetected(instPort));
643
644 break;
645 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
646 log.info("SwitchingHandler: Migration finished for MAC:{} IP:{}",
647 instPort.macAddress(),
648 instPort.ipAddress());
649
650 InstancePort revisedInstPort = swapStaleLocation(instPort);
651 eventExecutor.execute(() -> removeVportRules(revisedInstPort));
652
Jian Li24ec59f2018-05-23 19:01:25 +0900653 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900654 default:
655 break;
656 }
657 }
658
659 private void instPortDetected(InstancePort instPort) {
660 setNetworkRules(instPort, true);
661 // TODO add something else if needed
662 }
663
664 private void instPortRemoved(InstancePort instPort) {
665 setNetworkRules(instPort, false);
666 // TODO add something else if needed
667 }
668 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900669}