blob: b66ffa27dd7f42b01d9f07cb0821e8d8dae0d196 [file] [log] [blame]
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001/*
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -07002* 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
Hyunsun Moonb974fca2016-06-30 21:20:39 -070017package org.onosproject.openstacknetworking.switching;
18
Hyunsun Moonb974fca2016-06-30 21:20:39 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
jskimaa851932016-10-27 17:45:30 +090024import org.apache.felix.scr.annotations.Service;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070025import org.onlab.packet.Ethernet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070026import org.onlab.packet.Ip4Address;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070027import org.onlab.packet.IpAddress;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.net.DeviceId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070030import org.onosproject.net.Host;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070031import org.onosproject.net.PortNumber;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070032import org.onosproject.net.device.DeviceService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070033import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.flowobjective.DefaultForwardingObjective;
38import org.onosproject.net.flowobjective.FlowObjectiveService;
39import org.onosproject.net.flowobjective.ForwardingObjective;
jskimaa851932016-10-27 17:45:30 +090040import org.onosproject.openstacknetworking.OpenstackSwitchingService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070041import org.onosproject.openstacknetworking.AbstractVmHandler;
Hyunsun Moon05d9b262016-07-03 18:38:44 -070042import org.onosproject.openstacknode.OpenstackNodeService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070046import java.util.Objects;
47import java.util.Optional;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070048
sangho6032f342016-07-07 14:32:03 +090049import static org.onosproject.openstacknetworking.Constants.*;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070050import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070051
jskimaa851932016-10-27 17:45:30 +090052
Hyunsun Moonb974fca2016-06-30 21:20:39 -070053/**
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070054 * Populates switching flow rules.
Hyunsun Moonb974fca2016-06-30 21:20:39 -070055 */
jskimaa851932016-10-27 17:45:30 +090056@Service
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070057@Component(immediate = true)
jskimaa851932016-10-27 17:45:30 +090058public final class OpenstackSwitchingManager extends AbstractVmHandler
59 implements OpenstackSwitchingService {
Hyunsun Moonb974fca2016-06-30 21:20:39 -070060
61 private final Logger log = LoggerFactory.getLogger(getClass());
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb974fca2016-06-30 21:20:39 -070064 protected DeviceService deviceService;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070067 protected FlowObjectiveService flowObjectiveService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070068
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070070 protected OpenstackNodeService nodeService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070071
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070072 private ApplicationId appId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070073
74 @Activate
75 protected void activate() {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070076 super.activate();
77 appId = coreService.registerApplication(SWITCHING_APP_ID);
Hyunsun Moonb974fca2016-06-30 21:20:39 -070078 }
79
80 @Deactivate
81 protected void deactivate() {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070082 super.deactivate();
83 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -070084
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070085 private void populateSwitchingRules(Host host) {
86 populateFlowRulesForTunnelTag(host);
87 populateFlowRulesForTrafficToSameCnode(host);
88 populateFlowRulesForTrafficToDifferentCnode(host);
Hyunsun Moonb974fca2016-06-30 21:20:39 -070089
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070090 log.debug("Populated switching rule for {}", host);
91 }
92
93 private void populateFlowRulesForTunnelTag(Host host) {
94 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
95 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
96
97 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
98 .matchInPort(host.location().port());
99
100 tBuilder.setTunnelId(Long.valueOf(getVni(host)));
101
102 ForwardingObjective fo = DefaultForwardingObjective.builder()
103 .withSelector(sBuilder.build())
104 .withTreatment(tBuilder.build())
105 .withPriority(TUNNELTAG_RULE_PRIORITY)
106 .withFlag(ForwardingObjective.Flag.SPECIFIC)
107 .fromApp(appId)
108 .add();
109
110 flowObjectiveService.forward(host.location().deviceId(), fo);
111 }
112
113 private void populateFlowRulesForTrafficToSameCnode(Host host) {
114 //For L2 Switching Case
115 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
116 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
117
118 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
119 .matchIPDst(getIp(host).toIpPrefix())
120 .matchTunnelId(Long.valueOf(getVni(host)));
121
sanghofb3b5012016-11-10 15:47:53 +0900122 // Destination setting is required for routing cases.
123 // We do not believe the rule would not degrade the forwarding performance.
124 // But, if it does, we need to move the rule in a separate routing table.
125 tBuilder.setEthDst(host.mac())
126 .setOutput(host.location().port());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700127
128 ForwardingObjective fo = DefaultForwardingObjective.builder()
129 .withSelector(sBuilder.build())
130 .withTreatment(tBuilder.build())
131 .withPriority(SWITCHING_RULE_PRIORITY)
132 .withFlag(ForwardingObjective.Flag.SPECIFIC)
133 .fromApp(appId)
134 .add();
135
136 flowObjectiveService.forward(host.location().deviceId(), fo);
137 }
138
139 private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
140 Ip4Address localVmIp = getIp(host);
141 DeviceId localDeviceId = host.location().deviceId();
142 Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
143
144 if (!localDataIp.isPresent()) {
145 log.debug("Failed to get data IP for device {}",
146 host.location().deviceId());
147 return;
148 }
149
150 String vni = getVni(host);
151 getVmsInDifferentCnode(host).forEach(remoteVm -> {
152 Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
153 if (remoteDataIp.isPresent()) {
154 setVxLanFlowRule(vni,
155 localDeviceId,
156 remoteDataIp.get().getIp4Address(),
157 getIp(remoteVm));
158
159 setVxLanFlowRule(vni,
160 remoteVm.location().deviceId(),
161 localDataIp.get().getIp4Address(),
162 localVmIp);
163 }
164 });
165 }
166
167 private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
168 Ip4Address vmIp) {
169 Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
170 if (!tunnelPort.isPresent()) {
171 log.warn("Failed to get tunnel port from {}", deviceId);
172 return;
173 }
174
175 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
176 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
177
178 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
179 .matchTunnelId(Long.parseLong(vni))
180 .matchIPDst(vmIp.toIpPrefix());
181 tBuilder.extension(buildExtension(deviceService, deviceId, remoteIp), deviceId)
182 .setOutput(tunnelPort.get());
183
184 ForwardingObjective fo = DefaultForwardingObjective.builder()
185 .withSelector(sBuilder.build())
186 .withTreatment(tBuilder.build())
187 .withPriority(SWITCHING_RULE_PRIORITY)
188 .withFlag(ForwardingObjective.Flag.SPECIFIC)
189 .fromApp(appId)
190 .add();
191
192 flowObjectiveService.forward(deviceId, fo);
193 }
194
195 private void removeSwitchingRules(Host host) {
196 removeFlowRuleForTunnelTag(host);
197 removeFlowRuleForVMsInSameCnode(host);
198 removeFlowRuleForVMsInDiffrentCnode(host);
199
200 log.debug("Removed switching rule for {}", host);
201 }
202
203 private void removeFlowRuleForTunnelTag(Host host) {
204 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
205 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
206
207 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
208 .matchInPort(host.location().port());
209
210 ForwardingObjective fo = DefaultForwardingObjective.builder()
211 .withSelector(sBuilder.build())
212 .withTreatment(tBuilder.build())
213 .withPriority(TUNNELTAG_RULE_PRIORITY)
214 .withFlag(ForwardingObjective.Flag.SPECIFIC)
215 .fromApp(appId)
216 .remove();
217
218 flowObjectiveService.forward(host.location().deviceId(), fo);
219 }
220
221 private void removeFlowRuleForVMsInSameCnode(Host host) {
222 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
223 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
224 .matchIPDst(getIp(host).toIpPrefix())
225 .matchTunnelId(Long.valueOf(getVni(host)));
226
227 ForwardingObjective fo = DefaultForwardingObjective.builder()
228 .withSelector(sBuilder.build())
229 .withTreatment(DefaultTrafficTreatment.builder().build())
230 .withFlag(ForwardingObjective.Flag.SPECIFIC)
231 .withPriority(SWITCHING_RULE_PRIORITY)
232 .fromApp(appId)
233 .remove();
234
235 flowObjectiveService.forward(host.location().deviceId(), fo);
236 }
237
238 private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
239 DeviceId deviceId = host.location().deviceId();
240 final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
241 .stream()
242 .filter(this::isValidHost)
243 .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
244
245 getVmsInDifferentCnode(host).forEach(h -> {
246 removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
247 if (!anyPortRemainedInSameCnode) {
248 removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
249 }
250 });
251 }
252
253 private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
254 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
255
256 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
257 .matchTunnelId(Long.valueOf(vni))
258 .matchIPDst(vmIp.toIpPrefix());
259
260 ForwardingObjective fo = DefaultForwardingObjective.builder()
261 .withSelector(sBuilder.build())
262 .withTreatment(DefaultTrafficTreatment.builder().build())
263 .withFlag(ForwardingObjective.Flag.SPECIFIC)
264 .withPriority(SWITCHING_RULE_PRIORITY)
265 .fromApp(appId)
266 .remove();
267
268 flowObjectiveService.forward(deviceId, fo);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700269 }
270
271 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700272 protected void hostDetected(Host host) {
273 populateSwitchingRules(host);
274 log.info("Added new virtual machine to switching service {}", host);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700275 }
276
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700277 @Override
278 protected void hostRemoved(Host host) {
279 removeSwitchingRules(host);
280 log.info("Removed virtual machine from switching service {}", host);
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700281 }
jskimaa851932016-10-27 17:45:30 +0900282
283 @Override
284 public void reinstallVmFlow(Host host) {
285 if (host == null) {
286 hostService.getHosts().forEach(h -> {
287 populateSwitchingRules(h);
288 log.info("Re-Install data plane flow of virtual machine {}", h);
289 });
290 } else {
291 populateSwitchingRules(host);
292 log.info("Re-Install data plane flow of virtual machine {}", host);
293 }
294 }
295
296 @Override
297 public void purgeVmFlow(Host host) {
298 if (host == null) {
299 hostService.getHosts().forEach(h -> {
300 removeSwitchingRules(h);
301 log.info("Purge data plane flow of virtual machine {}", h);
302 });
303 } else {
304 removeSwitchingRules(host);
305 log.info("Purge data plane flow of virtual machine {}", host);
306 }
307 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700308}