blob: 4fb03a28ec80e66ac6b8b51dac9a1917d90e4c53 [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 park796c2eb2018-03-22 17:01:51 +090064import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_RULE;
sanghodc375372017-06-08 10:41:30 +090065import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
66import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
Jian Li70a2c3f2018-04-13 17:26:31 +090067import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
Jian Li26949762018-03-30 15:46:37 +090068import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090069import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090070import static org.slf4j.LoggerFactory.getLogger;
71
72
73/**
74 * Populates switching flow rules on OVS for the basic connectivity among the
75 * virtual instances in the same network.
76 */
77@Component(immediate = true)
78public final class OpenstackSwitchingHandler {
79
80 private final Logger log = getLogger(getClass());
81
Jian Li71670d12018-03-02 21:31:07 +090082 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 +090083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090085 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090088 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090091 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090094 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +090097 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900100 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900103 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
sangho1aaa7882017-05-31 13:22:47 +0900105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900106 protected DriverService driverService;
sangho1aaa7882017-05-31 13:22:47 +0900107
sanghoe6457a32017-08-24 14:31:19 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liea1b9662018-03-02 18:07:32 +0900109 protected OpenstackSecurityGroupService securityGroupService;
sanghoe6457a32017-08-24 14:31:19 +0900110
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 private final ExecutorService eventExecutor = newSingleThreadExecutor(
112 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
113 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
114 private ApplicationId appId;
115
116 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800117 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
119 instancePortService.addListener(instancePortListener);
120
121 log.info("Started");
122 }
123
124 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800125 void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126 instancePortService.removeListener(instancePortListener);
127 eventExecutor.shutdown();
128
129 log.info("Stopped");
130 }
131
Jian Liea1b9662018-03-02 18:07:32 +0900132 /**
133 * Configures L2 forwarding rules.
daniel park796c2eb2018-03-22 17:01:51 +0900134 * Currently, SONA supports Flat, VXLAN and VLAN modes.
Jian Liea1b9662018-03-02 18:07:32 +0900135 *
136 * @param instPort instance port object
137 * @param install install flag, add the rule if true, remove it otherwise
138 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 private void setNetworkRules(InstancePort instPort, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900140 NetworkType type = osNetworkService.network(instPort.networkId()).getNetworkType();
141 switch (type) {
daniel parka792cf72017-04-14 16:25:35 +0900142 case VXLAN:
143 setTunnelTagFlowRules(instPort, install);
144 setForwardingRules(instPort, install);
145 break;
146 case VLAN:
147 setVlanTagFlowRules(instPort, install);
148 setForwardingRulesForVlan(instPort, install);
149 break;
daniel park796c2eb2018-03-22 17:01:51 +0900150 case FLAT:
Jian Li70a2c3f2018-04-13 17:26:31 +0900151 setFlatJumpRules(instPort, install);
daniel park796c2eb2018-03-22 17:01:51 +0900152 setDownstreamRules(instPort, install);
153 setUpstreamRules(instPort, install);
154 break;
daniel parka792cf72017-04-14 16:25:35 +0900155 default:
Jian Liea1b9662018-03-02 18:07:32 +0900156 log.warn("Unsupported network tunnel type {}", type.name());
daniel parka792cf72017-04-14 16:25:35 +0900157 break;
158 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 }
160
Jian Li70a2c3f2018-04-13 17:26:31 +0900161 private void setFlatJumpRules(InstancePort port, boolean install) {
162 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
163 selector.matchInPort(port.portNumber());
164
165 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
166 treatment.transition(FLAT_TABLE);
167
168 osFlowRuleService.setRule(
169 appId,
170 port.deviceId(),
171 selector.build(),
172 treatment.build(),
173 PRIORITY_FLAT_RULE,
174 DHCP_ARP_TABLE,
175 install);
176
177 Network network = osNetworkService.network(port.networkId());
178
179 if (network == null) {
180 log.warn("The network does not exist");
181 return;
182 }
183
184 PortNumber portNumber = osNodeService.node(port.deviceId())
185 .phyIntfPortNum(network.getProviderPhyNet());
186
187 if (portNumber == null) {
188 log.warn("The port number does not exist");
189 return;
190 }
191
192 selector = DefaultTrafficSelector.builder();
193 selector.matchInPort(portNumber);
194
195 osFlowRuleService.setRule(
196 appId,
197 port.deviceId(),
198 selector.build(),
199 treatment.build(),
200 PRIORITY_FLAT_RULE,
201 DHCP_ARP_TABLE,
202 install);
203 }
204
daniel park796c2eb2018-03-22 17:01:51 +0900205 private void setDownstreamRules(InstancePort instPort, boolean install) {
206 TrafficSelector selector = DefaultTrafficSelector.builder()
207 .matchEthType(Ethernet.TYPE_IPV4)
208 .matchIPDst(instPort.ipAddress().toIpPrefix())
209 .build();
210 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
211 .setOutput(instPort.portNumber())
212 .build();
213
214 osFlowRuleService.setRule(
215 appId,
216 instPort.deviceId(),
217 selector,
218 treatment,
219 PRIORITY_FLAT_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900220 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900221 install);
222
223 selector = DefaultTrafficSelector.builder()
224 .matchEthType(Ethernet.TYPE_ARP)
225 .matchArpTpa(instPort.ipAddress().getIp4Address())
226 .build();
227
228 osFlowRuleService.setRule(
229 appId,
230 instPort.deviceId(),
231 selector,
232 treatment,
233 PRIORITY_FLAT_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900234 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900235 install);
236 }
237
238 private void setUpstreamRules(InstancePort instPort, boolean install) {
239 TrafficSelector selector = DefaultTrafficSelector.builder()
240 .matchInPort(instPort.portNumber())
241 .build();
242
243 Network network = osNetworkService.network(instPort.networkId());
244
245 if (network == null) {
246 log.warn("The network does not exist");
247 return;
248 }
249
250 PortNumber portNumber = osNodeService.node(instPort.deviceId())
251 .phyIntfPortNum(network.getProviderPhyNet());
252
253 if (portNumber == null) {
254 log.warn("The port number does not exist");
255 return;
256 }
257
258 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
259 .setOutput(portNumber)
260 .build();
261
262 osFlowRuleService.setRule(
263 appId,
264 instPort.deviceId(),
265 selector,
266 treatment,
267 PRIORITY_FLAT_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900268 FLAT_TABLE,
daniel park796c2eb2018-03-22 17:01:51 +0900269 install);
270 }
271
272
Jian Liea1b9662018-03-02 18:07:32 +0900273 /**
274 * Configures the flow rules which are used for L2 packet switching.
275 * Note that these rules will be inserted in switching table (table 5).
276 *
277 * @param instPort instance port object
278 * @param install install flag, add the rule if true, remove it otherwise
279 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 private void setForwardingRules(InstancePort instPort, boolean install) {
281 // switching rules for the instPorts in the same node
282 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900283 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 .matchEthType(Ethernet.TYPE_IPV4)
285 .matchIPDst(instPort.ipAddress().toIpPrefix())
286 .matchTunnelId(getVni(instPort))
287 .build();
288
289 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900290 // TODO: this might not be necessary for the VMs located in the same subnet
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 .setEthDst(instPort.macAddress())
292 .setOutput(instPort.portNumber())
293 .build();
294
sanghodc375372017-06-08 10:41:30 +0900295 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 appId,
297 instPort.deviceId(),
298 selector,
299 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900300 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900301 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302 install);
303
304 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900305 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
306 if (localNode == null) {
307 final String error = String.format("Cannot find openstack node for %s",
308 instPort.deviceId());
309 throw new IllegalStateException(error);
310 }
311 osNodeService.completeNodes(COMPUTE).stream()
312 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
313 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900314 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
315 .extension(buildExtension(
316 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900317 remoteNode.intgBridge(),
318 localNode.dataIp().getIp4Address()),
319 remoteNode.intgBridge())
320 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900321 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900322
sanghodc375372017-06-08 10:41:30 +0900323 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900324 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900325 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900326 selector,
327 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900328 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900329 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900330 install);
331 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900332 }
333
Jian Liea1b9662018-03-02 18:07:32 +0900334 /**
335 * Configures the flow rules which are used for L2 VLAN packet switching.
336 * Note that these rules will be inserted in switching table (table 5).
337 *
338 * @param instPort instance port object
339 * @param install install flag, add the rule if true, remove it otherwise
340 */
daniel parka792cf72017-04-14 16:25:35 +0900341 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
342 // switching rules for the instPorts in the same node
343 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900344 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900345 .matchEthType(Ethernet.TYPE_IPV4)
346 .matchIPDst(instPort.ipAddress().toIpPrefix())
347 .matchVlanId(getVlanId(instPort))
348 .build();
349
350 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
351 .popVlan()
Jian Liea1b9662018-03-02 18:07:32 +0900352 // TODO: this might not be necessary for the VMs located in the same subnet
daniel parka792cf72017-04-14 16:25:35 +0900353 .setEthDst(instPort.macAddress())
354 .setOutput(instPort.portNumber())
355 .build();
356
sanghodc375372017-06-08 10:41:30 +0900357 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900358 appId,
359 instPort.deviceId(),
360 selector,
361 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900362 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900363 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900364 install);
365
366 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900367 osNodeService.completeNodes(COMPUTE).stream()
368 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
369 remoteNode.vlanIntf() != null)
370 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900371 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900372 .setEthDst(instPort.macAddress())
373 .setOutput(remoteNode.vlanPortNum())
374 .build();
daniel parka792cf72017-04-14 16:25:35 +0900375
sanghodc375372017-06-08 10:41:30 +0900376 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900377 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900378 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900379 selector,
380 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900381 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900382 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900383 install);
384 });
daniel parka792cf72017-04-14 16:25:35 +0900385 }
386
Jian Liea1b9662018-03-02 18:07:32 +0900387 /**
388 * Configures the flow rule which is for using VXLAN to tag the packet
389 * based on the in_port number of a virtual instance.
390 * Note that this rule will be inserted in VNI table (table 0).
391 *
392 * @param instPort instance port object
393 * @param install install flag, add the rule if true, remove it otherwise
394 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900395 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
396 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900397 // TODO: need to handle IPv6 in near future
Hyunsun Moon44aac662017-02-18 02:07:01 +0900398 .matchEthType(Ethernet.TYPE_IPV4)
399 .matchInPort(instPort.portNumber())
400 .build();
401
Jian Liea1b9662018-03-02 18:07:32 +0900402 // XXX All egress traffic needs to go through connection tracking module,
403 // which might hurt its performance.
sangho1aaa7882017-05-31 13:22:47 +0900404 ExtensionTreatment ctTreatment =
405 RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
406 .commit(true).build();
407
sanghoe6457a32017-08-24 14:31:19 +0900408 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900409 .setTunnelId(getVni(instPort))
sanghoe6457a32017-08-24 14:31:19 +0900410 .transition(ACL_TABLE);
411
412 if (securityGroupService.isSecurityGroupEnabled()) {
413 tb.extension(ctTreatment, instPort.deviceId());
414 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900415
sanghodc375372017-06-08 10:41:30 +0900416 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900417 appId,
418 instPort.deviceId(),
419 selector,
sanghoe6457a32017-08-24 14:31:19 +0900420 tb.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900421 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900422 VTAG_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900423 install);
424 }
425
Jian Liea1b9662018-03-02 18:07:32 +0900426 /**
427 * Configures the flow rule which is for using VLAN to tag the packet
428 * based on the in_port number of a virtual instance.
429 * Note that this rule will be inserted in VNI table (table 0).
430 *
431 * @param instPort instance port object
432 * @param install install flag, add the rule if true, remove it otherwise
433 */
daniel parka792cf72017-04-14 16:25:35 +0900434 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
435 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Liea1b9662018-03-02 18:07:32 +0900436 // TODO: need to handle IPv6 in near future
daniel parka792cf72017-04-14 16:25:35 +0900437 .matchEthType(Ethernet.TYPE_IPV4)
438 .matchInPort(instPort.portNumber())
439 .build();
440
441 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
442 .pushVlan()
443 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900444 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900445 .build();
446
sanghodc375372017-06-08 10:41:30 +0900447 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900448 appId,
449 instPort.deviceId(),
450 selector,
451 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900452 PRIORITY_TUNNEL_TAG_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900453 VTAG_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900454 install);
daniel parka792cf72017-04-14 16:25:35 +0900455 }
456
Frank Wangf9571662017-06-06 18:01:29 +0800457 private void setNetworkAdminRules(Network network, boolean install) {
458 TrafficSelector selector;
459 if (network.getNetworkType() == NetworkType.VXLAN) {
460
461 selector = DefaultTrafficSelector.builder()
462 .matchTunnelId(Long.valueOf(network.getProviderSegID()))
463 .build();
464 } else {
465 selector = DefaultTrafficSelector.builder()
466 .matchVlanId(VlanId.vlanId(network.getProviderSegID()))
467 .build();
468 }
469
470 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
471 .drop()
472 .build();
473
474 osNodeService.completeNodes().stream()
475 .filter(osNode -> osNode.type() == COMPUTE)
Jian Liea1b9662018-03-02 18:07:32 +0900476 .forEach(osNode ->
Frank Wangf9571662017-06-06 18:01:29 +0800477 osFlowRuleService.setRule(
478 appId,
479 osNode.intgBridge(),
480 selector,
481 treatment,
482 PRIORITY_ADMIN_RULE,
483 ACL_TABLE,
Jian Liea1b9662018-03-02 18:07:32 +0900484 install)
485 );
Frank Wangf9571662017-06-06 18:01:29 +0800486 }
487
Jian Li70a2c3f2018-04-13 17:26:31 +0900488 // TODO: need to be purged sooner or later
Frank Wangf9571662017-06-06 18:01:29 +0800489 private void setPortAdminRules(Port port, boolean install) {
Jian Liea1b9662018-03-02 18:07:32 +0900490 InstancePort instancePort =
491 instancePortService.instancePort(MacAddress.valueOf(port.getMacAddress()));
Frank Wangf9571662017-06-06 18:01:29 +0800492 TrafficSelector selector = DefaultTrafficSelector.builder()
493 .matchInPort(instancePort.portNumber())
494 .build();
495
496 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
497 .drop()
498 .build();
499
500 osFlowRuleService.setRule(
501 appId,
502 instancePort.deviceId(),
503 selector,
504 treatment,
505 PRIORITY_ADMIN_RULE,
Jian Li70a2c3f2018-04-13 17:26:31 +0900506 VTAG_TABLE,
Frank Wangf9571662017-06-06 18:01:29 +0800507 install);
508 }
509
Jian Liea1b9662018-03-02 18:07:32 +0900510 /**
511 * Obtains the VLAN ID from the given instance port.
512 *
513 * @param instPort instance port object
514 * @return VLAN ID
515 */
daniel parka792cf72017-04-14 16:25:35 +0900516 private VlanId getVlanId(InstancePort instPort) {
517 Network osNet = osNetworkService.network(instPort.networkId());
518
519 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
Jian Li71670d12018-03-02 21:31:07 +0900520 final String error =
521 String.format(ERR_SET_FLOWS_VNI,
522 instPort, osNet == null ? "<none>" : osNet.getName());
daniel parka792cf72017-04-14 16:25:35 +0900523 throw new IllegalStateException(error);
524 }
525
526 return VlanId.vlanId(osNet.getProviderSegID());
527 }
528
Jian Liea1b9662018-03-02 18:07:32 +0900529 /**
530 * Obtains the VNI from the given instance port.
531 *
532 * @param instPort instance port object
533 * @return VXLAN Network Identifier (VNI)
534 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900535 private Long getVni(InstancePort instPort) {
536 Network osNet = osNetworkService.network(instPort.networkId());
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());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900541 throw new IllegalStateException(error);
542 }
543 return Long.valueOf(osNet.getProviderSegID());
544 }
545
Jian Liea1b9662018-03-02 18:07:32 +0900546 /**
547 * An internal instance port listener which listens the port events generated
548 * from VM. The corresponding L2 forwarding rules will be generated and
549 * inserted to integration bridge only if a new VM port is detected. If the
550 * existing detected VM port is removed due to VM purge, we will remove the
551 * corresponding L2 forwarding to as well for the sake of resource saving.
552 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900553 private class InternalInstancePortListener implements InstancePortListener {
554
555 @Override
556 public boolean isRelevant(InstancePortEvent event) {
557 InstancePort instPort = event.subject();
558 return mastershipService.isLocalMaster(instPort.deviceId());
559 }
560
561 @Override
562 public void event(InstancePortEvent event) {
563 InstancePort instPort = event.subject();
564 switch (event.type()) {
565 case OPENSTACK_INSTANCE_PORT_UPDATED:
566 case OPENSTACK_INSTANCE_PORT_DETECTED:
567 eventExecutor.execute(() -> {
568 log.info("Instance port detected MAC:{} IP:{}",
569 instPort.macAddress(),
570 instPort.ipAddress());
571 instPortDetected(event.subject());
572 });
573 break;
574 case OPENSTACK_INSTANCE_PORT_VANISHED:
575 eventExecutor.execute(() -> {
576 log.info("Instance port vanished MAC:{} IP:{}",
577 instPort.macAddress(),
578 instPort.ipAddress());
579 instPortRemoved(event.subject());
580 });
581 break;
582 default:
583 break;
584 }
585 }
586
587 private void instPortDetected(InstancePort instPort) {
588 setNetworkRules(instPort, true);
589 // TODO add something else if needed
590 }
591
592 private void instPortRemoved(InstancePort instPort) {
593 setNetworkRules(instPort, false);
594 // TODO add something else if needed
595 }
596 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900597}