blob: 10b1776eae6e77f52ef2d0a6aba54ced92df5baa [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;
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 Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.openstacknode.OpenstackNodeService;
42import org.openstack4j.model.network.Network;
43import org.slf4j.Logger;
44
45import java.util.concurrent.ExecutorService;
46
47import static java.util.concurrent.Executors.newSingleThreadExecutor;
48import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090049import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
50import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
51import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
52import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
53import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
54import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moonacde3f52017-02-23 17:57:35 +090056import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import static org.slf4j.LoggerFactory.getLogger;
58
59
60/**
61 * Populates switching flow rules on OVS for the basic connectivity among the
62 * virtual instances in the same network.
63 */
64@Component(immediate = true)
65public final class OpenstackSwitchingHandler {
66
67 private final Logger log = getLogger(getClass());
68
69 private static final String ERR_SET_FLOWS = "Failed to set flows for %s: ";
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected MastershipService mastershipService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected DeviceService deviceService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +090081 protected OpenstackFlowRuleService osFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected InstancePortService instancePortService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected OpenstackNetworkService osNetworkService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected OpenstackNodeService osNodeService;
91
92 private final ExecutorService eventExecutor = newSingleThreadExecutor(
93 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
94 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
95 private ApplicationId appId;
96
97 @Activate
98 protected void activate() {
99 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
100 instancePortService.addListener(instancePortListener);
101
102 log.info("Started");
103 }
104
105 @Deactivate
106 protected void deactivate() {
107 instancePortService.removeListener(instancePortListener);
108 eventExecutor.shutdown();
109
110 log.info("Stopped");
111 }
112
113 private void setNetworkRules(InstancePort instPort, boolean install) {
daniel parka792cf72017-04-14 16:25:35 +0900114 switch (osNetworkService.network(instPort.networkId()).getNetworkType()) {
115 case VXLAN:
116 setTunnelTagFlowRules(instPort, install);
117 setForwardingRules(instPort, install);
118 break;
119 case VLAN:
120 setVlanTagFlowRules(instPort, install);
121 setForwardingRulesForVlan(instPort, install);
122 break;
123 default:
124 break;
125 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126 }
127
128 private void setForwardingRules(InstancePort instPort, boolean install) {
129 // switching rules for the instPorts in the same node
130 TrafficSelector selector = DefaultTrafficSelector.builder()
131 .matchEthType(Ethernet.TYPE_IPV4)
132 .matchIPDst(instPort.ipAddress().toIpPrefix())
133 .matchTunnelId(getVni(instPort))
134 .build();
135
136 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
137 .setEthDst(instPort.macAddress())
138 .setOutput(instPort.portNumber())
139 .build();
140
sanghodc375372017-06-08 10:41:30 +0900141 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 appId,
143 instPort.deviceId(),
144 selector,
145 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900147 FORWARDING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 install);
149
150 // switching rules for the instPorts in the remote node
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900151 osNodeService.completeNodes().stream()
152 .filter(osNode -> osNode.type() == COMPUTE)
153 .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
154 .forEach(osNode -> {
155 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
156 .extension(buildExtension(
157 deviceService,
158 osNode.intBridge(),
159 osNodeService.dataIp(instPort.deviceId()).get().getIp4Address()),
160 osNode.intBridge())
161 .setOutput(osNodeService.tunnelPort(osNode.intBridge()).get())
162 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163
sanghodc375372017-06-08 10:41:30 +0900164 osFlowRuleService.setRule(
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900165 appId,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 osNode.intBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900167 selector,
168 treatmentToRemote,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900169 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900170 FORWARDING_TABLE,
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900171 install);
172 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 }
174
daniel parka792cf72017-04-14 16:25:35 +0900175 private void setForwardingRulesForVlan(InstancePort instPort, boolean install) {
176 // switching rules for the instPorts in the same node
177 TrafficSelector selector = DefaultTrafficSelector.builder()
178 .matchEthType(Ethernet.TYPE_IPV4)
179 .matchIPDst(instPort.ipAddress().toIpPrefix())
180 .matchVlanId(getVlanId(instPort))
181 .build();
182
183 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
184 .popVlan()
185 .setEthDst(instPort.macAddress())
186 .setOutput(instPort.portNumber())
187 .build();
188
sanghodc375372017-06-08 10:41:30 +0900189 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900190 appId,
191 instPort.deviceId(),
192 selector,
193 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900194 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900195 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900196 install);
197
198 // switching rules for the instPorts in the remote node
199 osNodeService.completeNodes().stream()
200 .filter(osNode -> osNode.type() == COMPUTE)
201 .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
202 .filter(osNode -> osNode.vlanPort().isPresent())
203 .forEach(osNode -> {
204 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
205 .setOutput(osNodeService.vlanPort(osNode.intBridge()).get())
206 .build();
207
sanghodc375372017-06-08 10:41:30 +0900208 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900209 appId,
210 osNode.intBridge(),
211 selector,
212 treatmentToRemote,
daniel parka792cf72017-04-14 16:25:35 +0900213 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900214 FORWARDING_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900215 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))
sanghodc375372017-06-08 10:41:30 +0900228 .transition(ACL_TABLE)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900229 .build();
230
sanghodc375372017-06-08 10:41:30 +0900231 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900232 appId,
233 instPort.deviceId(),
234 selector,
235 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 PRIORITY_TUNNEL_TAG_RULE,
sanghodc375372017-06-08 10:41:30 +0900237 SRC_VNI_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 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))
sanghodc375372017-06-08 10:41:30 +0900250 .transition(ACL_TABLE)
daniel parka792cf72017-04-14 16:25:35 +0900251 .build();
252
sanghodc375372017-06-08 10:41:30 +0900253 osFlowRuleService.setRule(
daniel parka792cf72017-04-14 16:25:35 +0900254 appId,
255 instPort.deviceId(),
256 selector,
257 treatment,
daniel parka792cf72017-04-14 16:25:35 +0900258 PRIORITY_TUNNEL_TAG_RULE,
sanghodc375372017-06-08 10:41:30 +0900259 SRC_VNI_TABLE,
daniel parka792cf72017-04-14 16:25:35 +0900260 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}