blob: 837025085b402160c44f089a91d08a73fc18f971 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002* Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003*
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*/
16
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;
daniel parka792cf72017-04-14 16:25:35 +090026import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.mastership.MastershipService;
30import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.flow.DefaultTrafficSelector;
32import org.onosproject.net.flow.DefaultTrafficTreatment;
33import org.onosproject.net.flow.TrafficSelector;
34import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090035import org.onosproject.openstacknetworking.api.InstancePort;
36import org.onosproject.openstacknetworking.api.InstancePortEvent;
37import org.onosproject.openstacknetworking.api.InstancePortListener;
38import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090039import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090041import org.onosproject.openstacknode.api.OpenstackNode;
42import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.openstack4j.model.network.Network;
44import org.slf4j.Logger;
45
46import java.util.concurrent.ExecutorService;
47
48import static java.util.concurrent.Executors.newSingleThreadExecutor;
49import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090050import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
51import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
52import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
53import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
54import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
55import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090057import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import static org.slf4j.LoggerFactory.getLogger;
59
60
61/**
62 * Populates switching flow rules on OVS for the basic connectivity among the
63 * virtual instances in the same network.
64 */
65@Component(immediate = true)
66public final class OpenstackSwitchingHandler {
67
68 private final Logger log = getLogger(getClass());
69
70 private static final String ERR_SET_FLOWS = "Failed to set flows for %s: ";
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected CoreService coreService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected MastershipService mastershipService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected DeviceService deviceService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +090082 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected InstancePortService instancePortService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected OpenstackNetworkService osNetworkService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected OpenstackNodeService osNodeService;
92
93 private final ExecutorService eventExecutor = newSingleThreadExecutor(
94 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
95 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
96 private ApplicationId appId;
97
98 @Activate
99 protected void activate() {
100 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
101 instancePortService.addListener(instancePortListener);
102
103 log.info("Started");
104 }
105
106 @Deactivate
107 protected void deactivate() {
108 instancePortService.removeListener(instancePortListener);
109 eventExecutor.shutdown();
110
111 log.info("Stopped");
112 }
113
114 private void setNetworkRules(InstancePort instPort, boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900115 switch (osNetworkService.network(instPort.networkId()).getNetworkType()) {
116 case VXLAN:
117 setTunnelTagFlowRules(instPort, install);
118 setForwardingRules(instPort, install);
119 break;
120 case VLAN:
121 setVlanTagFlowRules(instPort, install);
122 setForwardingRulesForVlan(instPort, install);
123 break;
124 default:
125 break;
126 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127 }
128
129 private void setForwardingRules(InstancePort instPort, boolean install) {
130 // switching rules for the instPorts in the same node
131 TrafficSelector selector = DefaultTrafficSelector.builder()
132 .matchEthType(Ethernet.TYPE_IPV4)
133 .matchIPDst(instPort.ipAddress().toIpPrefix())
134 .matchTunnelId(getVni(instPort))
135 .build();
136
137 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
138 .setEthDst(instPort.macAddress())
139 .setOutput(instPort.portNumber())
140 .build();
141
sanghodc375372017-06-08 10:41:30 +0900142 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 appId,
144 instPort.deviceId(),
145 selector,
146 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900148 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 install);
150
151 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900152 OpenstackNode localNode = osNodeService.node(instPort.deviceId());
153 if (localNode == null) {
154 final String error = String.format("Cannot find openstack node for %s",
155 instPort.deviceId());
156 throw new IllegalStateException(error);
157 }
158 osNodeService.completeNodes(COMPUTE).stream()
159 .filter(remoteNode -> !remoteNode.intgBridge().equals(localNode.intgBridge()))
160 .forEach(remoteNode -> {
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900161 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
162 .extension(buildExtension(
163 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900164 remoteNode.intgBridge(),
165 localNode.dataIp().getIp4Address()),
166 remoteNode.intgBridge())
167 .setOutput(remoteNode.tunnelPortNum())
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900168 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169
sanghodc375372017-06-08 10:41:30 +0900170 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900171 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900172 remoteNode.intgBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900173 selector,
174 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900175 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900176 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900177 install);
178 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 }
180
daniel parka792cf72017-04-14 16:25:35 +0900181 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
182 // switching rules for the instPorts in the same node
183 TrafficSelector selector = DefaultTrafficSelector.builder()
184 .matchEthType(Ethernet.TYPE_IPV4)
185 .matchIPDst(instPort.ipAddress().toIpPrefix())
186 .matchVlanId(getVlanId(instPort))
187 .build();
188
189 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
190 .popVlan()
191 .setEthDst(instPort.macAddress())
192 .setOutput(instPort.portNumber())
193 .build();
194
sanghodc375372017-06-08 10:41:30 +0900195 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900196 appId,
197 instPort.deviceId(),
198 selector,
199 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900200 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900201 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900202 install);
203
204 // switching rules for the instPorts in the remote node
Hyunsun Moon0d457362017-06-27 17:19:41 +0900205 osNodeService.completeNodes(COMPUTE).stream()
206 .filter(remoteNode -> !remoteNode.intgBridge().equals(instPort.deviceId()) &&
207 remoteNode.vlanIntf() != null)
208 .forEach(remoteNode -> {
daniel parka792cf72017-04-14 16:25:35 +0900209 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900210 .setOutput(remoteNode.vlanPortNum())
daniel parka792cf72017-04-14 16:25:35 +0900211 .build();
212
sanghodc375372017-06-08 10:41:30 +0900213 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900214 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900215 remoteNode.intgBridge(),
daniel parka792cf72017-04-14 16:25:35 +0900216 selector,
217 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900218 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900219 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900220 install);
221 });
daniel parka792cf72017-04-14 16:25:35 +0900222 }
223
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
225 TrafficSelector selector = DefaultTrafficSelector.builder()
226 .matchEthType(Ethernet.TYPE_IPV4)
227 .matchInPort(instPort.portNumber())
228 .build();
229
230 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
231 .setTunnelId(getVni(instPort))
sanghodc375372017-06-08 10:41:30 +0900232 .transition(ACL_TABLE)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 .build();
234
sanghodc375372017-06-08 10:41:30 +0900235 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 appId,
237 instPort.deviceId(),
238 selector,
239 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900240 PRIORITY_TUNNEL_TAG_RULE,
sanghodc375372017-06-08 10:41:30 +0900241 SRC_VNI_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900242 install);
243 }
244
daniel parka792cf72017-04-14 16:25:35 +0900245 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
246 TrafficSelector selector = DefaultTrafficSelector.builder()
247 .matchEthType(Ethernet.TYPE_IPV4)
248 .matchInPort(instPort.portNumber())
249 .build();
250
251 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
252 .pushVlan()
253 .setVlanId(getVlanId(instPort))
sanghodc375372017-06-08 10:41:30 +0900254 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900255 .build();
256
sanghodc375372017-06-08 10:41:30 +0900257 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900258 appId,
259 instPort.deviceId(),
260 selector,
261 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900262 PRIORITY_TUNNEL_TAG_RULE,
sanghodc375372017-06-08 10:41:30 +0900263 SRC_VNI_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900264 install);
265
266 }
267
268 private VlanId getVlanId(InstancePort instPort) {
269 Network osNet = osNetworkService.network(instPort.networkId());
270
271 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
272 final String error = String.format(
273 ERR_SET_FLOWS + "Failed to get VNI for %s",
274 instPort, osNet == null ? "<none>" : osNet.getName());
275 throw new IllegalStateException(error);
276 }
277
278 return VlanId.vlanId(osNet.getProviderSegID());
279 }
280
281
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 private Long getVni(InstancePort instPort) {
283 Network osNet = osNetworkService.network(instPort.networkId());
284 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
285 final String error = String.format(
286 ERR_SET_FLOWS + "Failed to get VNI for %s",
rohit8e5c8992017-03-29 19:15:30 +0530287 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 throw new IllegalStateException(error);
289 }
290 return Long.valueOf(osNet.getProviderSegID());
291 }
292
293 private class InternalInstancePortListener implements InstancePortListener {
294
295 @Override
296 public boolean isRelevant(InstancePortEvent event) {
297 InstancePort instPort = event.subject();
298 return mastershipService.isLocalMaster(instPort.deviceId());
299 }
300
301 @Override
302 public void event(InstancePortEvent event) {
303 InstancePort instPort = event.subject();
304 switch (event.type()) {
305 case OPENSTACK_INSTANCE_PORT_UPDATED:
306 case OPENSTACK_INSTANCE_PORT_DETECTED:
307 eventExecutor.execute(() -> {
308 log.info("Instance port detected MAC:{} IP:{}",
309 instPort.macAddress(),
310 instPort.ipAddress());
311 instPortDetected(event.subject());
312 });
313 break;
314 case OPENSTACK_INSTANCE_PORT_VANISHED:
315 eventExecutor.execute(() -> {
316 log.info("Instance port vanished MAC:{} IP:{}",
317 instPort.macAddress(),
318 instPort.ipAddress());
319 instPortRemoved(event.subject());
320 });
321 break;
322 default:
323 break;
324 }
325 }
326
327 private void instPortDetected(InstancePort instPort) {
328 setNetworkRules(instPort, true);
329 // TODO add something else if needed
330 }
331
332 private void instPortRemoved(InstancePort instPort) {
333 setNetworkRules(instPort, false);
334 // TODO add something else if needed
335 }
336 }
337}