blob: 2846ee019eaf340bb626362fe70598ce0ea57fc7 [file] [log] [blame]
Mahesh Poojary S7e9a78f2015-12-04 01:55:57 +05301/*
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.sfc.forwarder.impl;
17
18import static org.slf4j.LoggerFactory.getLogger;
19import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SPI;
20import static com.google.common.base.Preconditions.checkNotNull;
21
22import java.util.List;
23import java.util.ListIterator;
24
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.osgi.DefaultServiceDirectory;
28import org.onlab.osgi.ServiceDirectory;
29import org.onlab.packet.MacAddress;
30import org.onlab.packet.VlanId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.net.behaviour.ExtensionSelectorResolver;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.NshServicePathId;
35import org.onosproject.net.driver.DriverHandler;
36import org.onosproject.net.driver.DriverService;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.criteria.ExtensionSelector;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
42import org.onosproject.net.flowobjective.DefaultForwardingObjective;
43import org.onosproject.net.flowobjective.FlowObjectiveService;
44import org.onosproject.net.flowobjective.ForwardingObjective;
45import org.onosproject.net.flowobjective.Objective;
46import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
47import org.onosproject.vtnrsc.VirtualPortId;
48import org.onosproject.vtnrsc.service.VtnRscService;
49import org.onosproject.vtnrsc.PortChain;
50import org.onosproject.vtnrsc.PortPair;
51import org.onosproject.vtnrsc.PortPairGroup;
52import org.onosproject.vtnrsc.PortPairGroupId;
53import org.onosproject.vtnrsc.PortPairId;
54import org.onosproject.vtnrsc.virtualport.VirtualPortService;
55import org.onosproject.vtnrsc.portpair.PortPairService;
56import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
57import org.onosproject.vtnrsc.flowclassifier.FlowClassifierService;
58import org.onosproject.vtnrsc.portchain.PortChainService;
59import org.onosproject.sfc.forwarder.ServiceFunctionForwarderService;
60
61import org.slf4j.Logger;
62
63/**
64 * Provides Service Function Forwarder implementation.
65 */
66public class ServiceFunctionForwarderImpl implements ServiceFunctionForwarderService {
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected DriverService driverService;
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected VirtualPortService virtualPortService;
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected VtnRscService vtnRscService;
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected PortPairService portPairService;
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected PortPairGroupService portPairGroupService;
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected FlowClassifierService flowClassifierService;
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected PortChainService portChainService;
82
83 private final Logger log = getLogger(getClass());
84 protected ApplicationId appId;
85 protected FlowObjectiveService flowObjectiveService;
86
87 private static final String DRIVER_NAME = "onosfw";
88 private static final String PORT_CHAIN_NOT_NULL = "Port-Chain cannot be null";
89 private static final String PORT_CHAIN_ID_NOT_NULL = "Port-Chain-Id cannot be null";
90 private static final String APP_ID_NOT_NULL = "Application-Id cannot be null";
91 private static final int NULL = 0;
92
93 /**
94 * Default constructor.
95 */
96 public ServiceFunctionForwarderImpl() {
97 }
98
99 /**
100 * Explicit constructor.
101 */
102 public ServiceFunctionForwarderImpl(ApplicationId appId) {
103 this.appId = checkNotNull(appId, APP_ID_NOT_NULL);
104 ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
105 this.flowObjectiveService = serviceDirectory.get(FlowObjectiveService.class);
106 }
107
108 @Override
109 public void installForwardingRule(PortChain portChain, NshServicePathId nshSPI) {
110 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
111 prepareServiceFunctionForwarder(portChain, nshSPI, Objective.Operation.ADD);
112 }
113
114 @Override
115 public void unInstallForwardingRule(PortChain portChain, NshServicePathId nshSPI) {
116 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
117 prepareServiceFunctionForwarder(portChain, nshSPI, Objective.Operation.REMOVE);
118 }
119
120 @Override
121 public void prepareServiceFunctionForwarder(PortChain portChain, NshServicePathId nshSPI,
122 Objective.Operation type) {
123
124 // Go through the port pair group list
125 List<PortPairGroupId> portPairGrpList = portChain.portPairGroups();
126 ListIterator<PortPairGroupId> listGrpIterator = portPairGrpList.listIterator();
127
128 // Get source port pair group
129 if (!listGrpIterator.hasNext()) {
130 return;
131 }
132 PortPairGroupId portPairGrpId = listGrpIterator.next();
133 PortPairGroup currentPortPairGroup = portPairGroupService.getPortPairGroup(portPairGrpId);
134
135 // Get destination port pair group
136 if (!listGrpIterator.hasNext()) {
137 return;
138 }
139 portPairGrpId = listGrpIterator.next();
140 PortPairGroup nextPortPairGroup = portPairGroupService.getPortPairGroup(portPairGrpId);
141
142 // push SFF to OVS
143 pushServiceFunctionForwarder(currentPortPairGroup, nextPortPairGroup, listGrpIterator, nshSPI, type);
144 }
145
146 /**
147 * Push service-function-forwarder to OVS.
148 *
149 * @param currentPortPairGroup current port-pair-group
150 * @param nextPortPairGroup next port-pair-group
151 * @param listGrpIterator pointer to port-pair-group list
152 */
153 public void pushServiceFunctionForwarder(PortPairGroup currentPortPairGroup, PortPairGroup nextPortPairGroup,
154 ListIterator<PortPairGroupId> listGrpIterator, NshServicePathId nshSPI, Objective.Operation type) {
155 MacAddress srcMacAddress = null;
156 MacAddress dstMacAddress = null;
157 DeviceId deviceId = null;
158 DeviceId currentDeviceId = null;
159 DeviceId nextDeviceId = null;
160 PortPairGroupId portPairGrpId = null;
161
162 // Travel from SF to SF.
163 do {
164 // Get the required information on port pairs from source port pair
165 // group
166 List<PortPairId> portPairList = currentPortPairGroup.portPairs();
167 ListIterator<PortPairId> portPLIterator = portPairList.listIterator();
168 if (!portPLIterator.hasNext()) {
169 break;
170 }
171
172 PortPairId portPairId = portPLIterator.next();
173 PortPair portPair = portPairService.getPortPair(portPairId);
174
175 currentDeviceId = vtnRscService.getSFToSFFMaping(VirtualPortId.portId(portPair.ingress()));
176 if (deviceId == null) {
177 deviceId = currentDeviceId;
178 }
179 srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress())).macAddress();
180 dstMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())).macAddress();
181
182 // pack traffic selector
183 TrafficSelector.Builder selector = packTrafficSelector(deviceId, srcMacAddress, dstMacAddress, nshSPI);
184
185 // Get the required information on port pairs from destination port
186 // pair group
187 portPairList = nextPortPairGroup.portPairs();
188 portPLIterator = portPairList.listIterator();
189 if (!portPLIterator.hasNext()) {
190 break;
191 }
192
193 portPairId = portPLIterator.next();
194 portPair = portPairService.getPortPair(portPairId);
195
196 nextDeviceId = vtnRscService.getSFToSFFMaping(VirtualPortId.portId(portPair.ingress()));
197
198 // pack traffic treatment
199 TrafficTreatment.Builder treatment = packTrafficTreatment(currentDeviceId, nextDeviceId, portPair);
200
201 // Send SFF to OVS
202 sendServiceFunctionForwarder(selector, treatment, deviceId, type);
203
204 // Replace source port pair group with destination port pair group
205 // for moving to next SFF processing.
206 currentPortPairGroup = nextPortPairGroup;
207 if (!listGrpIterator.hasNext()) {
208 break;
209 }
210 portPairGrpId = listGrpIterator.next();
211 nextPortPairGroup = portPairGroupService.getPortPairGroup(portPairGrpId);
212 } while (true);
213 }
214
215 /**
216 * Pack Traffic selector.
217 *
218 * @param deviceId device id
219 * @param srcMacAddress source mac-address
220 * @param dstMacAddress destination mac-address
221 * @param nshSPI nsh spi
222 * @return traffic treatment
223 */
224 public TrafficSelector.Builder packTrafficSelector(DeviceId deviceId, MacAddress srcMacAddress,
225 MacAddress dstMacAddress, NshServicePathId nshSPI) {
226 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
227 selector.matchEthSrc(srcMacAddress);
228 selector.matchEthDst(dstMacAddress);
229
230 DriverHandler handler = driverService.createHandler(deviceId);
231 ExtensionSelectorResolver resolver = handler.behaviour(ExtensionSelectorResolver.class);
232 ExtensionSelector nspSpiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
233
234 try {
235 nspSpiSelector.setPropertyValue("nshSpi", nshSPI);
236 } catch (Exception e) {
237 log.error("Failed to get extension instruction to set Nsh Spi Id {}", deviceId);
238 }
239
240 selector.extension(nspSpiSelector, deviceId);
241 return selector;
242 }
243
244 /**
245 * Pack Traffic treatment.
246 *
247 * @param currentDeviceId current device id
248 * @param nextDeviceId next device id
249 * @param portPair port-pair
250 * @return traffic treatment
251 */
252 public TrafficTreatment.Builder packTrafficTreatment(DeviceId currentDeviceId, DeviceId nextDeviceId,
253 PortPair portPair) {
254 MacAddress srcMacAddress = null;
255 MacAddress dstMacAddress = null;
256
257 // Check the treatment whether destination SF is on same OVS or in
258 // different OVS.
259 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
260 if (currentDeviceId.equals(nextDeviceId)) {
261 srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress())).macAddress();
262 dstMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())).macAddress();
263 treatment.setEthSrc(srcMacAddress);
264 treatment.setEthDst(dstMacAddress);
265 } else {
266 treatment.setVlanId(VlanId.vlanId(Short.parseShort((vtnRscService.getL3vni(portPair
267 .tenantId()).toString()))));
268 }
269
270 return treatment;
271 }
272
273 /**
274 * Send service function forwarder to OVS.
275 *
276 * @param selector traffic selector
277 * @param treatment traffic treatment
278 * @param deviceId device id
279 * @param type operation type
280 */
281 public void sendServiceFunctionForwarder(TrafficSelector.Builder selector, TrafficTreatment.Builder treatment,
282 DeviceId deviceId, Objective.Operation type) {
283 ForwardingObjective.Builder objective = DefaultForwardingObjective.builder().withTreatment(treatment.build())
284 .withSelector(selector.build()).fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC);
285 if (type.equals(Objective.Operation.ADD)) {
286 log.debug("ADD");
287 flowObjectiveService.forward(deviceId, objective.add());
288 } else {
289 log.debug("REMOVE");
290 flowObjectiveService.forward(deviceId, objective.remove());
291 }
292 }
293}