blob: db324d75bee5d756da206873088671923819b2fb [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
122 tBuilder.setOutput(host.location().port());
123
124 ForwardingObjective fo = DefaultForwardingObjective.builder()
125 .withSelector(sBuilder.build())
126 .withTreatment(tBuilder.build())
127 .withPriority(SWITCHING_RULE_PRIORITY)
128 .withFlag(ForwardingObjective.Flag.SPECIFIC)
129 .fromApp(appId)
130 .add();
131
132 flowObjectiveService.forward(host.location().deviceId(), fo);
133 }
134
135 private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
136 Ip4Address localVmIp = getIp(host);
137 DeviceId localDeviceId = host.location().deviceId();
138 Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
139
140 if (!localDataIp.isPresent()) {
141 log.debug("Failed to get data IP for device {}",
142 host.location().deviceId());
143 return;
144 }
145
146 String vni = getVni(host);
147 getVmsInDifferentCnode(host).forEach(remoteVm -> {
148 Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
149 if (remoteDataIp.isPresent()) {
150 setVxLanFlowRule(vni,
151 localDeviceId,
152 remoteDataIp.get().getIp4Address(),
153 getIp(remoteVm));
154
155 setVxLanFlowRule(vni,
156 remoteVm.location().deviceId(),
157 localDataIp.get().getIp4Address(),
158 localVmIp);
159 }
160 });
161 }
162
163 private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
164 Ip4Address vmIp) {
165 Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
166 if (!tunnelPort.isPresent()) {
167 log.warn("Failed to get tunnel port from {}", deviceId);
168 return;
169 }
170
171 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
172 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
173
174 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
175 .matchTunnelId(Long.parseLong(vni))
176 .matchIPDst(vmIp.toIpPrefix());
177 tBuilder.extension(buildExtension(deviceService, deviceId, remoteIp), deviceId)
178 .setOutput(tunnelPort.get());
179
180 ForwardingObjective fo = DefaultForwardingObjective.builder()
181 .withSelector(sBuilder.build())
182 .withTreatment(tBuilder.build())
183 .withPriority(SWITCHING_RULE_PRIORITY)
184 .withFlag(ForwardingObjective.Flag.SPECIFIC)
185 .fromApp(appId)
186 .add();
187
188 flowObjectiveService.forward(deviceId, fo);
189 }
190
191 private void removeSwitchingRules(Host host) {
192 removeFlowRuleForTunnelTag(host);
193 removeFlowRuleForVMsInSameCnode(host);
194 removeFlowRuleForVMsInDiffrentCnode(host);
195
196 log.debug("Removed switching rule for {}", host);
197 }
198
199 private void removeFlowRuleForTunnelTag(Host host) {
200 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
201 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
202
203 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
204 .matchInPort(host.location().port());
205
206 ForwardingObjective fo = DefaultForwardingObjective.builder()
207 .withSelector(sBuilder.build())
208 .withTreatment(tBuilder.build())
209 .withPriority(TUNNELTAG_RULE_PRIORITY)
210 .withFlag(ForwardingObjective.Flag.SPECIFIC)
211 .fromApp(appId)
212 .remove();
213
214 flowObjectiveService.forward(host.location().deviceId(), fo);
215 }
216
217 private void removeFlowRuleForVMsInSameCnode(Host host) {
218 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
219 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
220 .matchIPDst(getIp(host).toIpPrefix())
221 .matchTunnelId(Long.valueOf(getVni(host)));
222
223 ForwardingObjective fo = DefaultForwardingObjective.builder()
224 .withSelector(sBuilder.build())
225 .withTreatment(DefaultTrafficTreatment.builder().build())
226 .withFlag(ForwardingObjective.Flag.SPECIFIC)
227 .withPriority(SWITCHING_RULE_PRIORITY)
228 .fromApp(appId)
229 .remove();
230
231 flowObjectiveService.forward(host.location().deviceId(), fo);
232 }
233
234 private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
235 DeviceId deviceId = host.location().deviceId();
236 final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
237 .stream()
238 .filter(this::isValidHost)
239 .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
240
241 getVmsInDifferentCnode(host).forEach(h -> {
242 removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
243 if (!anyPortRemainedInSameCnode) {
244 removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
245 }
246 });
247 }
248
249 private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
250 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
251
252 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
253 .matchTunnelId(Long.valueOf(vni))
254 .matchIPDst(vmIp.toIpPrefix());
255
256 ForwardingObjective fo = DefaultForwardingObjective.builder()
257 .withSelector(sBuilder.build())
258 .withTreatment(DefaultTrafficTreatment.builder().build())
259 .withFlag(ForwardingObjective.Flag.SPECIFIC)
260 .withPriority(SWITCHING_RULE_PRIORITY)
261 .fromApp(appId)
262 .remove();
263
264 flowObjectiveService.forward(deviceId, fo);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700265 }
266
267 @Override
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700268 protected void hostDetected(Host host) {
269 populateSwitchingRules(host);
270 log.info("Added new virtual machine to switching service {}", host);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700271 }
272
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700273 @Override
274 protected void hostRemoved(Host host) {
275 removeSwitchingRules(host);
276 log.info("Removed virtual machine from switching service {}", host);
Hyunsun Moon05d9b262016-07-03 18:38:44 -0700277 }
jskimaa851932016-10-27 17:45:30 +0900278
279 @Override
280 public void reinstallVmFlow(Host host) {
281 if (host == null) {
282 hostService.getHosts().forEach(h -> {
283 populateSwitchingRules(h);
284 log.info("Re-Install data plane flow of virtual machine {}", h);
285 });
286 } else {
287 populateSwitchingRules(host);
288 log.info("Re-Install data plane flow of virtual machine {}", host);
289 }
290 }
291
292 @Override
293 public void purgeVmFlow(Host host) {
294 if (host == null) {
295 hostService.getHosts().forEach(h -> {
296 removeSwitchingRules(h);
297 log.info("Purge data plane flow of virtual machine {}", h);
298 });
299 } else {
300 removeSwitchingRules(host);
301 log.info("Purge data plane flow of virtual machine {}", host);
302 }
303 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700304}