blob: 73fa751805ba434d2f4e9b016694270f31423d1a [file] [log] [blame]
Phaneendra Manda065d6182016-05-26 20:10:21 +05301/*
2 * Copyright 2015-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 // selector.extension(encapEthTypeSelector, deviceId);
319
320 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
321 ExtensionTreatment tunGpeNpTreatment = treatmentResolver.getExtensionInstruction(NICIRA_TUN_GPE_NP.type());
322 try {
323 tunGpeNpTreatment.setPropertyValue("tunGpeNp", ((byte) 4));
324 } catch (Exception e) {
325 log.error("Failed to get extension instruction to set tunGpeNp {}", deviceId);
326 }
327
328 ExtensionTreatment moveC1ToC1 = treatmentResolver
329 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
330 .NICIRA_MOV_NSH_C1_TO_C1.type());
331
332 ExtensionTreatment moveC2ToC2 = treatmentResolver
333 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
334 .NICIRA_MOV_NSH_C2_TO_C2.type());
335
336 ExtensionTreatment moveC3ToC3 = treatmentResolver
337 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
338 .NICIRA_MOV_NSH_C3_TO_C3.type());
339
340 ExtensionTreatment moveC4ToC4 = treatmentResolver
341 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
342 .NICIRA_MOV_NSH_C4_TO_C4.type());
343
344 ExtensionTreatment moveTunIpv4DstToTunIpv4Dst = treatmentResolver
345 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
346 .NICIRA_MOV_TUN_IPV4_DST_TO_TUN_IPV4_DST.type());
347
348 ExtensionTreatment moveTunIdToTunId = treatmentResolver
349 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
350 .NICIRA_MOV_TUN_ID_TO_TUN_ID.type());
351
352 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
353 treatment.extension(tunGpeNpTreatment, deviceId);
354 treatment.extension(moveC1ToC1, deviceId);
355 treatment.extension(moveC2ToC2, deviceId);
356 treatment.extension(moveC3ToC3, deviceId);
357 treatment.extension(moveC4ToC4, deviceId);
358 treatment.extension(moveTunIpv4DstToTunIpv4Dst, deviceId);
359 treatment.extension(moveTunIdToTunId, deviceId);
360
361 Iterable<Device> devices = deviceService.getAvailableDevices();
362 DeviceId localControllerId = getControllerId(deviceService.getDevice(deviceId), devices);
363 DriverHandler controllerHandler = driverService.createHandler(localControllerId);
364
365 BridgeConfig bridgeConfig = controllerHandler.behaviour(BridgeConfig.class);
366 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
367 String tunnelName = "vxlan-" + DEFAULT_IP;
368 ports.stream()
369 .filter(p ->p.name().equalsIgnoreCase(tunnelName))
370 .forEach(p -> {
371 treatment.setOutput(p);
372 sendSfcRule(selector, treatment, deviceId, type, TUNNEL_SEND_PRIORITY);
373 });
374 }
375
376 public void installSfcEndRule(PortPair portPair, NshServicePathId nshSpiId, Objective.Operation type) {
377 DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.egress()));
378 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())).macAddress();
379 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
380 PortNumber port = host.location().port();
381
382 // Prepare selector with nsp, nsi and inport from egress of port pair
383 DriverHandler handler = driverService.createHandler(deviceId);
384 ExtensionSelectorResolver selectorResolver = handler.behaviour(ExtensionSelectorResolver.class);
385 ExtensionSelector nshSpiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
386 ExtensionSelector nshSiSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
387 ExtensionSelector encapEthTypeSelector = selectorResolver.getExtensionSelector(NICIRA_MATCH_ENCAP_ETH_TYPE
388 .type());
389 try {
390 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
391 } catch (Exception e) {
392 log.error("Failed to set extension selector to match Nsh Spi Id for end rule {}", e.getMessage());
393 }
394 // Decrement the SI
395 nshSi = (short) (nshSi - 1);
396 try {
397 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
398 } catch (Exception e) {
399 log.error("Failed to set extension selector to match Nsh Si Id for end rule {}", e.getMessage());
400 }
401 try {
402 encapEthTypeSelector.setPropertyValue("encapEthType", ENCAP_ETH_TYPE);
403 } catch (Exception e) {
404 log.error("Failed to set extension selector to match encapEthType {}", deviceId);
405 }
406 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
407 selector.extension(encapEthTypeSelector, deviceId);
408 selector.extension(nshSpiSelector, deviceId);
409 selector.extension(nshSiSelector, deviceId);
410 selector.matchInPort(port);
411
412 // Set treatment to pop nsh header, set tunnel id and resubmit to table
413 // 0.
414 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
415 ExtensionTreatment popNshTreatment = treatmentResolver.getExtensionInstruction(NICIRA_POP_NSH.type());
416
417 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
418 treatment.extension(popNshTreatment, deviceId);
419
420 VirtualPort virtualPort = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress()));
421 SegmentationId segmentationId = tenantNetworkService.getNetwork(virtualPort.networkId()).segmentationId();
422 treatment.add(Instructions.modTunnelId(Long.parseLong(segmentationId.toString())));
423
424 ExtensionTreatment resubmitTableTreatment = treatmentResolver.getExtensionInstruction(NICIRA_RESUBMIT_TABLE
425 .type());
426
427 PortNumber vxlanPortNumber = getVxlanPortNumber(deviceId);
428
429 try {
430 resubmitTableTreatment.setPropertyValue("inPort", vxlanPortNumber);
431 } catch (Exception e) {
432 log.error("Failed to set extension treatment for resubmit table in port {}", deviceId);
433 }
434 try {
435 resubmitTableTreatment.setPropertyValue("table", ((short) 0));
436 } catch (Exception e) {
437 log.error("Failed to set extension treatment for resubmit table {}", deviceId);
438 }
439 treatment.extension(resubmitTableTreatment, deviceId);
440
441 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
442 }
443
444 public void installSfcForwardRule(PortPair portPair, PortPair nextPortPair, NshServicePathId nshSpiId,
445 Objective.Operation type) {
446 DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.egress()));
447 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())).macAddress();
448 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
449 PortNumber port = host.location().port();
450
451 DriverHandler handler = driverService.createHandler(deviceId);
452 ExtensionSelectorResolver resolver = handler.behaviour(ExtensionSelectorResolver.class);
453
454 // Prepare selector with nsp, nsi and inport from egress of port pair
455 ExtensionSelector nshSpiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
456 ExtensionSelector nshSiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
457 try {
458 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
459 } catch (Exception e) {
460 log.error("Failed to set extension selector to match Nsh Spi Id for forward rule {}", e.getMessage());
461 }
462 // Decrement the SI
463 nshSi = (short) (nshSi - 1);
464 try {
465 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
466 } catch (Exception e) {
467 log.error("Failed to set extension selector to match Nsh Si Id for forward rule {}", e.getMessage());
468 }
469 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
470 selector.extension(nshSpiSelector, deviceId);
471 selector.extension(nshSiSelector, deviceId);
472 selector.matchInPort(port);
473
474 DeviceId nextDeviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(nextPortPair.ingress()));
475 if (deviceId.equals(nextDeviceId)) {
476
477 // Treatment with transition
478 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
479 treatment.transition(ENCAP_OUTPUT_TABLE);
480
481 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
482 } else {
483 // Treatment with with transition to send on tunnel
484 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
485 ExtensionTreatment moveC2ToTunId = treatmentResolver
486 .getExtensionInstruction(ExtensionTreatmentType.ExtensionTreatmentTypes
487 .NICIRA_MOV_NSH_C2_TO_TUN_ID.type());
488
489 Device remoteDevice = deviceService.getDevice(nextDeviceId);
490 String url = remoteDevice.annotations().value(SWITCH_CHANNEL_ID);
491 String remoteControllerIp = url.substring(0, url.lastIndexOf(":"));
492 if (remoteControllerIp == null) {
493 log.error("Can't find remote controller of device: {}", nextDeviceId.toString());
494 return;
495 }
496
497 ExtensionTreatment tunnelDsttreatment = treatmentResolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST
498 .type());
499 try {
500 tunnelDsttreatment.setPropertyValue("tunnelDst", Ip4Address.valueOf(remoteControllerIp));
501 } catch (Exception e) {
502 log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
503 }
504
505 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
506 treatment.extension(moveC2ToTunId, deviceId);
507 treatment.extension(tunnelDsttreatment, deviceId);
508 treatment.transition(TUNNEL_SEND_TABLE);
509
510 sendSfcRule(selector, treatment, deviceId, type, DEFAULT_FORWARDER_PRIORITY);
511
512 installSfcTunnelSendRule(deviceId, nshSpiId, type);
513 installSfcTunnelReceiveRule(nextDeviceId, nshSpiId, type);
514 }
515 }
516
517 public void installSfcEncapOutputRule(PortPair portPair, NshServicePathId nshSpiId, Objective.Operation type) {
518
519 DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.ingress()));
520 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress())).macAddress();
521 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
522 PortNumber port = host.location().port();
523
524 DriverHandler handler = driverService.createHandler(deviceId);
525 ExtensionSelectorResolver resolver = handler.behaviour(ExtensionSelectorResolver.class);
526
527 // Prepare selector with nsp, nsi and encap eth type
528 ExtensionSelector nshSpiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SPI.type());
529 ExtensionSelector nshSiSelector = resolver.getExtensionSelector(NICIRA_MATCH_NSH_SI.type());
530 ExtensionSelector nshEncapEthTypeSelector = resolver.getExtensionSelector(NICIRA_MATCH_ENCAP_ETH_TYPE.type());
531
532 try {
533 nshSpiSelector.setPropertyValue("nshSpi", nshSpiId);
534 } catch (Exception e) {
535 log.error("Failed to set extension selector to match Nsh Spi Id for encap rule {}", e.getMessage());
536 }
537 try {
538 nshSiSelector.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
539 } catch (Exception e) {
540 log.error("Failed to set extension selector to match Nsh Si Id for encap rule {}", e.getMessage());
541 }
542 try {
543 nshEncapEthTypeSelector.setPropertyValue("encapEthType", ENCAP_ETH_TYPE);
544 } catch (Exception e) {
545 log.error("Failed to set extension selector to match Nsh Si Id {}", deviceId);
546 }
547 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
548 selector.extension(nshSpiSelector, deviceId);
549 selector.extension(nshSiSelector, deviceId);
550
551 ExtensionTreatmentResolver treatmentResolver = handler.behaviour(ExtensionTreatmentResolver.class);
552 ExtensionTreatment encapEthSrcTreatment = treatmentResolver
553 .getExtensionInstruction(NICIRA_ENCAP_ETH_SRC.type());
554 ExtensionTreatment encapEthDstTreatment = treatmentResolver
555 .getExtensionInstruction(NICIRA_ENCAP_ETH_DST.type());
556
557 try {
558 encapEthDstTreatment.setPropertyValue("encapEthDst", srcMacAddress);
559 } catch (Exception e) {
560 log.error("Failed to set extension treatment to set encap eth dst {}", deviceId);
561 }
562 // TODO: move from packet source mac address
563 try {
564 encapEthSrcTreatment.setPropertyValue("encapEthSrc", srcMacAddress);
565 } catch (Exception e) {
566 log.error("Failed to set extension treatment to set encap eth src {}", deviceId);
567 }
568
569 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
570 treatment.extension(encapEthSrcTreatment, deviceId);
571 treatment.extension(encapEthDstTreatment, deviceId);
572 treatment.setOutput(port);
573
574 sendSfcRule(selector, treatment, deviceId, type, ENCAP_OUTPUT_PRIORITY);
575 forwarderList.add(deviceId);
576 }
577
578 public ConnectPoint installSfcClassifierRules(PortChain portChain, PortPair portPair, NshServicePathId nshSpiId,
579 FiveTuple fiveTuple, Objective.Operation type) {
580
581 DeviceId deviceIdfromPortPair = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.ingress()));
582 MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress())).macAddress();
583 VirtualPort virtualPort = virtualPortService.getPort(VirtualPortId.portId(portPair.ingress()));
584 Host host = hostService.getHost(HostId.hostId(srcMacAddress));
585 PortNumber port = host.location().port();
586
587 DeviceId deviceId = deviceIdfromPortPair;
588
589 // get flow classifiers
590 List<FlowClassifierId> llFlowClassifierList = portChain.flowClassifiers();
591 ListIterator<FlowClassifierId> flowClassifierListIterator = llFlowClassifierList.listIterator();
592
593 while (flowClassifierListIterator.hasNext()) {
594 FlowClassifierId flowclassifierId = flowClassifierListIterator.next();
595 FlowClassifier flowClassifier = flowClassifierService.getFlowClassifier(flowclassifierId);
596
597 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
598 deviceId = vtnRscService.getSfToSffMaping(flowClassifier.srcPort());
599 }
600
601 // Build Traffic selector.
602 TrafficSelector.Builder selector = packClassifierSelector(flowClassifier, fiveTuple);
603
604 if (fiveTuple == null) {
605 // Send the packet to controller
606 log.info("Downloading rule to send packet to controller");
607 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
608 treatment.setOutput(PortNumber.CONTROLLER);
609 sendSfcRule(selector, treatment, deviceId, type, FLOW_CLASSIFIER_PRIORITY);
610 continue;
611 }
612
613 if (deviceId != null && !deviceId.equals(deviceIdfromPortPair)) {
614 // First SF is in another device. Set tunnel ipv4 destination to
615 // treatment
616 Device remoteDevice = deviceService.getDevice(deviceIdfromPortPair);
617 String url = remoteDevice.annotations().value(SWITCH_CHANNEL_ID);
618 String remoteControllerIp = url.substring(0, url.lastIndexOf(":"));
619 if (remoteControllerIp == null) {
620 log.error("Can't find remote controller of device: {}", deviceIdfromPortPair.toString());
621 return null;
622 }
623
624 DriverHandler handler = driverService.createHandler(deviceId);
625 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
626 ExtensionTreatment tunnelDsttreatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
627 try {
628 tunnelDsttreatment.setPropertyValue("tunnelDst", Ip4Address.valueOf(remoteControllerIp));
629 } catch (Exception e) {
630 log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
631 }
632
633 TrafficTreatment.Builder treatment = packClassifierTreatment(deviceId, virtualPort, port,
634 nshSpiId, flowClassifier);
635 treatment.extension(tunnelDsttreatment, deviceId);
636 treatment.transition(TUNNEL_SEND_TABLE);
637 sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
Phaneendra Manda2360d252016-06-15 18:53:30 +0530638
639 selector.matchInPort(PortNumber.CONTROLLER);
640 sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
641 classifierList.add(deviceId);
Phaneendra Manda065d6182016-05-26 20:10:21 +0530642
643 installSfcTunnelSendRule(deviceId, nshSpiId, type);
644 installSfcTunnelReceiveRule(deviceIdfromPortPair, nshSpiId, type);
645
646 } else {
647 // classifier and port pair are in the same OVS. So directly
648 // send packet to first port pair
649 TrafficTreatment.Builder treatment = packClassifierTreatment(deviceIdfromPortPair, virtualPort, port,
650 nshSpiId, flowClassifier);
651 treatment.transition(ENCAP_OUTPUT_TABLE);
652 sendSfcRule(selector, treatment, deviceIdfromPortPair, type, flowClassifier.priority());
Phaneendra Manda2360d252016-06-15 18:53:30 +0530653
654 selector.matchInPort(PortNumber.CONTROLLER);
655 sendSfcRule(selector, treatment, deviceId, type, flowClassifier.priority());
Phaneendra Manda065d6182016-05-26 20:10:21 +0530656 classifierList.add(deviceIdfromPortPair);
657 }
658 }
659
660 return host.location();
661 }
662
663 /**
664 * Pack Traffic selector.
665 *
666 * @param flowClassifier flow-classifier
667 * @param fiveTuple five tuple info for the packet
668 * @return traffic selector
669 */
670 public TrafficSelector.Builder packClassifierSelector(FlowClassifier flowClassifier, FiveTuple fiveTuple) {
671
672 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
673
674 if ((flowClassifier.srcIpPrefix() != null) && (flowClassifier.srcIpPrefix().prefixLength() != 0)) {
675 selector.matchIPSrc(flowClassifier.srcIpPrefix());
676 } else if (fiveTuple != null && fiveTuple.ipSrc() != null) {
677 selector.matchIPSrc(IpPrefix.valueOf(fiveTuple.ipSrc(), 24));
678 }
679
680 if ((flowClassifier.dstIpPrefix() != null) && (flowClassifier.dstIpPrefix().prefixLength() != 0)) {
681 selector.matchIPDst(flowClassifier.dstIpPrefix());
682 } else if (fiveTuple != null && fiveTuple.ipDst() != null) {
683 selector.matchIPDst(IpPrefix.valueOf(fiveTuple.ipDst(), 24));
684 }
685
686 if ((flowClassifier.protocol() != null) && (!flowClassifier.protocol().isEmpty())) {
687 if (flowClassifier.protocol().equalsIgnoreCase("TCP")) {
688 selector.add(Criteria.matchIPProtocol(IPv4.PROTOCOL_TCP));
689 } else if (flowClassifier.protocol().equalsIgnoreCase("UDP")) {
690 selector.add(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP));
691 } else if (flowClassifier.protocol().equalsIgnoreCase("ICMP")) {
692 selector.add(Criteria.matchIPProtocol(IPv4.PROTOCOL_ICMP));
693 }
694 } else if (fiveTuple != null && fiveTuple.protocol() != 0) {
695 selector.add(Criteria.matchIPProtocol(fiveTuple.protocol()));
696 }
697
698 if (((flowClassifier.etherType() != null) && (!flowClassifier.etherType().isEmpty()))
699 && (flowClassifier.etherType().equals("IPv4") || flowClassifier.etherType().equals("IPv6"))) {
700 if (flowClassifier.etherType().equals("IPv4")) {
701 selector.matchEthType(Ethernet.TYPE_IPV4);
702 } else {
703 selector.matchEthType(Ethernet.TYPE_IPV6);
704 }
705 }
706
707 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
708 VirtualPortId vPortId = VirtualPortId.portId(flowClassifier.srcPort().portId());
709 MacAddress macAddress = virtualPortService.getPort(vPortId).macAddress();
710 Host host = hostService.getHost(HostId.hostId(macAddress));
711 selector.matchInPort(host.location().port());
712 }
713
714 // Take the port information from five tuple only when the protocol is
715 // TCP.
716 if (fiveTuple != null && fiveTuple.protocol() == IPv4.PROTOCOL_TCP) {
717 selector.matchTcpSrc(TpPort.tpPort((int) fiveTuple.portSrc().toLong()));
718 selector.matchTcpDst(TpPort.tpPort((int) fiveTuple.portDst().toLong()));
719 } else {
720 // For udp packets take the port information from flow classifier
721 List<TpPort> srcPortRange = new LinkedList<>();
722 List<TpPort> dstPortRange = new LinkedList<>();
723 if ((flowClassifier.minSrcPortRange() != 0) && flowClassifier.maxSrcPortRange() != 0
724 && flowClassifier.minDstPortRange() != 0 && flowClassifier.maxDstPortRange() != 0) {
725
726 for (int port = flowClassifier.minSrcPortRange(); port <= flowClassifier.maxSrcPortRange(); port++) {
727 srcPortRange.add(TpPort.tpPort(port));
728 }
729 for (int port = flowClassifier.minDstPortRange(); port <= flowClassifier.maxDstPortRange(); port++) {
730 dstPortRange.add(TpPort.tpPort(port));
731 }
732 }
733
734 for (TpPort inPort : srcPortRange) {
735 selector.matchUdpSrc(inPort);
736 }
737 for (TpPort outPort : dstPortRange) {
738 selector.matchUdpDst(outPort);
739 }
740 }
741 return selector;
742 }
743
744 /**
745 * Pack traffic treatment.
746 *
747 * @param deviceId device id
748 * @param virtualPort virtual port
749 * @param port port number
750 * @param nshSpi nsh spi
751 * @param flowClassifier flow-classifier
752 * @return traffic treatment
753 */
754 public TrafficTreatment.Builder packClassifierTreatment(DeviceId deviceId, VirtualPort virtualPort,
755 PortNumber port, NshServicePathId nshSpi, FlowClassifier flowClassifier) {
756
757 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
758
759 // set tunnel id
760 SegmentationId segmentationId = tenantNetworkService.getNetwork(virtualPort.networkId()).segmentationId();
761 treatmentBuilder.add(Instructions.modTunnelId(Long.parseLong(segmentationId.toString())));
762
763 // Set all NSH header fields
764 DriverHandler handler = driverService.createHandler(deviceId);
765 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
766 ExtensionTreatment nspIdTreatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_SPI.type());
767 ExtensionTreatment nsiIdTreatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_SI.type());
768 ExtensionTreatment pushNshTreatment = resolver.getExtensionInstruction(NICIRA_PUSH_NSH.type());
769
770 ExtensionTreatment nshCh1Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH1.type());
771 ExtensionTreatment nshCh2Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH2.type());
772 ExtensionTreatment nshCh3Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH3.type());
773 ExtensionTreatment nshCh4Treatment = resolver.getExtensionInstruction(NICIRA_SET_NSH_CH4.type());
774 ExtensionTreatment nshMdTypeTreatment = resolver.getExtensionInstruction(NICIRA_NSH_MDTYPE.type());
775 ExtensionTreatment nshNpTreatment = resolver.getExtensionInstruction(NICIRA_NSH_NP.type());
776
777 try {
778 nshMdTypeTreatment.setPropertyValue("nshMdType", ((byte) 1));
779 } catch (Exception e) {
780 log.error("Failed to get extension instruction to set nshMdType {}", deviceId);
781 }
782 try {
783 nshNpTreatment.setPropertyValue("nshNp", ((byte) 3));
784 } catch (Exception e) {
785 log.error("Failed to get extension instruction to set nshNp {}", deviceId);
786 }
787 try {
788 nspIdTreatment.setPropertyValue("nshSpi", nshSpi);
789 } catch (Exception e) {
790 log.error("Failed to get extension instruction to set Nsh Spi Id {}", deviceId);
791 }
792 try {
793 nsiIdTreatment.setPropertyValue("nshSi", NshServiceIndex.of(nshSi));
794 } catch (Exception e) {
795 log.error("Failed to get extension instruction to set Nsh Si Id {}", deviceId);
796 }
797 try {
798 nshCh1Treatment.setPropertyValue("nshCh", NshContextHeader.of(1));
799 } catch (Exception e) {
800 log.error("Failed to get extension instruction to set NshCh1 {}", deviceId);
801 }
802 try {
803 nshCh2Treatment.setPropertyValue("nshCh", NshContextHeader.of(Integer.parseInt(segmentationId.toString())));
804 } catch (Exception e) {
805 log.error("Failed to get extension instruction to set NshCh2 {}", deviceId);
806 }
807 try {
808 nshCh3Treatment.setPropertyValue("nshCh", NshContextHeader.of(3));
809 } catch (Exception e) {
810 log.error("Failed to get extension instruction to set NshCh3 {}", deviceId);
811 }
812 try {
813 nshCh4Treatment.setPropertyValue("nshCh", NshContextHeader.of(4));
814 } catch (Exception e) {
815 log.error("Failed to get extension instruction to set NshCh4 {}", deviceId);
816 }
817 treatmentBuilder.extension(pushNshTreatment, deviceId);
818 treatmentBuilder.extension(nshMdTypeTreatment, deviceId);
819 treatmentBuilder.extension(nshNpTreatment, deviceId);
820 treatmentBuilder.extension(nspIdTreatment, deviceId);
821 treatmentBuilder.extension(nsiIdTreatment, deviceId);
822 treatmentBuilder.extension(nshCh1Treatment, deviceId);
823 treatmentBuilder.extension(nshCh2Treatment, deviceId);
824 treatmentBuilder.extension(nshCh3Treatment, deviceId);
825 treatmentBuilder.extension(nshCh4Treatment, deviceId);
826
827 return treatmentBuilder;
828 }
829
830 /**
831 * Get the ControllerId from the device .
832 *
833 * @param device Device
834 * @param devices Devices
835 * @return Controller Id
836 */
837 public DeviceId getControllerId(Device device, Iterable<Device> devices) {
838 for (Device d : devices) {
839 if (d.type() == Device.Type.CONTROLLER && d.id().toString()
840 .contains(getControllerIpOfSwitch(device))) {
841 return d.id();
842 }
843 }
844 log.info("Can not find controller for device : {}", device.id());
845 return null;
846 }
847
848 /**
849 * Get the ControllerIp from the device .
850 *
851 * @param device Device
852 * @return Controller Ip
853 */
854 public String getControllerIpOfSwitch(Device device) {
855 String url = device.annotations().value(SWITCH_CHANNEL_ID);
856 return url.substring(0, url.lastIndexOf(":"));
857 }
858
859 /**
860 * Send service-function-forwarder to OVS.
861 *
862 * @param selector traffic selector
863 * @param treatment traffic treatment
864 * @param deviceId device id
865 * @param type operation type
866 * @param priority priority of classifier
867 */
868 public void sendSfcRule(TrafficSelector.Builder selector, TrafficTreatment.Builder treatment, DeviceId deviceId,
869 Objective.Operation type, int priority) {
870
871 log.info("Sending sfc flow rule. Selector {}, Treatment {}", selector.toString(),
872 treatment.toString());
873 ForwardingObjective.Builder objective = DefaultForwardingObjective.builder().withTreatment(treatment.build())
874 .withSelector(selector.build()).fromApp(appId).makePermanent().withFlag(Flag.VERSATILE)
875 .withPriority(priority);
876
877 if (type.equals(Objective.Operation.ADD)) {
878 log.debug("flowClassifierRules-->ADD");
879 flowObjectiveService.forward(deviceId, objective.add());
880 } else {
881 log.debug("flowClassifierRules-->REMOVE");
882 flowObjectiveService.forward(deviceId, objective.remove());
883 }
884 }
885
886 private PortNumber getVxlanPortNumber(DeviceId deviceId) {
887 Iterable<Port> ports = deviceService.getPorts(deviceId);
888 Port vxlanPort = Sets.newHashSet(ports).stream()
889 .filter(p ->!p.number().equals(PortNumber.LOCAL))
890 .filter(p ->p.annotations().value(AnnotationKeys.PORT_NAME)
891 .startsWith(VXLANPORT_HEAD))
892 .findFirst().get();
893 return vxlanPort.number();
894 }
895}