blob: 18116a9195b6996ed718acb3772a7a3992ec6bb7 [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 Li26949762018-03-30 15:46:37 +090072import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090073import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import static org.slf4j.LoggerFactory.getLogger;
75
76
77/**
78 * Populates switching flow rules on OVS for the basic connectivity among the
79 * virtual instances in the same network.
80 */
81@Component(immediate = true)
82public final class OpenstackSwitchingHandler {
83
84 private final Logger log = getLogger(getClass());
85
Jian Li71670d12018-03-02 21:31:07 +090086 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 +090087
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090089 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090090
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090092 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090093
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090095 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090098 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090099
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900101 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900104 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900107 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108
sangho1aaa7882017-05-31 13:22:47 +0900109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900110 protected DriverService driverService;
sangho1aaa7882017-05-31 13:22:47 +0900111
sanghoe6457a32017-08-24 14:31:19 +0900112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900113 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900114
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 private final ExecutorService eventExecutor = newSingleThreadExecutor(
116 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
117 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
118 private ApplicationId appId;
119
120 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800121 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
123 instancePortService.addListener(instancePortListener);
124
125 log.info("Started");
126 }
127
128 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800129 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130 instancePortService.removeListener(instancePortListener);
131 eventExecutor.shutdown();
132
133 log.info("Stopped");
134 }
135
Jian Liea1b9662018-03-02 18:07:32 +0900136 /**
137 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900138 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900139 *
140 * @param instPort instance port object
141 * @param install install flag, add the rule if true, remove it otherwise
142 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900144 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
145 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900146 case VXLAN:
147 setTunnelTagFlowRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900148 setForwardingRulesForVxlan(instPort, install);
daniel parka792cf72017-04-14 16:25:35 +0900149 break;
150 case VLAN:
151 setVlanTagFlowRules(instPort, install);
152 setForwardingRulesForVlan(instPort, install);
153 break;
daniel park796c2eb2018-03-22 17:01:51 +0900154 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900155 setFlatJumpRules(instPort, install);
Jian Li9a921b42018-06-18 02:44:50 +0900156 setDownstreamRulesForFlat(instPort, install);
157 setUpstreamRulesForFlat(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900158 break;
daniel parka792cf72017-04-14 16:25:35 +0900159 default:
Jian Liea1b9662018-03-02 18:07:32 +0900160 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900161 break;
162 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163 }
164
Jian Li24ec59f2018-05-23 19:01:25 +0900165 /**
166 * Removes virtual port.
167 *
168 * @param instPort instance port
169 */
170 private void removeVportRules(InstancePort instPort) {
171 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
172
173 switch (type) {
174 case VXLAN:
175 setTunnelTagFlowRules(instPort, false);
176 break;
177 case VLAN:
178 setVlanTagFlowRules(instPort, false);
179 break;
Jian Li9a921b42018-06-18 02:44:50 +0900180 case FLAT:
181 setFlatJumpRules(instPort, false);
182 setUpstreamRulesForFlat(instPort, false);
183 setDownstreamRulesForFlat(instPort, false);
Ray Milkeybcc53d32018-07-02 10:22:57 -0700184 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900185 default:
Jian Li9a921b42018-06-18 02:44:50 +0900186 log.warn("Unsupported network type {}", type.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900187 break;
188 }
189 }
190
Jian Li70a2c3f2018-04-13 17:26:31 +0900191 private void setFlatJumpRules(InstancePort port, boolean install) {
192 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
193 selector.matchInPort(port.portNumber());
194
195 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
Jian Li960ae512018-07-03 22:50:56 +0900196 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
Jian Li70a2c3f2018-04-13 17:26:31 +0900197
198 osFlowRuleService.setRule(
199 appId,
200 port.deviceId(),
201 selector.build(),
202 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900203 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900204 DHCP_ARP_TABLE,
205 install);
206
207 Network network = osNetworkService.network(port.networkId());
208
209 if (network == null) {
210 log.warn("The network does not exist");
211 return;
212 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900213 PortNumber portNumber = osNodeService.node(port.deviceId())
214 .phyIntfPortNum(network.getProviderPhyNet());
215
216 if (portNumber == null) {
217 log.warn("The port number does not exist");
218 return;
219 }
220
221 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900222 selector.matchInPort(portNumber)
223 .matchEthType(Ethernet.TYPE_IPV4)
224 .matchIPDst(port.ipAddress().toIpPrefix());
Jian Li70a2c3f2018-04-13 17:26:31 +0900225
226 osFlowRuleService.setRule(
227 appId,
228 port.deviceId(),
229 selector.build(),
230 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900231 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
232 DHCP_ARP_TABLE,
233 install);
234
235 selector = DefaultTrafficSelector.builder();
236 selector.matchInPort(portNumber)
237 .matchEthType(Ethernet.TYPE_ARP)
238 .matchArpTpa(port.ipAddress().getIp4Address());
239
240 osFlowRuleService.setRule(
241 appId,
242 port.deviceId(),
243 selector.build(),
244 treatment.build(),
245 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900246 DHCP_ARP_TABLE,
247 install);
248 }
249
Jian Li9a921b42018-06-18 02:44:50 +0900250 private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900251 TrafficSelector selector = DefaultTrafficSelector.builder()
252 .matchEthType(Ethernet.TYPE_IPV4)
253 .matchIPDst(instPort.ipAddress().toIpPrefix())
254 .build();
255 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
256 .setOutput(instPort.portNumber())
257 .build();
258
259 osFlowRuleService.setRule(
260 appId,
261 instPort.deviceId(),
262 selector,
263 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900264 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900265 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900266 install);
267
268 selector = DefaultTrafficSelector.builder()
269 .matchEthType(Ethernet.TYPE_ARP)
270 .matchArpTpa(instPort.ipAddress().getIp4Address())
271 .build();
272
273 osFlowRuleService.setRule(
274 appId,
275 instPort.deviceId(),
276 selector,
277 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900278 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900279 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900280 install);
281 }
282
Jian Li9a921b42018-06-18 02:44:50 +0900283 private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
daniel park796c2eb2018-03-22 17:01:51 +0900284 TrafficSelector selector = DefaultTrafficSelector.builder()
285 .matchInPort(instPort.portNumber())
286 .build();
287
288 Network network = osNetworkService.network(instPort.networkId());
289
290 if (network == null) {
291 log.warn("The network does not exist");
292 return;
293 }
294
295 PortNumber portNumber = osNodeService.node(instPort.deviceId())
296 .phyIntfPortNum(network.getProviderPhyNet());
297
298 if (portNumber == null) {
299 log.warn("The port number does not exist");
300 return;
301 }
302
303 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
304 .setOutput(portNumber)
305 .build();
306
307 osFlowRuleService.setRule(
308 appId,
309 instPort.deviceId(),
310 selector,
311 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900312 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900313 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900314 install);
315 }
316
317
Jian Liea1b9662018-03-02 18:07:32 +0900318 /**
319 * Configures the flow rules which are used for L2 packet switching.
320 * Note that these rules will be inserted in switching table (table 5).
321 *
322 * @param instPort instance port object
323 * @param install install flag, add the rule if true, remove it otherwise
324 */
Jian Li9a921b42018-06-18 02:44:50 +0900325 private void setForwardingRulesForVxlan(InstancePort instPort, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326 // switching rules for the instPorts in the same node
327 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900328 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900329 .matchEthType(Ethernet.TYPE_IPV4)
330 .matchIPDst(instPort.ipAddress().toIpPrefix())
331 .matchTunnelId(getVni(instPort))
332 .build();
333
334 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900335 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900336 .setEthDst(instPort.macAddress())
337 .setOutput(instPort.portNumber())
338 .build();
339
sanghodc375372017-06-08 10:41:30 +0900340 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 appId,
342 instPort.deviceId(),
343 selector,
344 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900345 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900346 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 install);
348
349 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900350 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
351 if (localNode == null) {
352 final String error = String.format("Cannot find openstack node for %s",
353 instPort.deviceId());
354 throw new IllegalStateException(error);
355 }
356 osNodeService.completeNodes(COMPUTE).stream()
357 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
358 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900359 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
360 .extension(buildExtension(
361 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900362 remoteNode.intgBridge(),
363 localNode.dataIp().getIp4Address()),
364 remoteNode.intgBridge())
365 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900366 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367
sanghodc375372017-06-08 10:41:30 +0900368 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900369 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900370 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900371 selector,
372 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900373 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900374 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900375 install);
376 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377 }
378
Jian Liea1b9662018-03-02 18:07:32 +0900379 /**
380 * Configures the flow rules which are used for L2 VLAN packet switching.
381 * Note that these rules will be inserted in switching table (table 5).
382 *
383 * @param instPort instance port object
384 * @param install install flag, add the rule if true, remove it otherwise
385 */
daniel parka792cf72017-04-14 16:25:35 +0900386 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
387 // switching rules for the instPorts in the same node
388 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900389 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900390 .matchEthType(Ethernet.TYPE_IPV4)
391 .matchIPDst(instPort.ipAddress().toIpPrefix())
392 .matchVlanId(getVlanId(instPort))
393 .build();
394
395 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
396 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900397 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900398 .setEthDst(instPort.macAddress())
399 .setOutput(instPort.portNumber())
400 .build();
401
sanghodc375372017-06-08 10:41:30 +0900402 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900403 appId,
404 instPort.deviceId(),
405 selector,
406 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900407 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900408 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900409 install);
410
411 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900412 osNodeService.completeNodes(COMPUTE).stream()
413 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
414 remoteNode.vlanIntf() != null)
415 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900416 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900417 .setEthDst(instPort.macAddress())
418 .setOutput(remoteNode.vlanPortNum())
419 .build();
daniel parka792cf72017-04-14 16:25:35 +0900420
sanghodc375372017-06-08 10:41:30 +0900421 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900422 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900423 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900424 selector,
425 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900426 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900427 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900428 install);
429 });
daniel parka792cf72017-04-14 16:25:35 +0900430 }
431
Jian Liea1b9662018-03-02 18:07:32 +0900432 /**
433 * Configures the flow rule which is for using VXLAN to tag the packet
434 * based on the in_port number of a virtual instance.
435 * Note that this rule will be inserted in VNI table (table 0).
436 *
437 * @param instPort instance port object
438 * @param install install flag, add the rule if true, remove it otherwise
439 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900440 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
441 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900442 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900443 .matchEthType(Ethernet.TYPE_IPV4)
444 .matchInPort(instPort.portNumber())
445 .build();
446
Jian Liea1b9662018-03-02 18:07:32 +0900447 // XXX All egress traffic needs to go through connection tracking module,
448 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900449 ExtensionTreatment ctTreatment =
450 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
451 .commit(true).build();
452
sanghoe6457a32017-08-24 14:31:19 +0900453 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900454 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900455 .transition(ACL_TABLE);
456
457 if (securityGroupService.isSecurityGroupEnabled()) {
458 tb.extension(ctTreatment, instPort.deviceId());
459 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900460
sanghodc375372017-06-08 10:41:30 +0900461 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900462 appId,
463 instPort.deviceId(),
464 selector,
sanghoe6457a32017-08-24 14:31:19 +0900465 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900466 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900467 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900468 install);
469 }
470
Jian Liea1b9662018-03-02 18:07:32 +0900471 /**
472 * Configures the flow rule which is for using VLAN to tag the packet
473 * based on the in_port number of a virtual instance.
474 * Note that this rule will be inserted in VNI table (table 0).
475 *
476 * @param instPort instance port object
477 * @param install install flag, add the rule if true, remove it otherwise
478 */
daniel parka792cf72017-04-14 16:25:35 +0900479 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
480 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900481 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900482 .matchEthType(Ethernet.TYPE_IPV4)
483 .matchInPort(instPort.portNumber())
484 .build();
485
486 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
487 .pushVlan()
488 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900489 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900490 .build();
491
sanghodc375372017-06-08 10:41:30 +0900492 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900493 appId,
494 instPort.deviceId(),
495 selector,
496 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900497 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900498 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900499 install);
daniel parka792cf72017-04-14 16:25:35 +0900500 }
501
Frank Wangf9571662017-06-06 18:01:29 +0800502 private void setNetworkAdminRules(Network network, boolean install) {
503 TrafficSelector selector;
504 if (network.getNetworkType() == NetworkType.VXLAN) {
505
506 selector = DefaultTrafficSelector.builder()
507 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
508 .build();
509 } else {
510 selector = DefaultTrafficSelector.builder()
511 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
512 .build();
513 }
514
515 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
516 .drop()
517 .build();
518
519 osNodeService.completeNodes().stream()
520 .filter(osNode -> osNode.type() == COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900521 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800522 osFlowRuleService.setRule(
523 appId,
524 osNode.intgBridge(),
525 selector,
526 treatment,
527 PRIORITY_ADMIN_RULE,
528 ACL_TABLE,
Jian Liea1b9662018-03-02 18:07:32 +0900529 install)
530 );
Frank Wangf9571662017-06-06 18:01:29 +0800531 }
532
Jian Li70a2c3f2018-04-13 17:26:31 +0900533 // TODO: need to be purged sooner or later
Frank Wangf9571662017-06-06 18:01:29 +0800534 private void setPortAdminRules(Port port, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900535 InstancePort instancePort =
536 instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
Frank Wangf9571662017-06-06 18:01:29 +0800537 TrafficSelector selector = DefaultTrafficSelector.builder()
538 .matchInPort(instancePort.portNumber())
539 .build();
540
541 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
542 .drop()
543 .build();
544
545 osFlowRuleService.setRule(
546 appId,
547 instancePort.deviceId(),
548 selector,
549 treatment,
550 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900551 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800552 install);
553 }
554
Jian Liea1b9662018-03-02 18:07:32 +0900555 /**
556 * Obtains the VLAN ID from the given instance port.
557 *
558 * @param instPort instance port object
559 * @return VLAN ID
560 */
daniel parka792cf72017-04-14 16:25:35 +0900561 private VlanId getVlanId(InstancePort instPort) {
562 Network osNet = osNetworkService.network(instPort.networkId());
563
564 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900565 final String error =
566 String.format(ERR_SET_FLOWS_VNI,
567 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900568 throw new IllegalStateException(error);
569 }
570
571 return VlanId.vlanId(osNet.getProviderSegID());
572 }
573
Jian Liea1b9662018-03-02 18:07:32 +0900574 /**
575 * Obtains the VNI from the given instance port.
576 *
577 * @param instPort instance port object
578 * @return VXLAN Network Identifier (VNI)
579 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900580 private Long getVni(InstancePort instPort) {
581 Network osNet = osNetworkService.network(instPort.networkId());
582 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900583 final String error =
584 String.format(ERR_SET_FLOWS_VNI,
585 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900586 throw new IllegalStateException(error);
587 }
588 return Long.valueOf(osNet.getProviderSegID());
589 }
590
Jian Liea1b9662018-03-02 18:07:32 +0900591 /**
592 * An internal instance port listener which listens the port events generated
593 * from VM. The corresponding L2 forwarding rules will be generated and
594 * inserted to integration bridge only if a new VM port is detected. If the
595 * existing detected VM port is removed due to VM purge, we will remove the
596 * corresponding L2 forwarding to as well for the sake of resource saving.
597 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 private class InternalInstancePortListener implements InstancePortListener {
599
600 @Override
601 public boolean isRelevant(InstancePortEvent event) {
602 InstancePort instPort = event.subject();
603 return mastershipService.isLocalMaster(instPort.deviceId());
604 }
605
606 @Override
607 public void event(InstancePortEvent event) {
608 InstancePort instPort = event.subject();
Jian Li9a921b42018-06-18 02:44:50 +0900609
Hyunsun Moon44aac662017-02-18 02:07:01 +0900610 switch (event.type()) {
611 case OPENSTACK_INSTANCE_PORT_UPDATED:
612 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li9a921b42018-06-18 02:44:50 +0900613 log.info("Instance port detected MAC:{} IP:{}",
614 instPort.macAddress(),
615 instPort.ipAddress());
616 eventExecutor.execute(() ->
617 instPortDetected(instPort)
618 );
619
Hyunsun Moon44aac662017-02-18 02:07:01 +0900620 break;
621 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li9a921b42018-06-18 02:44:50 +0900622 log.info("Instance port vanished MAC:{} IP:{}",
623 instPort.macAddress(),
624 instPort.ipAddress());
625 eventExecutor.execute(() ->
626 instPortRemoved(instPort)
627 );
628
Hyunsun Moon44aac662017-02-18 02:07:01 +0900629 break;
Jian Li9a921b42018-06-18 02:44:50 +0900630
631 // we do not consider MIGRATION_STARTED case, because the rules
632 // will be installed to corresponding switches at
633 // OPENSTACK_INSTANCE_PORT_UPDATED phase
634
635 // TODO: we may need to consider to refactor the VM migration
636 // event detection logic for better code readability
Jian Li24ec59f2018-05-23 19:01:25 +0900637 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li9a921b42018-06-18 02:44:50 +0900638 log.info("Instance port vanished MAC:{} IP:{}, " +
639 "due to VM migration", instPort.macAddress(),
640 instPort.ipAddress());
641 eventExecutor.execute(() ->
642 removeVportRules(instPort)
643 );
Jian Li24ec59f2018-05-23 19:01:25 +0900644 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900645 default:
646 break;
647 }
648 }
649
650 private void instPortDetected(InstancePort instPort) {
651 setNetworkRules(instPort, true);
652 // TODO add something else if needed
653 }
654
655 private void instPortRemoved(InstancePort instPort) {
656 setNetworkRules(instPort, false);
657 // TODO add something else if needed
658 }
659 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900660}