blob: 975096f926c753dfdacc43410b010ed65f690b8a [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
2* Copyright 2016-present Open Networking Laboratory
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*/
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;
35import org.onosproject.net.flowobjective.FlowObjectiveService;
36import org.onosproject.net.flowobjective.ForwardingObjective;
37import org.onosproject.openstacknetworking.api.InstancePort;
38import org.onosproject.openstacknetworking.api.InstancePortEvent;
39import org.onosproject.openstacknetworking.api.InstancePortListener;
40import org.onosproject.openstacknetworking.api.InstancePortService;
41import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.openstacknode.OpenstackNodeService;
43import 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;
50import static org.onosproject.openstacknetworking.api.Constants.*;
51import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moonacde3f52017-02-23 17:57:35 +090052import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import static org.slf4j.LoggerFactory.getLogger;
54
55
56/**
57 * Populates switching flow rules on OVS for the basic connectivity among the
58 * virtual instances in the same network.
59 */
60@Component(immediate = true)
61public final class OpenstackSwitchingHandler {
62
63 private final Logger log = getLogger(getClass());
64
65 private static final String ERR_SET_FLOWS = "Failed to set flows for %s: ";
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected CoreService coreService;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected MastershipService mastershipService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected DeviceService deviceService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected FlowObjectiveService flowObjectiveService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected InstancePortService instancePortService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected OpenstackNetworkService osNetworkService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected OpenstackNodeService osNodeService;
87
88 private final ExecutorService eventExecutor = newSingleThreadExecutor(
89 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
90 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
91 private ApplicationId appId;
92
93 @Activate
94 protected void activate() {
95 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
96 instancePortService.addListener(instancePortListener);
97
98 log.info("Started");
99 }
100
101 @Deactivate
102 protected void deactivate() {
103 instancePortService.removeListener(instancePortListener);
104 eventExecutor.shutdown();
105
106 log.info("Stopped");
107 }
108
109 private void setNetworkRules(InstancePort instPort, boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900110 switch (osNetworkService.network(instPort.networkId()).getNetworkType()) {
111 case VXLAN:
112 setTunnelTagFlowRules(instPort, install);
113 setForwardingRules(instPort, install);
114 break;
115 case VLAN:
116 setVlanTagFlowRules(instPort, install);
117 setForwardingRulesForVlan(instPort, install);
118 break;
119 default:
120 break;
121 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 }
123
124 private void setForwardingRules(InstancePort instPort, boolean install) {
125 // switching rules for the instPorts in the same node
126 TrafficSelector selector = DefaultTrafficSelector.builder()
127 .matchEthType(Ethernet.TYPE_IPV4)
128 .matchIPDst(instPort.ipAddress().toIpPrefix())
129 .matchTunnelId(getVni(instPort))
130 .build();
131
132 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
133 .setEthDst(instPort.macAddress())
134 .setOutput(instPort.portNumber())
135 .build();
136
137 RulePopulatorUtil.setRule(
138 flowObjectiveService,
139 appId,
140 instPort.deviceId(),
141 selector,
142 treatment,
143 ForwardingObjective.Flag.SPECIFIC,
144 PRIORITY_SWITCHING_RULE,
145 install);
146
147 // switching rules for the instPorts in the remote node
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900148 osNodeService.completeNodes().stream()
149 .filter(osNode -> osNode.type() == COMPUTE)
150 .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
151 .forEach(osNode -> {
152 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
153 .extension(buildExtension(
154 deviceService,
155 osNode.intBridge(),
156 osNodeService.dataIp(instPort.deviceId()).get().getIp4Address()),
157 osNode.intBridge())
158 .setOutput(osNodeService.tunnelPort(osNode.intBridge()).get())
159 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900161 RulePopulatorUtil.setRule(
162 flowObjectiveService,
163 appId,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 osNode.intBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900165 selector,
166 treatmentToRemote,
167 ForwardingObjective.Flag.SPECIFIC,
168 PRIORITY_SWITCHING_RULE,
169 install);
170 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 }
172
daniel parka792cf72017-04-14 16:25:35 +0900173 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
174 // switching rules for the instPorts in the same node
175 TrafficSelector selector = DefaultTrafficSelector.builder()
176 .matchEthType(Ethernet.TYPE_IPV4)
177 .matchIPDst(instPort.ipAddress().toIpPrefix())
178 .matchVlanId(getVlanId(instPort))
179 .build();
180
181 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
182 .popVlan()
183 .setEthDst(instPort.macAddress())
184 .setOutput(instPort.portNumber())
185 .build();
186
187 RulePopulatorUtil.setRule(
188 flowObjectiveService,
189 appId,
190 instPort.deviceId(),
191 selector,
192 treatment,
193 ForwardingObjective.Flag.SPECIFIC,
194 PRIORITY_SWITCHING_RULE,
195 install);
196
197 // switching rules for the instPorts in the remote node
198 osNodeService.completeNodes().stream()
199 .filter(osNode -> osNode.type() == COMPUTE)
200 .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
201 .filter(osNode -> osNode.vlanPort().isPresent())
202 .forEach(osNode -> {
203 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
204 .setOutput(osNodeService.vlanPort(osNode.intBridge()).get())
205 .build();
206
207 RulePopulatorUtil.setRule(
208 flowObjectiveService,
209 appId,
210 osNode.intBridge(),
211 selector,
212 treatmentToRemote,
213 ForwardingObjective.Flag.SPECIFIC,
214 PRIORITY_SWITCHING_RULE,
215 install);
216 });
217
218 }
219
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
221 TrafficSelector selector = DefaultTrafficSelector.builder()
222 .matchEthType(Ethernet.TYPE_IPV4)
223 .matchInPort(instPort.portNumber())
224 .build();
225
226 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
227 .setTunnelId(getVni(instPort))
228 .build();
229
230 RulePopulatorUtil.setRule(
231 flowObjectiveService,
232 appId,
233 instPort.deviceId(),
234 selector,
235 treatment,
236 ForwardingObjective.Flag.SPECIFIC,
237 PRIORITY_TUNNEL_TAG_RULE,
238 install);
239 }
240
daniel parka792cf72017-04-14 16:25:35 +0900241 private void setVlanTagFlowRules(InstancePort instPort, boolean install) {
242 TrafficSelector selector = DefaultTrafficSelector.builder()
243 .matchEthType(Ethernet.TYPE_IPV4)
244 .matchInPort(instPort.portNumber())
245 .build();
246
247 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
248 .pushVlan()
249 .setVlanId(getVlanId(instPort))
250 .build();
251
252 RulePopulatorUtil.setRule(
253 flowObjectiveService,
254 appId,
255 instPort.deviceId(),
256 selector,
257 treatment,
258 ForwardingObjective.Flag.SPECIFIC,
259 PRIORITY_TUNNEL_TAG_RULE,
260 install);
261
262 }
263
264 private VlanId getVlanId(InstancePort instPort) {
265 Network osNet = osNetworkService.network(instPort.networkId());
266
267 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
268 final String error = String.format(
269 ERR_SET_FLOWS + "Failed to get VNI for %s",
270 instPort, osNet == null ? "<none>" : osNet.getName());
271 throw new IllegalStateException(error);
272 }
273
274 return VlanId.vlanId(osNet.getProviderSegID());
275 }
276
277
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 private Long getVni(InstancePort instPort) {
279 Network osNet = osNetworkService.network(instPort.networkId());
280 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
281 final String error = String.format(
282 ERR_SET_FLOWS + "Failed to get VNI for %s",
rohit8e5c8992017-03-29 19:15:30 +0530283 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 throw new IllegalStateException(error);
285 }
286 return Long.valueOf(osNet.getProviderSegID());
287 }
288
289 private class InternalInstancePortListener implements InstancePortListener {
290
291 @Override
292 public boolean isRelevant(InstancePortEvent event) {
293 InstancePort instPort = event.subject();
294 return mastershipService.isLocalMaster(instPort.deviceId());
295 }
296
297 @Override
298 public void event(InstancePortEvent event) {
299 InstancePort instPort = event.subject();
300 switch (event.type()) {
301 case OPENSTACK_INSTANCE_PORT_UPDATED:
302 case OPENSTACK_INSTANCE_PORT_DETECTED:
303 eventExecutor.execute(() -> {
304 log.info("Instance port detected MAC:{} IP:{}",
305 instPort.macAddress(),
306 instPort.ipAddress());
307 instPortDetected(event.subject());
308 });
309 break;
310 case OPENSTACK_INSTANCE_PORT_VANISHED:
311 eventExecutor.execute(() -> {
312 log.info("Instance port vanished MAC:{} IP:{}",
313 instPort.macAddress(),
314 instPort.ipAddress());
315 instPortRemoved(event.subject());
316 });
317 break;
318 default:
319 break;
320 }
321 }
322
323 private void instPortDetected(InstancePort instPort) {
324 setNetworkRules(instPort, true);
325 // TODO add something else if needed
326 }
327
328 private void instPortRemoved(InstancePort instPort) {
329 setNetworkRules(instPort, false);
330 // TODO add something else if needed
331 }
332 }
333}