blob: 48691019573f5e6025e1253526c413a116bec43c [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 Li70a2c3f2018-04-13 17:26:31 +090070import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Li26949762018-03-30 15:46:37 +090071import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090072import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import static org.slf4j.LoggerFactory.getLogger;
74
75
76/**
77 * Populates switching flow rules on OVS for the basic connectivity among the
78 * virtual instances in the same network.
79 */
80@Component(immediate = true)
81public final class OpenstackSwitchingHandler {
82
83 private final Logger log = getLogger(getClass());
84
Jian Li71670d12018-03-02 21:31:07 +090085 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 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090088 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090091 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090094 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090097 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900100 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900103 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900106 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107
sangho1aaa7882017-05-31 13:22:47 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900109 protected DriverService driverService;
sangho1aaa7882017-05-31 13:22:47 +0900110
sanghoe6457a32017-08-24 14:31:19 +0900111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900112 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900113
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 private final ExecutorService eventExecutor = newSingleThreadExecutor(
115 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
116 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
117 private ApplicationId appId;
118
119 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800120 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
122 instancePortService.addListener(instancePortListener);
123
124 log.info("Started");
125 }
126
127 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800128 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 instancePortService.removeListener(instancePortListener);
130 eventExecutor.shutdown();
131
132 log.info("Stopped");
133 }
134
Jian Liea1b9662018-03-02 18:07:32 +0900135 /**
136 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900137 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900138 *
139 * @param instPort instance port object
140 * @param install install flag, add the rule if true, remove it otherwise
141 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900143 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
144 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900145 case VXLAN:
146 setTunnelTagFlowRules(instPort, install);
147 setForwardingRules(instPort, install);
148 break;
149 case VLAN:
150 setVlanTagFlowRules(instPort, install);
151 setForwardingRulesForVlan(instPort, install);
152 break;
daniel park796c2eb2018-03-22 17:01:51 +0900153 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900154 setFlatJumpRules(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900155 setDownstreamRules(instPort, install);
156 setUpstreamRules(instPort, install);
157 break;
daniel parka792cf72017-04-14 16:25:35 +0900158 default:
Jian Liea1b9662018-03-02 18:07:32 +0900159 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900160 break;
161 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 }
163
Jian Li70a2c3f2018-04-13 17:26:31 +0900164 private void setFlatJumpRules(InstancePort port, boolean install) {
165 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
166 selector.matchInPort(port.portNumber());
167
168 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
169 treatment.transition(FLAT_TABLE);
170
171 osFlowRuleService.setRule(
172 appId,
173 port.deviceId(),
174 selector.build(),
175 treatment.build(),
Daniel Parkd1b14d32018-06-12 16:10:28 +0900176 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900177 DHCP_ARP_TABLE,
178 install);
179
180 Network network = osNetworkService.network(port.networkId());
181
182 if (network == null) {
183 log.warn("The network does not exist");
184 return;
185 }
Jian Li70a2c3f2018-04-13 17:26:31 +0900186 PortNumber portNumber = osNodeService.node(port.deviceId())
187 .phyIntfPortNum(network.getProviderPhyNet());
188
189 if (portNumber == null) {
190 log.warn("The port number does not exist");
191 return;
192 }
193
194 selector = DefaultTrafficSelector.builder();
Daniel Parkd1b14d32018-06-12 16:10:28 +0900195 selector.matchInPort(portNumber)
196 .matchEthType(Ethernet.TYPE_IPV4)
197 .matchIPDst(port.ipAddress().toIpPrefix());
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_DOWNSTREAM_RULE,
205 DHCP_ARP_TABLE,
206 install);
207
208 selector = DefaultTrafficSelector.builder();
209 selector.matchInPort(portNumber)
210 .matchEthType(Ethernet.TYPE_ARP)
211 .matchArpTpa(port.ipAddress().getIp4Address());
212
213 osFlowRuleService.setRule(
214 appId,
215 port.deviceId(),
216 selector.build(),
217 treatment.build(),
218 PRIORITY_FLAT_JUMP_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900219 DHCP_ARP_TABLE,
220 install);
221 }
222
daniel park796c2eb2018-03-22 17:01:51 +0900223 private void setDownstreamRules(InstancePort instPort, boolean install) {
224 TrafficSelector selector = DefaultTrafficSelector.builder()
225 .matchEthType(Ethernet.TYPE_IPV4)
226 .matchIPDst(instPort.ipAddress().toIpPrefix())
227 .build();
228 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
229 .setOutput(instPort.portNumber())
230 .build();
231
232 osFlowRuleService.setRule(
233 appId,
234 instPort.deviceId(),
235 selector,
236 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900237 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900238 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900239 install);
240
241 selector = DefaultTrafficSelector.builder()
242 .matchEthType(Ethernet.TYPE_ARP)
243 .matchArpTpa(instPort.ipAddress().getIp4Address())
244 .build();
245
246 osFlowRuleService.setRule(
247 appId,
248 instPort.deviceId(),
249 selector,
250 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900251 PRIORITY_FLAT_DOWNSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900252 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900253 install);
254 }
255
256 private void setUpstreamRules(InstancePort instPort, boolean install) {
257 TrafficSelector selector = DefaultTrafficSelector.builder()
258 .matchInPort(instPort.portNumber())
259 .build();
260
261 Network network = osNetworkService.network(instPort.networkId());
262
263 if (network == null) {
264 log.warn("The network does not exist");
265 return;
266 }
267
268 PortNumber portNumber = osNodeService.node(instPort.deviceId())
269 .phyIntfPortNum(network.getProviderPhyNet());
270
271 if (portNumber == null) {
272 log.warn("The port number does not exist");
273 return;
274 }
275
276 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
277 .setOutput(portNumber)
278 .build();
279
280 osFlowRuleService.setRule(
281 appId,
282 instPort.deviceId(),
283 selector,
284 treatment,
Daniel Parkd1b14d32018-06-12 16:10:28 +0900285 PRIORITY_FLAT_UPSTREAM_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900286 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900287 install);
288 }
289
290
Jian Liea1b9662018-03-02 18:07:32 +0900291 /**
292 * Configures the flow rules which are used for L2 packet switching.
293 * Note that these rules will be inserted in switching table (table 5).
294 *
295 * @param instPort instance port object
296 * @param install install flag, add the rule if true, remove it otherwise
297 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900298 private void setForwardingRules(InstancePort instPort, boolean install) {
299 // switching rules for the instPorts in the same node
300 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900301 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302 .matchEthType(Ethernet.TYPE_IPV4)
303 .matchIPDst(instPort.ipAddress().toIpPrefix())
304 .matchTunnelId(getVni(instPort))
305 .build();
306
307 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900308 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 .setEthDst(instPort.macAddress())
310 .setOutput(instPort.portNumber())
311 .build();
312
sanghodc375372017-06-08 10:41:30 +0900313 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314 appId,
315 instPort.deviceId(),
316 selector,
317 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900318 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900319 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320 install);
321
322 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900323 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
324 if (localNode == null) {
325 final String error = String.format("Cannot find openstack node for %s",
326 instPort.deviceId());
327 throw new IllegalStateException(error);
328 }
329 osNodeService.completeNodes(COMPUTE).stream()
330 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
331 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900332 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
333 .extension(buildExtension(
334 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900335 remoteNode.intgBridge(),
336 localNode.dataIp().getIp4Address()),
337 remoteNode.intgBridge())
338 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900339 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900340
sanghodc375372017-06-08 10:41:30 +0900341 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900342 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900343 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900344 selector,
345 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900346 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900347 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900348 install);
349 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900350 }
351
Jian Liea1b9662018-03-02 18:07:32 +0900352 /**
353 * Configures the flow rules which are used for L2 VLAN packet switching.
354 * Note that these rules will be inserted in switching table (table 5).
355 *
356 * @param instPort instance port object
357 * @param install install flag, add the rule if true, remove it otherwise
358 */
daniel parka792cf72017-04-14 16:25:35 +0900359 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
360 // switching rules for the instPorts in the same node
361 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900362 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900363 .matchEthType(Ethernet.TYPE_IPV4)
364 .matchIPDst(instPort.ipAddress().toIpPrefix())
365 .matchVlanId(getVlanId(instPort))
366 .build();
367
368 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
369 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900370 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900371 .setEthDst(instPort.macAddress())
372 .setOutput(instPort.portNumber())
373 .build();
374
sanghodc375372017-06-08 10:41:30 +0900375 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900376 appId,
377 instPort.deviceId(),
378 selector,
379 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900380 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900381 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900382 install);
383
384 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900385 osNodeService.completeNodes(COMPUTE).stream()
386 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
387 remoteNode.vlanIntf() != null)
388 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900389 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900390 .setEthDst(instPort.macAddress())
391 .setOutput(remoteNode.vlanPortNum())
392 .build();
daniel parka792cf72017-04-14 16:25:35 +0900393
sanghodc375372017-06-08 10:41:30 +0900394 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900395 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900396 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900397 selector,
398 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900399 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900400 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900401 install);
402 });
daniel parka792cf72017-04-14 16:25:35 +0900403 }
404
Jian Liea1b9662018-03-02 18:07:32 +0900405 /**
406 * Configures the flow rule which is for using VXLAN to tag the packet
407 * based on the in_port number of a virtual instance.
408 * Note that this rule will be inserted in VNI table (table 0).
409 *
410 * @param instPort instance port object
411 * @param install install flag, add the rule if true, remove it otherwise
412 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900413 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
414 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900415 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900416 .matchEthType(Ethernet.TYPE_IPV4)
417 .matchInPort(instPort.portNumber())
418 .build();
419
Jian Liea1b9662018-03-02 18:07:32 +0900420 // XXX All egress traffic needs to go through connection tracking module,
421 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900422 ExtensionTreatment ctTreatment =
423 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
424 .commit(true).build();
425
sanghoe6457a32017-08-24 14:31:19 +0900426 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900427 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900428 .transition(ACL_TABLE);
429
430 if (securityGroupService.isSecurityGroupEnabled()) {
431 tb.extension(ctTreatment, instPort.deviceId());
432 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900433
sanghodc375372017-06-08 10:41:30 +0900434 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900435 appId,
436 instPort.deviceId(),
437 selector,
sanghoe6457a32017-08-24 14:31:19 +0900438 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900439 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900440 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441 install);
442 }
443
Jian Liea1b9662018-03-02 18:07:32 +0900444 /**
445 * Configures the flow rule which is for using VLAN to tag the packet
446 * based on the in_port number of a virtual instance.
447 * Note that this rule will be inserted in VNI table (table 0).
448 *
449 * @param instPort instance port object
450 * @param install install flag, add the rule if true, remove it otherwise
451 */
daniel parka792cf72017-04-14 16:25:35 +0900452 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
453 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900454 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900455 .matchEthType(Ethernet.TYPE_IPV4)
456 .matchInPort(instPort.portNumber())
457 .build();
458
459 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
460 .pushVlan()
461 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900462 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900463 .build();
464
sanghodc375372017-06-08 10:41:30 +0900465 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900466 appId,
467 instPort.deviceId(),
468 selector,
469 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900470 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900471 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900472 install);
daniel parka792cf72017-04-14 16:25:35 +0900473 }
474
Frank Wangf9571662017-06-06 18:01:29 +0800475 private void setNetworkAdminRules(Network network, boolean install) {
476 TrafficSelector selector;
477 if (network.getNetworkType() == NetworkType.VXLAN) {
478
479 selector = DefaultTrafficSelector.builder()
480 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
481 .build();
482 } else {
483 selector = DefaultTrafficSelector.builder()
484 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
485 .build();
486 }
487
488 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
489 .drop()
490 .build();
491
492 osNodeService.completeNodes().stream()
493 .filter(osNode -> osNode.type() == COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900494 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800495 osFlowRuleService.setRule(
496 appId,
497 osNode.intgBridge(),
498 selector,
499 treatment,
500 PRIORITY_ADMIN_RULE,
501 ACL_TABLE,
Jian Liea1b9662018-03-02 18:07:32 +0900502 install)
503 );
Frank Wangf9571662017-06-06 18:01:29 +0800504 }
505
Jian Li70a2c3f2018-04-13 17:26:31 +0900506 // TODO: need to be purged sooner or later
Frank Wangf9571662017-06-06 18:01:29 +0800507 private void setPortAdminRules(Port port, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900508 InstancePort instancePort =
509 instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
Frank Wangf9571662017-06-06 18:01:29 +0800510 TrafficSelector selector = DefaultTrafficSelector.builder()
511 .matchInPort(instancePort.portNumber())
512 .build();
513
514 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
515 .drop()
516 .build();
517
518 osFlowRuleService.setRule(
519 appId,
520 instancePort.deviceId(),
521 selector,
522 treatment,
523 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900524 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800525 install);
526 }
527
Jian Liea1b9662018-03-02 18:07:32 +0900528 /**
529 * Obtains the VLAN ID from the given instance port.
530 *
531 * @param instPort instance port object
532 * @return VLAN ID
533 */
daniel parka792cf72017-04-14 16:25:35 +0900534 private VlanId getVlanId(InstancePort instPort) {
535 Network osNet = osNetworkService.network(instPort.networkId());
536
537 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900538 final String error =
539 String.format(ERR_SET_FLOWS_VNI,
540 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900541 throw new IllegalStateException(error);
542 }
543
544 return VlanId.vlanId(osNet.getProviderSegID());
545 }
546
Jian Liea1b9662018-03-02 18:07:32 +0900547 /**
548 * Obtains the VNI from the given instance port.
549 *
550 * @param instPort instance port object
551 * @return VXLAN Network Identifier (VNI)
552 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900553 private Long getVni(InstancePort instPort) {
554 Network osNet = osNetworkService.network(instPort.networkId());
555 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900556 final String error =
557 String.format(ERR_SET_FLOWS_VNI,
558 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 throw new IllegalStateException(error);
560 }
561 return Long.valueOf(osNet.getProviderSegID());
562 }
563
Jian Liea1b9662018-03-02 18:07:32 +0900564 /**
565 * An internal instance port listener which listens the port events generated
566 * from VM. The corresponding L2 forwarding rules will be generated and
567 * inserted to integration bridge only if a new VM port is detected. If the
568 * existing detected VM port is removed due to VM purge, we will remove the
569 * corresponding L2 forwarding to as well for the sake of resource saving.
570 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900571 private class InternalInstancePortListener implements InstancePortListener {
572
573 @Override
574 public boolean isRelevant(InstancePortEvent event) {
575 InstancePort instPort = event.subject();
576 return mastershipService.isLocalMaster(instPort.deviceId());
577 }
578
579 @Override
580 public void event(InstancePortEvent event) {
581 InstancePort instPort = event.subject();
582 switch (event.type()) {
583 case OPENSTACK_INSTANCE_PORT_UPDATED:
584 case OPENSTACK_INSTANCE_PORT_DETECTED:
585 eventExecutor.execute(() -> {
586 log.info("Instance port detected MAC:{} IP:{}",
587 instPort.macAddress(),
588 instPort.ipAddress());
589 instPortDetected(event.subject());
590 });
591 break;
592 case OPENSTACK_INSTANCE_PORT_VANISHED:
593 eventExecutor.execute(() -> {
594 log.info("Instance port vanished MAC:{} IP:{}",
595 instPort.macAddress(),
596 instPort.ipAddress());
597 instPortRemoved(event.subject());
598 });
599 break;
600 default:
601 break;
602 }
603 }
604
605 private void instPortDetected(InstancePort instPort) {
606 setNetworkRules(instPort, true);
607 // TODO add something else if needed
608 }
609
610 private void instPortRemoved(InstancePort instPort) {
611 setNetworkRules(instPort, false);
612 // TODO add something else if needed
613 }
614 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900615}