blob: 9e22997cc5d4d374b70573ae7fb7d5b2e5778aef [file] [log] [blame]
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001/*
2 * Copyright 2015 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 */
16package org.onosproject.cordvtn;
17
18import org.onlab.packet.Ip4Address;
19import org.onlab.util.ItemNotFoundException;
20import org.onosproject.core.ApplicationId;
21import org.onosproject.net.DeviceId;
22import org.onosproject.net.Port;
23import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
24import org.onosproject.net.driver.DefaultDriverData;
25import org.onosproject.net.driver.DefaultDriverHandler;
26import org.onosproject.net.driver.Driver;
27import org.onosproject.net.driver.DriverHandler;
28import org.onosproject.net.driver.DriverService;
29import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
31import org.onosproject.net.flow.TrafficSelector;
32import org.onosproject.net.flow.TrafficTreatment;
33import org.onosproject.net.flow.instructions.ExtensionPropertyException;
34import org.onosproject.net.flow.instructions.ExtensionTreatment;
35import org.onosproject.net.flowobjective.DefaultForwardingObjective;
36import org.onosproject.net.flowobjective.FlowObjectiveService;
37import org.onosproject.net.flowobjective.ForwardingObjective;
38import org.slf4j.Logger;
39
40import java.util.List;
41
42import static com.google.common.base.Preconditions.checkArgument;
43import static com.google.common.base.Preconditions.checkNotNull;
44import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
45import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * Populates rules for virtual tenant network.
49 */
50public final class CordVtnRuleInstaller {
51 protected final Logger log = getLogger(getClass());
52
53 private static final int DEFAULT_PRIORITY = 5000;
54
55 private final ApplicationId appId;
56 private final FlowObjectiveService flowObjectiveService;
57 private final DriverService driverService;
58 private final String tunnelType;
59
60 /**
61 * Creates a new rule installer.
62 *
63 * @param appId application id
64 * @param flowObjectiveService flow objective service
65 * @param driverService driver service
66 * @param tunnelType tunnel type
67 */
68 public CordVtnRuleInstaller(ApplicationId appId,
69 FlowObjectiveService flowObjectiveService,
70 DriverService driverService,
71 String tunnelType) {
72 this.appId = appId;
73 this.flowObjectiveService = flowObjectiveService;
74 this.driverService = driverService;
75 this.tunnelType = checkNotNull(tunnelType);
76 }
77
78 /**
79 * Installs flow rules for tunnel in traffic.
80 *
81 * @param deviceId device id to install flow rules
82 * @param inPort in port
83 * @param dstInfos list of destination info
84 */
85 public void installFlowRulesTunnelIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) {
86 dstInfos.stream().forEach(dstInfo -> {
87 ForwardingObjective.Builder fBuilder = vtnRulesSameNode(inPort, dstInfo);
88 if (fBuilder != null) {
89 flowObjectiveService.forward(deviceId, fBuilder.add());
90 }
91 });
92 }
93
94 /**
95 * Installs flow rules for local in traffic.
96 *
97 * @param deviceId device id to install flow rules
98 * @param inPort in port
99 * @param dstInfos list of destination info
100 */
101 public void installFlowRulesLocalIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) {
102 dstInfos.stream().forEach(dstInfo -> {
103 ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ?
104 vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo);
105
106 if (fBuilder != null) {
107 flowObjectiveService.forward(deviceId, fBuilder.add());
108 }
109 });
110 }
111
112 /**
113 * Uninstalls flow rules associated with a given port from a given device.
114 *
115 * @param deviceId device id
116 * @param inPort port associated with removed host
117 * @param dstInfos list of destination info
118 */
119 public void uninstallFlowRules(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) {
120 dstInfos.stream().forEach(dstInfo -> {
121 ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ?
122 vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo);
123
124 if (fBuilder != null) {
125 flowObjectiveService.forward(deviceId, fBuilder.remove());
126 }
127 });
128 }
129
130 /**
131 * Returns forwarding objective builder to provision basic virtual tenant network.
132 * This method cares for the traffics whose source and destination device is the same.
133 *
134 * @param inPort in port
135 * @param dstInfo destination information
136 * @return forwarding objective builder
137 */
138 private ForwardingObjective.Builder vtnRulesSameNode(Port inPort, DestinationInfo dstInfo) {
139 checkArgument(inPort.element().id().equals(dstInfo.output().element().id()));
140
141 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
142 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
143
144 sBuilder.matchInPort(inPort.number())
145 .matchEthDst(dstInfo.mac());
146 if (isTunnelPort(inPort)) {
147 sBuilder.matchTunnelId(dstInfo.tunnelId());
148 }
149
150 tBuilder.setOutput(dstInfo.output().number());
151
152 return DefaultForwardingObjective.builder()
153 .withSelector(sBuilder.build())
154 .withTreatment(tBuilder.build())
155 .withPriority(DEFAULT_PRIORITY)
156 .withFlag(ForwardingObjective.Flag.VERSATILE)
157 .fromApp(appId)
158 .makePermanent();
159 }
160
161 /**
162 * Returns forwarding objective builder to provision basic virtual tenant network.
163 * This method cares for the traffics whose source and destination is not the same.
164 *
165 * @param deviceId device id to install flow rules
166 * @param inPort in port
167 * @param dstInfo destination information
168 * @return forwarding objective, or null if it fails to build it
169 */
170 private ForwardingObjective.Builder vtnRulesRemoteNode(DeviceId deviceId, Port inPort, DestinationInfo dstInfo) {
171 checkArgument(isTunnelPort(dstInfo.output()));
172
173 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
174 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
175
176 ExtensionTreatment extTreatment =
177 getTunnelDstInstruction(deviceId, dstInfo.remoteIp().getIp4Address());
178 if (extTreatment == null) {
179 return null;
180 }
181
182 sBuilder.matchInPort(inPort.number())
183 .matchEthDst(dstInfo.mac());
184
185 tBuilder.extension(extTreatment, deviceId)
186 .setTunnelId(dstInfo.tunnelId())
187 .setOutput(dstInfo.output().number());
188
189 return DefaultForwardingObjective.builder()
190 .withSelector(sBuilder.build())
191 .withTreatment(tBuilder.build())
192 .withPriority(DEFAULT_PRIORITY)
193 .withFlag(ForwardingObjective.Flag.VERSATILE)
194 .fromApp(appId)
195 .makePermanent();
196 }
197
198 /**
199 * Checks if a given port is tunnel interface or not.
200 * It assumes the tunnel interface contains tunnelType string in its name.
201 *
202 * @param port port
203 * @return true if the port is tunnel interface, false otherwise.
204 */
205 private boolean isTunnelPort(Port port) {
206 return port.annotations().value("portName").contains(tunnelType);
207 }
208
209 /**
210 * Returns extension instruction to set tunnel destination.
211 *
212 * @param deviceId device id
213 * @param remoteIp tunnel destination address
214 * @return extension treatment or null if it fails to get instruction
215 */
216 private ExtensionTreatment getTunnelDstInstruction(DeviceId deviceId, Ip4Address remoteIp) {
217 try {
218 Driver driver = driverService.getDriver(deviceId);
219 DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
220 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
221
222 ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
223 treatment.setPropertyValue("tunnelDst", remoteIp);
224
225 return treatment;
226 } catch (ItemNotFoundException | UnsupportedOperationException | ExtensionPropertyException e) {
227 log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
228 return null;
229 }
230 }
231}