blob: 71397a7cb58e6b76a0b3af2a8e35859674ebd57d [file] [log] [blame]
Phaneendra Manda8db7d092016-06-04 00:17:24 +05301/*
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 */
16package org.onosproject.sfc.installer.impl;
17
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_ENCAP_ETH_TYPE;
20import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SI;
21import static org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_NSH_SPI;
22import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_ENCAP_ETH_DST;
23import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_ENCAP_ETH_SRC;
24import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_NSH_MDTYPE;
25import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_NSH_NP;
26import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_POP_NSH;
27import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_PUSH_NSH;
28import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_RESUBMIT_TABLE;
29import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH1;
30import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH2;
31import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH3;
32import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_CH4;
33import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SI;
34import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_NSH_SPI;
35import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
36import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_TUN_GPE_NP;
37import static org.slf4j.LoggerFactory.getLogger;
38
39import java.util.LinkedList;
40import java.util.List;
41import java.util.ListIterator;
42import java.util.Set;
43
44import org.onlab.osgi.DefaultServiceDirectory;
45import org.onlab.osgi.ServiceDirectory;
46import org.onlab.packet.Ethernet;
47import org.onlab.packet.IPv4;
48import org.onlab.packet.Ip4Address;
49import org.onlab.packet.IpPrefix;
50import org.onlab.packet.MacAddress;
51import org.onlab.packet.TpPort;
52import org.onosproject.core.ApplicationId;
53import org.onosproject.net.AnnotationKeys;
54import org.onosproject.net.ConnectPoint;
55import org.onosproject.net.Device;
56import org.onosproject.net.DeviceId;
57import org.onosproject.net.Host;
58import org.onosproject.net.HostId;
59import org.onosproject.net.NshContextHeader;
60import org.onosproject.net.NshServiceIndex;
61import org.onosproject.net.NshServicePathId;
62import org.onosproject.net.Port;
63import org.onosproject.net.PortNumber;
64import org.onosproject.net.behaviour.BridgeConfig;
65import org.onosproject.net.behaviour.ExtensionSelectorResolver;
66import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
67import org.onosproject.net.device.DeviceService;
68import org.onosproject.net.driver.DriverHandler;
69import org.onosproject.net.driver.DriverService;
70import org.onosproject.net.flow.DefaultTrafficSelector;
71import org.onosproject.net.flow.DefaultTrafficTreatment;
72import org.onosproject.net.flow.TrafficSelector;
73import org.onosproject.net.flow.TrafficTreatment;
74import org.onosproject.net.flow.criteria.Criteria;
75import org.onosproject.net.flow.criteria.ExtensionSelector;
76import org.onosproject.net.flow.instructions.ExtensionTreatment;
77import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
78import org.onosproject.net.flow.instructions.Instructions;
79import org.onosproject.net.flowobjective.DefaultForwardingObjective;
80import org.onosproject.net.flowobjective.FlowObjectiveService;
81import org.onosproject.net.flowobjective.ForwardingObjective;
82import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
83import org.onosproject.net.flowobjective.Objective;
84import org.onosproject.net.host.HostService;
85import org.onosproject.sfc.installer.SfcFlowRuleInstallerService;
86import org.onosproject.vtnrsc.FiveTuple;
87import org.onosproject.vtnrsc.FlowClassifier;
88import org.onosproject.vtnrsc.FlowClassifierId;
89import org.onosproject.vtnrsc.PortChain;
90import org.onosproject.vtnrsc.PortPair;
91import org.onosproject.vtnrsc.PortPairGroup;
92import org.onosproject.vtnrsc.PortPairGroupId;
93import org.onosproject.vtnrsc.PortPairId;
94import org.onosproject.vtnrsc.SegmentationId;
95import org.onosproject.vtnrsc.VirtualPort;
96import org.onosproject.vtnrsc.VirtualPortId;
97import org.onosproject.vtnrsc.flowclassifier.FlowClassifierService;
98import org.onosproject.vtnrsc.portpair.PortPairService;
99import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
100import org.onosproject.vtnrsc.service.VtnRscService;
101import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
102import org.onosproject.vtnrsc.virtualport.VirtualPortService;
103import org.slf4j.Logger;
104
105import com.google.common.collect.Lists;
106import com.google.common.collect.Sets;
107
108/**
109 * Provides flow classifier installer implementation.
110 */
111public class SfcFlowRuleInstallerImpl implements SfcFlowRuleInstallerService {
112 private final Logger log = getLogger(getClass());
113
114 protected VirtualPortService virtualPortService;
115 protected VtnRscService vtnRscService;
116 protected PortPairService portPairService;
117 protected PortPairGroupService portPairGroupService;
118 protected FlowClassifierService flowClassifierService;
119 protected DriverService driverService;
120 protected DeviceService deviceService;
121 protected HostService hostService;
122 protected TenantNetworkService tenantNetworkService;
123 protected FlowObjectiveService flowObjectiveService;
124 protected ApplicationId appId;
125
126 private static final String PORT_CHAIN_NOT_NULL = "Port-Chain cannot be null";
127 private static final int FLOW_CLASSIFIER_PRIORITY = 0xC738;
128 private static final int DEFAULT_FORWARDER_PRIORITY = 0xD6D8;
129 private static final int ENCAP_OUTPUT_PRIORITY = 0x64;
130 private static final int TUNNEL_SEND_PRIORITY = 0xC8;
131 private static final String SWITCH_CHANNEL_ID = "channelId";
132 private static final int ENCAP_OUTPUT_TABLE = 4;
133 private static final int TUNNEL_SEND_TABLE = 7;
134 private static final short ENCAP_ETH_TYPE = (short) 0x894f;
135 private static final String DEFAULT_IP = "0.0.0.0";
136 private static final String VXLANPORT_HEAD = "vxlan-0.0.0.0";
137
138 /* Port chain params */
139 private short nshSi;
140 List<DeviceId> classifierList;
141 List<DeviceId> forwarderList;
142
143 /**
144 * Default constructor.
145 */
146 public SfcFlowRuleInstallerImpl() {
147 }
148
149 /**
150 * Explicit constructor.
151 *
152 * @param appId application id.
153 */
154 public SfcFlowRuleInstallerImpl(ApplicationId appId) {
155 this.appId = checkNotNull(appId, "ApplicationId can not be null");
156 ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
157 this.flowObjectiveService = serviceDirectory.get(FlowObjectiveService.class);
158 this.driverService = serviceDirectory.get(DriverService.class);
159 this.deviceService = serviceDirectory.get(DeviceService.class);
160 this.hostService = serviceDirectory.get(HostService.class);
161 this.virtualPortService = serviceDirectory.get(VirtualPortService.class);
162 this.vtnRscService = serviceDirectory.get(VtnRscService.class);
163 this.portPairService = serviceDirectory.get(PortPairService.class);
164 this.portPairGroupService = serviceDirectory.get(PortPairGroupService.class);
165 this.flowClassifierService = serviceDirectory.get(FlowClassifierService.class);
166 this.tenantNetworkService = serviceDirectory.get(TenantNetworkService.class);
167 nshSi = 0xff;
168 }
169
170 @Override
171 public ConnectPoint installFlowClassifier(PortChain portChain, NshServicePathId nshSpiId) {
172 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
173 // Get the portPairGroup
174 List<PortPairGroupId> llPortPairGroupIdList = portChain.portPairGroups();
175 ListIterator<PortPairGroupId> portPairGroupIdListIterator = llPortPairGroupIdList.listIterator();
176 PortPairGroupId portPairGroupId = portPairGroupIdListIterator.next();
177 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
178 List<PortPairId> llPortPairIdList = portPairGroup.portPairs();
179
180 // Get port pair
181 ListIterator<PortPairId> portPairListIterator = llPortPairIdList.listIterator();
182 PortPairId portPairId = portPairListIterator.next();
183 PortPair portPair = portPairService.getPortPair(portPairId);
184
185 return installSfcClassifierRules(portChain, portPair, nshSpiId, null, Objective.Operation.ADD);
186 }
187
188 @Override
189 public ConnectPoint unInstallFlowClassifier(PortChain portChain, NshServicePathId nshSpiId) {
190 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
191 // Get the portPairGroup
192 List<PortPairGroupId> llPortPairGroupIdList = portChain.portPairGroups();
193 ListIterator<PortPairGroupId> portPairGroupIdListIterator = llPortPairGroupIdList.listIterator();
194 PortPairGroupId portPairGroupId = portPairGroupIdListIterator.next();
195 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
196 List<PortPairId> llPortPairIdList = portPairGroup.portPairs();
197
198 // Get port pair
199 ListIterator<PortPairId> portPairListIterator = llPortPairIdList.listIterator();
200 PortPairId portPairId = portPairListIterator.next();
201 PortPair portPair = portPairService.getPortPair(portPairId);
202
203 return installSfcClassifierRules(portChain, portPair, nshSpiId, null, Objective.Operation.REMOVE);
204 }
205
206 @Override
207 public ConnectPoint installLoadBalancedFlowRules(PortChain portChain, FiveTuple fiveTuple,
208 NshServicePathId nshSpiId) {
209 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
210
211 return installSfcFlowRules(portChain, fiveTuple, nshSpiId, Objective.Operation.ADD);
212 }
213
214 @Override
215 public ConnectPoint unInstallLoadBalancedFlowRules(PortChain portChain, FiveTuple fiveTuple,
216 NshServicePathId nshSpiId) {
217 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
218 return installSfcFlowRules(portChain, fiveTuple, nshSpiId, Objective.Operation.REMOVE);
219 }
220
221 public ConnectPoint installSfcFlowRules(PortChain portChain, FiveTuple fiveTuple, NshServicePathId nshSpiId,
222 Objective.Operation type) {
223 checkNotNull(portChain, PORT_CHAIN_NOT_NULL);
224
225 classifierList = Lists.newArrayList();
226 forwarderList = Lists.newArrayList();
227
228 // Get the load balanced path
229 List<PortPairId> portPairs = portChain.getLoadBalancePath(fiveTuple);
230
231 // Get the first port pair
232 ListIterator<PortPairId> portPairListIterator = portPairs.listIterator();
233 PortPairId portPairId = portPairListIterator.next();
234 PortPair currentPortPair = portPairService.getPortPair(portPairId);
235
236 ConnectPoint connectPoint = installSfcClassifierRules(portChain, currentPortPair, nshSpiId, fiveTuple, type);
237
238 log.info("Installing encap and output for first port pair");
239
240 installSfcEncapOutputRule(currentPortPair, nshSpiId, type);
241
242 PortPair nextPortPair;
243 while (portPairListIterator.hasNext()) {
244 portPairId = portPairListIterator.next();
245 nextPortPair = portPairService.getPortPair(portPairId);
246 installSfcForwardRule(currentPortPair, nextPortPair, nshSpiId, type);
247 installSfcEncapOutputRule(nextPortPair, nshSpiId, type);
248 currentPortPair = nextPortPair;
249 }
250 installSfcEndRule(currentPortPair, nshSpiId, type);
251
252 if (type.equals(Objective.Operation.ADD)) {
253 portChain.addSfcClassifiers(portChain.getLoadBalanceId(fiveTuple), classifierList);
254 portChain.addSfcForwarders(portChain.getLoadBalanceId(fiveTuple), forwarderList);
255 } else {
256 portChain.removeSfcClassifiers(portChain.getLoadBalanceId(fiveTuple), classifierList);
257 portChain.removeSfcForwarders(portChain.getLoadBalanceId(fiveTuple), forwarderList);
258 }
259 return connectPoint;
260 }
261
262 public void installSfcTunnelReceiveRule(DeviceId deviceId, NshServicePathId nshSpiId, Objective.Operation type) {
263
264 DriverHandler handler = driverService.createHandler(deviceId);
265 ExtensionSelectorResolver selectorResolver = handler.behaviour(ExtensionSelectorResolver.class);
266 ExtensionSelector nshSpiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
267 ExtensionSelector nshSiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
268
269 try {
270 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
271 } catch (Exception e) {
272 log.error("Failed to set extension selector to match Nsh Spi Id for end rule {}", e.getMessage());
273 }
274 try {
275 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
276 } catch (Exception e) {
277 log.error("Failed to set extension selector to match Nsh Si Id for end rule {}", e.getMessage());
278 }
279
280 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
281 selector.extension(nshSpiSelector, deviceId);
282 selector.extension(nshSiSelector, deviceId);
283
284 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
285 treatment.transition(ENCAP_OUTPUT_TABLE);
286
287 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
288 }
289
290 public void installSfcTunnelSendRule(DeviceId deviceId, NshServicePathId nshSpiId, Objective.Operation type) {
291
292 // Prepare selector with nsp, nsi and inport from egress of port pair
293 DriverHandler handler = driverService.createHandler(deviceId);
294 ExtensionSelectorResolver selectorResolver = handler.behaviour(ExtensionSelectorResolver.class);
295 ExtensionSelector nshSpiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
296 ExtensionSelector nshSiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
297 ExtensionSelector encapEthTypeSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_ENCAP_ETH_TYPE
298 .type());
299 try {
300 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
301 } catch (Exception e) {
302 log.error("Failed to set extension selector to match Nsh Spi Id for end rule {}", e.getMessage());
303 }
304 try {
305 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
306 } catch (Exception e) {
307 log.error("Failed to set extension selector to match Nsh Si Id for end rule {}", e.getMessage());
308 }
309 try {
310 encapEthTypeSelector.setPropertyValue("encapEthType", ENCAP_ETH_TYPE);
311 } catch (Exception e) {
312 log.error("Failed to set extension selector to match encapEthType {}", deviceId);
313 }
314
315 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
316 selector.extension(nshSpiSelector, deviceId);
317 selector.extension(nshSiSelector, deviceId);
318
319 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
320 ExtensionTreatment tunGpeNpTreatment = treatmentResolver.getExtensionInstruction(NICIRA_TUN_GPE_NP.type());
321 try {
322 tunGpeNpTreatment.setPropertyValue("tunGpeNp", ((byte) 4));
323 } catch (Exception e) {
324 log.error("Failed to get extension instruction to set tunGpeNp {}", deviceId);
325 }
326
327 ExtensionTreatment moveC1ToC1 = treatmentResolver
328 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
329 .NICIRA_MOV_NSH_C1_TO_C1.type());
330
331 ExtensionTreatment moveC2ToC2 = treatmentResolver
332 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
333 .NICIRA_MOV_NSH_C2_TO_C2.type());
334
335 ExtensionTreatment moveC3ToC3 = treatmentResolver
336 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
337 .NICIRA_MOV_NSH_C3_TO_C3.type());
338
339 ExtensionTreatment moveC4ToC4 = treatmentResolver
340 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
341 .NICIRA_MOV_NSH_C4_TO_C4.type());
342
343 ExtensionTreatment moveTunIpv4DstToTunIpv4Dst = treatmentResolver
344 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
345 .NICIRA_MOV_TUN_IPV4_DST_TO_TUN_IPV4_DST.type());
346
347 ExtensionTreatment moveTunIdToTunId = treatmentResolver
348 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
349 .NICIRA_MOV_TUN_ID_TO_TUN_ID.type());
350
351 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
352 treatment.extension(tunGpeNpTreatment, deviceId);
353 treatment.extension(moveC1ToC1, deviceId);
354 treatment.extension(moveC2ToC2, deviceId);
355 treatment.extension(moveC3ToC3, deviceId);
356 treatment.extension(moveC4ToC4, deviceId);
357 treatment.extension(moveTunIpv4DstToTunIpv4Dst, deviceId);
358 treatment.extension(moveTunIdToTunId, deviceId);
359
360 Iterable<Device> devices = deviceService.getAvailableDevices();
361 DeviceId localControllerId = getControllerId(deviceService.getDevice(deviceId), devices);
362 DriverHandler controllerHandler = driverService.createHandler(localControllerId);
363
364 BridgeConfig bridgeConfig = controllerHandler.behaviour(BridgeConfig.class);
365 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
366 String tunnelName = "vxlan-" + DEFAULT_IP;
367 ports.stream()
368 .filter(p ->p.name().equalsIgnoreCase(tunnelName))
369 .forEach(p -> {
370 treatment.setOutput(p);
371 sendSfcRule(selector, treatment, deviceId, type, TUNNEL_SEND_PRIORITY);
372 });
373 }
374
375 public void installSfcEndRule(PortPair portPair, NshServicePathId nshSpiId, Objective.Operation type) {
376 DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.egress()));
377 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())).macAddress();
378 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
379 PortNumber port = host.location().port();
380
381 // Prepare selector with nsp, nsi and inport from egress of port pair
382 DriverHandler handler = driverService.createHandler(deviceId);
383 ExtensionSelectorResolver selectorResolver = handler.behaviour(ExtensionSelectorResolver.class);
384 ExtensionSelector nshSpiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
385 ExtensionSelector nshSiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
386 ExtensionSelector encapEthTypeSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_ENCAP_ETH_TYPE
387 .type());
388 try {
389 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
390 } catch (Exception e) {
391 log.error("Failed to set extension selector to match Nsh Spi Id for end rule {}", e.getMessage());
392 }
393 // Decrement the SI
394 nshSi = (short) (nshSi - 1);
395 try {
396 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
397 } catch (Exception e) {
398 log.error("Failed to set extension selector to match Nsh Si Id for end rule {}", e.getMessage());
399 }
400 try {
401 encapEthTypeSelector.setPropertyValue("encapEthType", ENCAP_ETH_TYPE);
402 } catch (Exception e) {
403 log.error("Failed to set extension selector to match encapEthType {}", deviceId);
404 }
405 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
406 selector.extension(encapEthTypeSelector, deviceId);
407 selector.extension(nshSpiSelector, deviceId);
408 selector.extension(nshSiSelector, deviceId);
409 selector.matchInPort(port);
410
411 // Set treatment to pop nsh header, set tunnel id and resubmit to table
412 // 0.
413 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
414 ExtensionTreatment popNshTreatment = treatmentResolver.getExtensionInstruction(NICIRA_POP_NSH.type());
415
416 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
417 treatment.extension(popNshTreatment, deviceId);
418
419 VirtualPort virtualPort = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress()));
420 SegmentationId segmentationId = tenantNetworkService.getNetwork(virtualPort.networkId()).segmentationId();
421 treatment.add(Instructions.modTunnelId(Long.parseLong(segmentationId.toString())));
422
423 ExtensionTreatment resubmitTableTreatment = treatmentResolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE
424 .type());
425
426 PortNumber vxlanPortNumber = getVxlanPortNumber(deviceId);
427
428 try {
429 resubmitTableTreatment.setPropertyValue("inPort", vxlanPortNumber);
430 } catch (Exception e) {
431 log.error("Failed to set extension treatment for resubmit table in port {}", deviceId);
432 }
433 try {
434 resubmitTableTreatment.setPropertyValue("table", ((short) 0));
435 } catch (Exception e) {
436 log.error("Failed to set extension treatment for resubmit table {}", deviceId);
437 }
438 treatment.extension(resubmitTableTreatment, deviceId);
439
440 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
441 }
442
443 public void installSfcForwardRule(PortPair portPair, PortPair nextPortPair, NshServicePathId nshSpiId,
444 Objective.Operation type) {
445 DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.egress()));
446 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())).macAddress();
447 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
448 PortNumber port = host.location().port();
449
450 DriverHandler handler = driverService.createHandler(deviceId);
451 ExtensionSelectorResolver resolver = handler.behaviour(ExtensionSelectorResolver.class);
452
453 // Prepare selector with nsp, nsi and inport from egress of port pair
454 ExtensionSelector nshSpiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
455 ExtensionSelector nshSiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
456 try {
457 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
458 } catch (Exception e) {
459 log.error("Failed to set extension selector to match Nsh Spi Id for forward rule {}", e.getMessage());
460 }
461 // Decrement the SI
462 nshSi = (short) (nshSi - 1);
463 try {
464 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
465 } catch (Exception e) {
466 log.error("Failed to set extension selector to match Nsh Si Id for forward rule {}", e.getMessage());
467 }
468 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
469 selector.extension(nshSpiSelector, deviceId);
470 selector.extension(nshSiSelector, deviceId);
471 selector.matchInPort(port);
472
473 DeviceId nextDeviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(nextPortPair.ingress()));
474 if (deviceId.equals(nextDeviceId)) {
475
476 // Treatment with transition
477 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
478 treatment.transition(ENCAP_OUTPUT_TABLE);
479
480 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
481 } else {
482 // Treatment with with transition to send on tunnel
483 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
484 ExtensionTreatment moveC2ToTunId = treatmentResolver
485 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
486 .NICIRA_MOV_NSH_C2_TO_TUN_ID.type());
487
488 Device remoteDevice = deviceService.getDevice(nextDeviceId);
489 String url = remoteDevice.annotations().value(SWITCH_CHANNEL_ID);
490 String remoteControllerIp = url.substring(0, url.lastIndexOf(":"));
491 if (remoteControllerIp == null) {
492 log.error("Can't find remote controller of device: {}", nextDeviceId.toString());
493 return;
494 }
495
496 ExtensionTreatment tunnelDsttreatment = treatmentResolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST
497 .type());
498 try {
499 tunnelDsttreatment.setPropertyValue("tunnelDst", Ip4Address.valueOf(remoteControllerIp));
500 } catch (Exception e) {
501 log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
502 }
503
504 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
505 treatment.extension(moveC2ToTunId, deviceId);
506 treatment.extension(tunnelDsttreatment, deviceId);
507 treatment.transition(TUNNEL_SEND_TABLE);
508
509 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
510
511 installSfcTunnelSendRule(deviceId, nshSpiId, type);
512 installSfcTunnelReceiveRule(nextDeviceId, nshSpiId, type);
513 }
514 }
515
516 public void installSfcEncapOutputRule(PortPair portPair, NshServicePathId nshSpiId, Objective.Operation type) {
517
518 DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.ingress()));
519 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress())).macAddress();
520 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
521 PortNumber port = host.location().port();
522
523 DriverHandler handler = driverService.createHandler(deviceId);
524 ExtensionSelectorResolver resolver = handler.behaviour(ExtensionSelectorResolver.class);
525
526 // Prepare selector with nsp, nsi and encap eth type
527 ExtensionSelector nshSpiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
528 ExtensionSelector nshSiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
529 ExtensionSelector nshEncapEthTypeSelector = resolver.getExtensionSelector(NICIRA_MATCH_ENCAP_ETH_TYPE.type());
530
531 try {
532 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
533 } catch (Exception e) {
534 log.error("Failed to set extension selector to match Nsh Spi Id for encap rule {}", e.getMessage());
535 }
536 try {
537 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
538 } catch (Exception e) {
539 log.error("Failed to set extension selector to match Nsh Si Id for encap rule {}", e.getMessage());
540 }
541 try {
542 nshEncapEthTypeSelector.setPropertyValue("encapEthType", ENCAP_ETH_TYPE);
543 } catch (Exception e) {
544 log.error("Failed to set extension selector to match Nsh Si Id {}", deviceId);
545 }
546 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
547 selector.extension(nshSpiSelector, deviceId);
548 selector.extension(nshSiSelector, deviceId);
549
550 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
551 ExtensionTreatment encapEthSrcTreatment = treatmentResolver
552 .getExtensionInstruction(NICIRA_ENCAP_ETH_SRC.type());
553 ExtensionTreatment encapEthDstTreatment = treatmentResolver
554 .getExtensionInstruction(NICIRA_ENCAP_ETH_DST.type());
555
556 try {
557 encapEthDstTreatment.setPropertyValue("encapEthDst", srcMacAddress);
558 } catch (Exception e) {
559 log.error("Failed to set extension treatment to set encap eth dst {}", deviceId);
560 }
561 // TODO: move from packet source mac address
562 try {
563 encapEthSrcTreatment.setPropertyValue("encapEthSrc", srcMacAddress);
564 } catch (Exception e) {
565 log.error("Failed to set extension treatment to set encap eth src {}", deviceId);
566 }
567
568 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
569 treatment.extension(encapEthSrcTreatment, deviceId);
570 treatment.extension(encapEthDstTreatment, deviceId);
571 treatment.setOutput(port);
572
573 sendSfcRule(selector, treatment, deviceId, type, ENCAP_OUTPUT_PRIORITY);
574 forwarderList.add(deviceId);
575 }
576
577 public ConnectPoint installSfcClassifierRules(PortChain portChain, PortPair portPair, NshServicePathId nshSpiId,
578 FiveTuple fiveTuple, Objective.Operation type) {
579
580 DeviceId deviceIdfromPortPair = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.ingress()));
581 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress())).macAddress();
582 VirtualPort virtualPort = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress()));
583 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
584 PortNumber port = host.location().port();
585
586 DeviceId deviceId = deviceIdfromPortPair;
587
588 // get flow classifiers
589 List<FlowClassifierId> llFlowClassifierList = portChain.flowClassifiers();
590 ListIterator<FlowClassifierId> flowClassifierListIterator = llFlowClassifierList.listIterator();
591
592 while (flowClassifierListIterator.hasNext()) {
593 FlowClassifierId flowclassifierId = flowClassifierListIterator.next();
594 FlowClassifier flowClassifier = flowClassifierService.getFlowClassifier(flowclassifierId);
595
596 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
597 deviceId = vtnRscService.getSfToSffMaping(flowClassifier.srcPort());
598 }
599
600 // Build Traffic selector.
601 TrafficSelector.Builder selector = packClassifierSelector(flowClassifier, fiveTuple);
602
603 if (fiveTuple == null) {
604 // Send the packet to controller
605 log.info("Downloading rule to send packet to controller");
606 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
607 treatment.setOutput(PortNumber.CONTROLLER);
608 sendSfcRule(selector, treatment, deviceId, type, FLOW_CLASSIFIER_PRIORITY);
609 continue;
610 }
611
612 if (deviceId != null && !deviceId.equals(deviceIdfromPortPair)) {
613 // First SF is in another device. Set tunnel ipv4 destination to
614 // treatment
615 Device remoteDevice = deviceService.getDevice(deviceIdfromPortPair);
616 String url = remoteDevice.annotations().value(SWITCH_CHANNEL_ID);
617 String remoteControllerIp = url.substring(0, url.lastIndexOf(":"));
618 if (remoteControllerIp == null) {
619 log.error("Can't find remote controller of device: {}", deviceIdfromPortPair.toString());
620 return null;
621 }
622
623 DriverHandler handler = driverService.createHandler(deviceId);
624 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
625 ExtensionTreatment tunnelDsttreatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
626 try {
627 tunnelDsttreatment.setPropertyValue("tunnelDst", Ip4Address.valueOf(remoteControllerIp));
628 } catch (Exception e) {
629 log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
630 }
631
632 TrafficTreatment.Builder treatment = packClassifierTreatment(deviceId, virtualPort, port,
633 nshSpiId, flowClassifier);
634 treatment.extension(tunnelDsttreatment, deviceId);
635 treatment.transition(TUNNEL_SEND_TABLE);
636 sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
637 classifierList.add(deviceIdfromPortPair);
638
639 installSfcTunnelSendRule(deviceId, nshSpiId, type);
640 installSfcTunnelReceiveRule(deviceIdfromPortPair, nshSpiId, type);
641
642 } else {
643 // classifier and port pair are in the same OVS. So directly
644 // send packet to first port pair
645 TrafficTreatment.Builder treatment = packClassifierTreatment(deviceIdfromPortPair, virtualPort, port,
646 nshSpiId, flowClassifier);
647 treatment.transition(ENCAP_OUTPUT_TABLE);
648 sendSfcRule(selector, treatment, deviceIdfromPortPair, type, flowClassifier.priority());
649 classifierList.add(deviceIdfromPortPair);
650 }
651 }
652
653 return host.location();
654 }
655
656 /**
657 * Pack Traffic selector.
658 *
659 * @param flowClassifier flow-classifier
660 * @param fiveTuple five tuple info for the packet
661 * @return traffic selector
662 */
663 public TrafficSelector.Builder packClassifierSelector(FlowClassifier flowClassifier, FiveTuple fiveTuple) {
664
665 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
666
667 if ((flowClassifier.srcIpPrefix() != null) && (flowClassifier.srcIpPrefix().prefixLength() != 0)) {
668 selector.matchIPSrc(flowClassifier.srcIpPrefix());
669 } else if (fiveTuple != null && fiveTuple.ipSrc() != null) {
670 selector.matchIPSrc(IpPrefix.valueOf(fiveTuple.ipSrc(), 24));
671 }
672
673 if ((flowClassifier.dstIpPrefix() != null) && (flowClassifier.dstIpPrefix().prefixLength() != 0)) {
674 selector.matchIPDst(flowClassifier.dstIpPrefix());
675 } else if (fiveTuple != null && fiveTuple.ipDst() != null) {
676 selector.matchIPDst(IpPrefix.valueOf(fiveTuple.ipDst(), 24));
677 }
678
679 if ((flowClassifier.protocol() != null) && (!flowClassifier.protocol().isEmpty())) {
680 if (flowClassifier.protocol().equalsIgnoreCase("TCP")) {
681 selector.add(Criteria.matchIPProtocol(IPv4.PROTOCOL_TCP));
682 } else if (flowClassifier.protocol().equalsIgnoreCase("UDP")) {
683 selector.add(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP));
684 } else if (flowClassifier.protocol().equalsIgnoreCase("ICMP")) {
685 selector.add(Criteria.matchIPProtocol(IPv4.PROTOCOL_ICMP));
686 }
687 } else if (fiveTuple != null && fiveTuple.protocol() != 0) {
688 selector.add(Criteria.matchIPProtocol(fiveTuple.protocol()));
689 }
690
691 if (((flowClassifier.etherType() != null) && (!flowClassifier.etherType().isEmpty()))
692 && (flowClassifier.etherType().equals("IPv4") || flowClassifier.etherType().equals("IPv6"))) {
693 if (flowClassifier.etherType().equals("IPv4")) {
694 selector.matchEthType(Ethernet.TYPE_IPV4);
695 } else {
696 selector.matchEthType(Ethernet.TYPE_IPV6);
697 }
698 }
699
700 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
701 VirtualPortId vPortId = VirtualPortId.portId(flowClassifier.srcPort().portId());
702 MacAddress macAddress = virtualPortService.getPort(vPortId).macAddress();
703 Host host = hostService.getHost(HostId.hostId(macAddress));
704 selector.matchInPort(host.location().port());
705 }
706
707 // Take the port information from five tuple only when the protocol is
708 // TCP.
709 if (fiveTuple != null && fiveTuple.protocol() == IPv4.PROTOCOL_TCP) {
710 selector.matchTcpSrc(TpPort.tpPort((int) fiveTuple.portSrc().toLong()));
711 selector.matchTcpDst(TpPort.tpPort((int) fiveTuple.portDst().toLong()));
712 } else {
713 // For udp packets take the port information from flow classifier
714 List<TpPort> srcPortRange = new LinkedList<>();
715 List<TpPort> dstPortRange = new LinkedList<>();
716 if ((flowClassifier.minSrcPortRange() != 0) && flowClassifier.maxSrcPortRange() != 0
717 && flowClassifier.minDstPortRange() != 0 && flowClassifier.maxDstPortRange() != 0) {
718
719 for (int port = flowClassifier.minSrcPortRange(); port <= flowClassifier.maxSrcPortRange(); port++) {
720 srcPortRange.add(TpPort.tpPort(port));
721 }
722 for (int port = flowClassifier.minDstPortRange(); port <= flowClassifier.maxDstPortRange(); port++) {
723 dstPortRange.add(TpPort.tpPort(port));
724 }
725 }
726
727 for (TpPort inPort : srcPortRange) {
728 selector.matchUdpSrc(inPort);
729 }
730 for (TpPort outPort : dstPortRange) {
731 selector.matchUdpDst(outPort);
732 }
733 }
734 return selector;
735 }
736
737 /**
738 * Pack traffic treatment.
739 *
740 * @param deviceId device id
741 * @param virtualPort virtual port
742 * @param port port number
743 * @param nshSpi nsh spi
744 * @param flowClassifier flow-classifier
745 * @return traffic treatment
746 */
747 public TrafficTreatment.Builder packClassifierTreatment(DeviceId deviceId, VirtualPort virtualPort,
748 PortNumber port, NshServicePathId nshSpi, FlowClassifier flowClassifier) {
749
750 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
751
752 // set tunnel id
753 SegmentationId segmentationId = tenantNetworkService.getNetwork(virtualPort.networkId()).segmentationId();
754 treatmentBuilder.add(Instructions.modTunnelId(Long.parseLong(segmentationId.toString())));
755
756 // Set all NSH header fields
757 DriverHandler handler = driverService.createHandler(deviceId);
758 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
759 ExtensionTreatment nspIdTreatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_SPI.type());
760 ExtensionTreatment nsiIdTreatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_SI.type());
761 ExtensionTreatment pushNshTreatment = resolver.getExtensionInstruction(NICIRA_PUSH_NSH.type());
762
763 ExtensionTreatment nshCh1Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH1.type());
764 ExtensionTreatment nshCh2Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH2.type());
765 ExtensionTreatment nshCh3Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH3.type());
766 ExtensionTreatment nshCh4Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH4.type());
767 ExtensionTreatment nshMdTypeTreatment = resolver.getExtensionInstruction(NICIRA_NSH_MDTYPE.type());
768 ExtensionTreatment nshNpTreatment = resolver.getExtensionInstruction(NICIRA_NSH_NP.type());
769
770 try {
771 nshMdTypeTreatment.setPropertyValue("nshMdType", ((byte) 1));
772 } catch (Exception e) {
773 log.error("Failed to get extension instruction to set nshMdType {}", deviceId);
774 }
775 try {
776 nshNpTreatment.setPropertyValue("nshNp", ((byte) 3));
777 } catch (Exception e) {
778 log.error("Failed to get extension instruction to set nshNp {}", deviceId);
779 }
780 try {
781 nspIdTreatment.setPropertyValue("nshSpi", nshSpi);
782 } catch (Exception e) {
783 log.error("Failed to get extension instruction to set Nsh Spi Id {}", deviceId);
784 }
785 try {
786 nsiIdTreatment.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
787 } catch (Exception e) {
788 log.error("Failed to get extension instruction to set Nsh Si Id {}", deviceId);
789 }
790 try {
791 nshCh1Treatment.setPropertyValue("nshCh", NshContextHeader.of(1));
792 } catch (Exception e) {
793 log.error("Failed to get extension instruction to set NshCh1 {}", deviceId);
794 }
795 try {
796 nshCh2Treatment.setPropertyValue("nshCh", NshContextHeader.of(Integer.parseInt(segmentationId.toString())));
797 } catch (Exception e) {
798 log.error("Failed to get extension instruction to set NshCh2 {}", deviceId);
799 }
800 try {
801 nshCh3Treatment.setPropertyValue("nshCh", NshContextHeader.of(3));
802 } catch (Exception e) {
803 log.error("Failed to get extension instruction to set NshCh3 {}", deviceId);
804 }
805 try {
806 nshCh4Treatment.setPropertyValue("nshCh", NshContextHeader.of(4));
807 } catch (Exception e) {
808 log.error("Failed to get extension instruction to set NshCh4 {}", deviceId);
809 }
810 treatmentBuilder.extension(pushNshTreatment, deviceId);
811 treatmentBuilder.extension(nshMdTypeTreatment, deviceId);
812 treatmentBuilder.extension(nshNpTreatment, deviceId);
813 treatmentBuilder.extension(nspIdTreatment, deviceId);
814 treatmentBuilder.extension(nsiIdTreatment, deviceId);
815 treatmentBuilder.extension(nshCh1Treatment, deviceId);
816 treatmentBuilder.extension(nshCh2Treatment, deviceId);
817 treatmentBuilder.extension(nshCh3Treatment, deviceId);
818 treatmentBuilder.extension(nshCh4Treatment, deviceId);
819
820 return treatmentBuilder;
821 }
822
823 /**
824 * Get the ControllerId from the device .
825 *
826 * @param device Device
827 * @param devices Devices
828 * @return Controller Id
829 */
830 public DeviceId getControllerId(Device device, Iterable<Device> devices) {
831 for (Device d : devices) {
832 if (d.type() == Device.Type.CONTROLLER && d.id().toString()
833 .contains(getControllerIpOfSwitch(device))) {
834 return d.id();
835 }
836 }
837 log.info("Can not find controller for device : {}", device.id());
838 return null;
839 }
840
841 /**
842 * Get the ControllerIp from the device .
843 *
844 * @param device Device
845 * @return Controller Ip
846 */
847 public String getControllerIpOfSwitch(Device device) {
848 String url = device.annotations().value(SWITCH_CHANNEL_ID);
849 return url.substring(0, url.lastIndexOf(":"));
850 }
851
852 /**
853 * Send service-function-forwarder to OVS.
854 *
855 * @param selector traffic selector
856 * @param treatment traffic treatment
857 * @param deviceId device id
858 * @param type operation type
859 * @param priority priority of classifier
860 */
861 public void sendSfcRule(TrafficSelector.Builder selector, TrafficTreatment.Builder treatment, DeviceId deviceId,
862 Objective.Operation type, int priority) {
863
864 log.info("Sending sfc flow rule. Selector {}, Treatment {}", selector.toString(),
865 treatment.toString());
866 ForwardingObjective.Builder objective = DefaultForwardingObjective.builder().withTreatment(treatment.build())
867 .withSelector(selector.build()).fromApp(appId).makePermanent().withFlag(Flag.VERSATILE)
868 .withPriority(priority);
869
870 if (type.equals(Objective.Operation.ADD)) {
871 log.debug("flowClassifierRules-->ADD");
872 flowObjectiveService.forward(deviceId, objective.add());
873 } else {
874 log.debug("flowClassifierRules-->REMOVE");
875 flowObjectiveService.forward(deviceId, objective.remove());
876 }
877 }
878
879 private PortNumber getVxlanPortNumber(DeviceId deviceId) {
880 Iterable<Port> ports = deviceService.getPorts(deviceId);
881 Port vxlanPort = Sets.newHashSet(ports).stream()
882 .filter(p ->!p.number().equals(PortNumber.LOCAL))
883 .filter(p ->p.annotations().value(AnnotationKeys.PORT_NAME)
884 .startsWith(VXLANPORT_HEAD))
885 .findFirst().get();
886 return vxlanPort.number();
887 }
888}