blob: 2acb87805516fb5530d5c06536ecb776555ece27 [file] [log] [blame]
Mahesh Poojary S335e7c32015-10-29 10:16:51 +05301/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Mahesh Poojary S335e7c32015-10-29 10:16:51 +05303 *
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.manager.impl;
17
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053018import static org.slf4j.LoggerFactory.getLogger;
19
Phaneendra Mandab3555032016-02-08 11:41:53 +053020import java.util.Collection;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053021import java.util.Iterator;
22import java.util.List;
23import java.util.Optional;
Phaneendra Mandab3555032016-02-08 11:41:53 +053024import java.util.Set;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053025
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053031import org.apache.felix.scr.annotations.Service;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053032import org.onlab.packet.Ethernet;
33import org.onlab.packet.IPv4;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053034import org.onlab.packet.IpAddress;
35import org.onlab.packet.MacAddress;
Phaneendra Mandab3555032016-02-08 11:41:53 +053036import org.onlab.packet.TCP;
37import org.onlab.packet.UDP;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053038import org.onlab.util.ItemNotFoundException;
Jonathan Hart51539b82015-10-29 09:53:04 -070039import org.onlab.util.KryoNamespace;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053040import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053042import org.onosproject.core.IdGenerator;
43import org.onosproject.net.ConnectPoint;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053044import org.onosproject.net.NshServicePathId;
Phaneendra Mandab3555032016-02-08 11:41:53 +053045import org.onosproject.net.PortNumber;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053046import org.onosproject.net.flow.DefaultTrafficTreatment;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.packet.DefaultOutboundPacket;
49import org.onosproject.net.packet.OutboundPacket;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053050import org.onosproject.net.packet.PacketContext;
51import org.onosproject.net.packet.PacketProcessor;
52import org.onosproject.net.packet.PacketService;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053053import org.onosproject.sfc.forwarder.ServiceFunctionForwarderService;
54import org.onosproject.sfc.forwarder.impl.ServiceFunctionForwarderImpl;
55import org.onosproject.sfc.installer.FlowClassifierInstallerService;
56import org.onosproject.sfc.installer.impl.FlowClassifierInstallerImpl;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053057import org.onosproject.sfc.manager.SfcService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053058import org.onosproject.store.serializers.KryoNamespaces;
59import org.onosproject.store.service.DistributedSet;
60import org.onosproject.store.service.EventuallyConsistentMap;
61import org.onosproject.store.service.Serializer;
62import org.onosproject.store.service.StorageService;
63import org.onosproject.store.service.WallClockTimestamp;
Phaneendra Mandab3555032016-02-08 11:41:53 +053064import org.onosproject.vtnrsc.DefaultFiveTuple;
65import org.onosproject.vtnrsc.FiveTuple;
66import org.onosproject.vtnrsc.FixedIp;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053067import org.onosproject.vtnrsc.FlowClassifier;
68import org.onosproject.vtnrsc.FlowClassifierId;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053069import org.onosproject.vtnrsc.LoadBalanceId;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053070import org.onosproject.vtnrsc.PortChain;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053071import org.onosproject.vtnrsc.PortChainId;
Jonathan Hart51539b82015-10-29 09:53:04 -070072import org.onosproject.vtnrsc.PortPair;
73import org.onosproject.vtnrsc.PortPairGroup;
74import org.onosproject.vtnrsc.PortPairGroupId;
75import org.onosproject.vtnrsc.PortPairId;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053076import org.onosproject.vtnrsc.TenantId;
Phaneendra Mandab3555032016-02-08 11:41:53 +053077import org.onosproject.vtnrsc.VirtualPort;
78import org.onosproject.vtnrsc.VirtualPortId;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053079import org.onosproject.vtnrsc.event.VtnRscEvent;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053080import org.onosproject.vtnrsc.event.VtnRscEventFeedback;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053081import org.onosproject.vtnrsc.event.VtnRscListener;
Phaneendra Mandab3555032016-02-08 11:41:53 +053082import org.onosproject.vtnrsc.flowclassifier.FlowClassifierService;
83import org.onosproject.vtnrsc.portchain.PortChainService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053084import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053085import org.onosproject.vtnrsc.service.VtnRscService;
Phaneendra Mandab3555032016-02-08 11:41:53 +053086import org.onosproject.vtnrsc.virtualport.VirtualPortService;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053087import org.slf4j.Logger;
88
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053089import com.google.common.collect.Lists;
90
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053091/**
92 * Provides implementation of SFC Service.
93 */
94@Component(immediate = true)
95@Service
96public class SfcManager implements SfcService {
97
98 private final Logger log = getLogger(getClass());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053099
100 private String nshSpiIdTopic = "nsh-spi-id";
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530101 private static final String APP_ID = "org.onosproject.app.vtn";
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530102 private static final int SFC_PRIORITY = 1000;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530103 private static final int NULL_PORT = 0;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530104 private static final int MAX_NSH_SPI_ID = 0x7FFFF;
105 private static final int MAX_LOAD_BALANCE_ID = 0x20;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected VtnRscService vtnRscService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected CoreService coreService;
112
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected PacketService packetService;
115
Phaneendra Mandab3555032016-02-08 11:41:53 +0530116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected PortChainService portChainService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530120 protected PortPairGroupService portPairGroupService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530123 protected FlowClassifierService flowClassifierService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected VirtualPortService virtualPortService;
127
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected StorageService storageService;
130
131 protected SfcPacketProcessor processor = new SfcPacketProcessor();
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530132
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530133 protected ApplicationId appId;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530134 protected ServiceFunctionForwarderService serviceFunctionForwarder;
135 protected FlowClassifierInstallerService flowClassifierInstaller;
136 protected IdGenerator nshSpiIdGenerator;
137 protected EventuallyConsistentMap<PortChainId, Integer> nshSpiPortChainMap;
138 protected DistributedSet<Integer> nshSpiIdFreeList;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530139
140 private final VtnRscListener vtnRscListener = new InnerVtnRscListener();
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530141
142 @Activate
143 public void activate() {
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530144 appId = coreService.registerApplication(APP_ID);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530145 serviceFunctionForwarder = new ServiceFunctionForwarderImpl(appId);
146 flowClassifierInstaller = new FlowClassifierInstallerImpl(appId);
147 nshSpiIdGenerator = coreService.getIdGenerator(nshSpiIdTopic);
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530148
149 vtnRscService.addListener(vtnRscListener);
150
151 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
152 .register(TenantId.class)
153 .register(PortPairId.class)
154 .register(PortPairGroupId.class)
155 .register(FlowClassifierId.class)
156 .register(PortChainId.class);
157
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530158 nshSpiPortChainMap = storageService.<PortChainId, Integer>eventuallyConsistentMapBuilder()
159 .withName("nshSpiPortChainMap")
160 .withSerializer(serializer)
161 .withTimestampProvider((k, v) -> new WallClockTimestamp())
162 .build();
163
164 nshSpiIdFreeList = storageService.<Integer>setBuilder()
165 .withName("nshSpiIdDeletedList")
166 .withSerializer(Serializer.using(KryoNamespaces.API))
167 .build()
168 .asDistributedSet();
169
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530170 packetService.addProcessor(processor, PacketProcessor.director(SFC_PRIORITY));
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530171 log.info("Started");
172 }
173
174 @Deactivate
175 public void deactivate() {
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530176 vtnRscService.removeListener(vtnRscListener);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530177 packetService.removeProcessor(processor);
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530178 log.info("Stopped");
179 }
180
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530181 /*
182 * Handle events.
183 */
184 private class InnerVtnRscListener implements VtnRscListener {
185 @Override
186 public void event(VtnRscEvent event) {
187
188 if (VtnRscEvent.Type.PORT_PAIR_PUT == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530189 PortPair portPair = ((VtnRscEventFeedback) event.subject()).portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530190 onPortPairCreated(portPair);
191 } else if (VtnRscEvent.Type.PORT_PAIR_DELETE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530192 PortPair portPair = ((VtnRscEventFeedback) event.subject()).portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530193 onPortPairDeleted(portPair);
194 } else if (VtnRscEvent.Type.PORT_PAIR_UPDATE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530195 PortPair portPair = ((VtnRscEventFeedback) event.subject()).portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530196 onPortPairDeleted(portPair);
197 onPortPairCreated(portPair);
198 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_PUT == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530199 PortPairGroup portPairGroup = ((VtnRscEventFeedback) event.subject()).portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530200 onPortPairGroupCreated(portPairGroup);
201 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_DELETE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530202 PortPairGroup portPairGroup = ((VtnRscEventFeedback) event.subject()).portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530203 onPortPairGroupDeleted(portPairGroup);
204 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_UPDATE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530205 PortPairGroup portPairGroup = ((VtnRscEventFeedback) event.subject()).portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530206 onPortPairGroupDeleted(portPairGroup);
207 onPortPairGroupCreated(portPairGroup);
208 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_PUT == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530209 FlowClassifier flowClassifier = ((VtnRscEventFeedback) event.subject()).flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530210 onFlowClassifierCreated(flowClassifier);
211 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_DELETE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530212 FlowClassifier flowClassifier = ((VtnRscEventFeedback) event.subject()).flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530213 onFlowClassifierDeleted(flowClassifier);
214 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_UPDATE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530215 FlowClassifier flowClassifier = ((VtnRscEventFeedback) event.subject()).flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530216 onFlowClassifierDeleted(flowClassifier);
217 onFlowClassifierCreated(flowClassifier);
218 } else if (VtnRscEvent.Type.PORT_CHAIN_PUT == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530219 PortChain portChain = (PortChain) ((VtnRscEventFeedback) event.subject()).portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530220 onPortChainCreated(portChain);
221 } else if (VtnRscEvent.Type.PORT_CHAIN_DELETE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530222 PortChain portChain = (PortChain) ((VtnRscEventFeedback) event.subject()).portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530223 onPortChainDeleted(portChain);
224 } else if (VtnRscEvent.Type.PORT_CHAIN_UPDATE == event.type()) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530225 PortChain portChain = (PortChain) ((VtnRscEventFeedback) event.subject()).portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530226 onPortChainDeleted(portChain);
227 onPortChainCreated(portChain);
228 }
229 }
230 }
231
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530232 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530233 public void onPortPairCreated(PortPair portPair) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530234 log.debug("onPortPairCreated");
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530235 // TODO: Modify forwarding rule on port-pair creation.
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530236 }
237
238 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530239 public void onPortPairDeleted(PortPair portPair) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530240 log.debug("onPortPairDeleted");
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530241 // TODO: Modify forwarding rule on port-pair deletion.
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530242 }
243
244 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530245 public void onPortPairGroupCreated(PortPairGroup portPairGroup) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530246 log.debug("onPortPairGroupCreated");
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530247 // TODO: Modify forwarding rule on port-pair-group creation.
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530248 }
249
250 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530251 public void onPortPairGroupDeleted(PortPairGroup portPairGroup) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530252 log.debug("onPortPairGroupDeleted");
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530253 // TODO: Modify forwarding rule on port-pair-group deletion.
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530254 }
255
256 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530257 public void onFlowClassifierCreated(FlowClassifier flowClassifier) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530258 log.debug("onFlowClassifierCreated");
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530259 // TODO: Modify forwarding rule on flow-classifier creation.
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530260 }
261
262 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530263 public void onFlowClassifierDeleted(FlowClassifier flowClassifier) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530264 log.debug("onFlowClassifierDeleted");
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530265 // TODO: Modify forwarding rule on flow-classifier deletion.
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530266 }
267
268 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530269 public void onPortChainCreated(PortChain portChain) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700270 NshServicePathId nshSpi;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530271 log.info("onPortChainCreated");
272 if (nshSpiPortChainMap.containsKey(portChain.portChainId())) {
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530273 nshSpi = NshServicePathId.of(nshSpiPortChainMap.get(portChain.portChainId()));
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530274 } else {
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530275 int id = getNextNshSpi();
276 if (id > MAX_NSH_SPI_ID) {
277 log.error("Reached max limit of service path index."
278 + "Failed to install SFC for port chain {}", portChain.portChainId().toString());
279 return;
280 }
281 nshSpi = NshServicePathId.of(id);
282 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(id));
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530283 }
284
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530285 // Install classifier rule to send the packet to controller
286 flowClassifierInstaller.installFlowClassifier(portChain, nshSpi);
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530287 }
288
289 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530290 public void onPortChainDeleted(PortChain portChain) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530291 log.info("onPortChainDeleted");
292 if (!nshSpiPortChainMap.containsKey(portChain.portChainId())) {
293 throw new ItemNotFoundException("Unable to find NSH SPI");
294 }
295
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530296 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
297 // Uninstall classifier rules
298 flowClassifierInstaller.unInstallFlowClassifier(portChain, NshServicePathId.of(nshSpiId));
299 // remove from nshSpiPortChainMap and add to nshSpiIdFreeList
300 nshSpiPortChainMap.remove(portChain.portChainId());
301 nshSpiIdFreeList.add(nshSpiId);
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530302
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530303 // Uninstall load balanced classifier and forwarding rules.
304 NshServicePathId nshSpi;
305 LoadBalanceId id;
306 List<LoadBalanceId> processedIdList = Lists.newArrayList();
307 Set<FiveTuple> fiveTupleSet = portChain.getLoadBalanceIdMapKeys();
308 for (FiveTuple fiveTuple : fiveTupleSet) {
309 id = portChain.getLoadBalanceId(fiveTuple);
310 if (processedIdList.contains(id)) {
311 // multiple five tuple can have single path.
312 continue;
313 } else {
314 processedIdList.add(id);
315 }
316 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
317 flowClassifierInstaller.unInstallLoadBalancedFlowClassifier(portChain, fiveTuple, nshSpi);
318 serviceFunctionForwarder.unInstallLoadBalancedForwardingRule(portChain.getLoadBalancePath(fiveTuple),
319 nshSpi);
320 }
321 }
322
323 /**
324 * Get next nsh service path identifier.
325 *
326 * @return value of service path identifier
327 */
328 int getNextNshSpi() {
329 // If there is any free id use it. Otherwise generate new id.
330 if (nshSpiIdFreeList.isEmpty()) {
331 return (int) nshSpiIdGenerator.getNewId();
332 }
333 Iterator<Integer> it = nshSpiIdFreeList.iterator();
334 Integer value = it.next();
335 nshSpiIdFreeList.remove(value);
336 return value;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530337 }
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530338
339 private class SfcPacketProcessor implements PacketProcessor {
340
Phaneendra Mandab3555032016-02-08 11:41:53 +0530341 /**
342 * Check for given ip match with the fixed ips for the virtual port.
343 *
344 * @param vPortId virtual port id
345 * @param ip ip address to match
346 * @return true if the ip match with the fixed ips in virtual port false otherwise
347 */
348 private boolean checkIpInVirtualPort(VirtualPortId vPortId, IpAddress ip) {
349 boolean found = false;
350 Set<FixedIp> ips = virtualPortService.getPort(vPortId).fixedIps();
351 for (FixedIp fixedIp : ips) {
352 if (fixedIp.ip().equals(ip)) {
353 found = true;
354 break;
355 }
356 }
357 return found;
358 }
359
360 /**
361 * Find the port chain for the received packet.
362 *
363 * @param fiveTuple five tuple info from the packet
364 * @return portChainId id of port chain
365 */
366 private PortChainId findPortChainFromFiveTuple(FiveTuple fiveTuple) {
367
368 PortChainId portChainId = null;
369
370 Iterable<PortChain> portChains = portChainService.getPortChains();
371 if (portChains == null) {
372 log.error("Could not retrive port chain list");
373 }
374
375 // Identify the port chain to which the packet belongs
376 for (final PortChain portChain : portChains) {
377
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530378 if (!portChain.tenantId().equals(fiveTuple.tenantId())) {
379 continue;
380 }
381
Phaneendra Mandab3555032016-02-08 11:41:53 +0530382 Iterable<FlowClassifierId> flowClassifiers = portChain.flowClassifiers();
383
384 // One port chain can have multiple flow classifiers.
385 for (final FlowClassifierId flowClassifierId : flowClassifiers) {
386
387 FlowClassifier flowClassifier = flowClassifierService.getFlowClassifier(flowClassifierId);
388 boolean match = false;
389 // Check whether protocol is set in flow classifier
390 if (flowClassifier.protocol() != null) {
391 if ((flowClassifier.protocol().equals("TCP") && fiveTuple.protocol() == IPv4.PROTOCOL_TCP) ||
392 (flowClassifier.protocol().equals("UDP") &&
393 fiveTuple.protocol() == IPv4.PROTOCOL_UDP)) {
394 match = true;
395 } else {
396 continue;
397 }
398 }
399
400 // Check whether source ip prefix is set in flow classifier
401 if (flowClassifier.srcIpPrefix() != null) {
402 if (flowClassifier.srcIpPrefix().contains(fiveTuple.ipSrc())) {
403 match = true;
404 } else {
405 continue;
406 }
407 }
408
409 // Check whether destination ip prefix is set in flow classifier
410 if (flowClassifier.dstIpPrefix() != null) {
411 if (flowClassifier.dstIpPrefix().contains(fiveTuple.ipDst())) {
412 match = true;
413 } else {
414 continue;
415 }
416 }
417
418 // Check whether source port is set in flow classifier
419 if (fiveTuple.portSrc().toLong() >= flowClassifier.minSrcPortRange() ||
420 fiveTuple.portSrc().toLong() <= flowClassifier.maxSrcPortRange()) {
421 match = true;
422 } else {
423 continue;
424 }
425
426 // Check whether destination port is set in flow classifier
427 if (fiveTuple.portDst().toLong() >= flowClassifier.minSrcPortRange() ||
428 fiveTuple.portDst().toLong() <= flowClassifier.maxSrcPortRange()) {
429 match = true;
430 } else {
431 continue;
432 }
433
434 // Check whether neutron source port is set in flow classfier
435 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
436 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.srcPort().portId()),
437 fiveTuple.ipSrc());
438 if (!match) {
439 continue;
440 }
441 }
442
443 // Check whether destination neutron destination port is set in flow classifier
444 if ((flowClassifier.dstPort() != null) && (!flowClassifier.dstPort().portId().isEmpty())) {
445 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.dstPort().portId()),
446 fiveTuple.ipDst());
447 if (!match) {
448 continue;
449 }
450 }
451
452 if (match) {
453 portChainId = portChain.portChainId();
454 break;
455 }
456 }
457 }
458 return portChainId;
459 }
460
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530461 /**
462 * Find the load balanced path set it to port chain for the given five tuple.
463 *
464 * @param portChainId port chain id
465 * @param fiveTuple five tuple info
466 * @return load balance id
467 */
468 private LoadBalanceId loadBalanceSfc(PortChainId portChainId, FiveTuple fiveTuple) {
469
470 // Get the port chain
471 PortChain portChain = portChainService.getPortChain(portChainId);
472 List<PortPairId> loadBalancePath = Lists.newArrayList();
473 LoadBalanceId id;
474 int paths = portChain.getLoadBalancePathSize();
475 if (paths >= MAX_LOAD_BALANCE_ID) {
476 log.info("Max limit reached for load balance paths. "
477 + "Reusing the created path for port chain {} with five tuple {}",
478 portChainId, fiveTuple);
479 id = LoadBalanceId.of((byte) ((paths + 1) % MAX_LOAD_BALANCE_ID));
480 portChain.addLoadBalancePath(fiveTuple, id, portChain.getLoadBalancePath(id));
481 }
482
483 // Get the list of port pair groups from port chain
484 Iterable<PortPairGroupId> portPairGroups = portChain.portPairGroups();
485 for (final PortPairGroupId portPairGroupId : portPairGroups) {
486 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
487
488 // Get the list of port pair ids from port pair group.
489 Iterable<PortPairId> portPairs = portPairGroup.portPairs();
490 int minLoad = 0xFFF;
491 PortPairId minLoadPortPairId = null;
492 for (final PortPairId portPairId : portPairs) {
493 int load = portPairGroup.getLoad(portPairId);
494 if (load == 0) {
495 minLoadPortPairId = portPairId;
496 break;
497 } else {
498 // Check the port pair which has min load.
499 if (load < minLoad) {
500 minLoad = load;
501 minLoadPortPairId = portPairId;
502 }
503 }
504 }
505 if (minLoadPortPairId != null) {
506 loadBalancePath.add(minLoadPortPairId);
507 portPairGroup.addLoad(minLoadPortPairId);
508 }
509 }
510
511 // Check if the path already exists, if not create a new id
512 Optional<LoadBalanceId> output = portChain.matchPath(loadBalancePath);
513 if (output.isPresent()) {
514 id = output.get();
515 } else {
516 id = LoadBalanceId.of((byte) (paths + 1));
517 }
518
519 portChain.addLoadBalancePath(fiveTuple, id, loadBalancePath);
520 return id;
521 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530522
523 /**
524 * Get the tenant id for the given mac address.
525 *
526 * @param mac mac address
527 * @return tenantId tenant id for the given mac address
528 */
529 private TenantId getTenantId(MacAddress mac) {
530 Collection<VirtualPort> virtualPorts = virtualPortService.getPorts();
531 for (VirtualPort virtualPort : virtualPorts) {
532 if (virtualPort.macAddress().equals(mac)) {
533 return virtualPort.tenantId();
534 }
535 }
536 return null;
537 }
538
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530539 @Override
540 public void process(PacketContext context) {
541 Ethernet packet = context.inPacket().parsed();
542 if (packet == null) {
543 return;
544 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530545 // get the five tuple parameters for the packet
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530546 short ethType = packet.getEtherType();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530547 IpAddress ipSrc = null;
548 IpAddress ipDst = null;
549 int portSrc = 0;
550 int portDst = 0;
551 byte protocol = 0;
552 MacAddress macSrc = packet.getSourceMAC();
553 TenantId tenantId = getTenantId(macSrc);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530554
555 if (ethType == Ethernet.TYPE_IPV4) {
556 IPv4 ipv4Packet = (IPv4) packet.getPayload();
557 ipSrc = IpAddress.valueOf(ipv4Packet.getSourceAddress());
558 ipDst = IpAddress.valueOf(ipv4Packet.getDestinationAddress());
Phaneendra Mandab3555032016-02-08 11:41:53 +0530559 protocol = ipv4Packet.getProtocol();
560 if (protocol == IPv4.PROTOCOL_TCP) {
561 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
562 portSrc = tcpPacket.getSourcePort();
563 portDst = tcpPacket.getDestinationPort();
564 } else if (protocol == IPv4.PROTOCOL_UDP) {
565 UDP udpPacket = (UDP) ipv4Packet.getPayload();
566 portSrc = udpPacket.getSourcePort();
567 portDst = udpPacket.getDestinationPort();
568 }
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530569 } else if (ethType == Ethernet.TYPE_IPV6) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530570 return;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530571 }
572
Phaneendra Mandab3555032016-02-08 11:41:53 +0530573
574 FiveTuple fiveTuple = DefaultFiveTuple.builder()
575 .setIpSrc(ipSrc)
576 .setIpDst(ipDst)
577 .setPortSrc(PortNumber.portNumber(portSrc))
578 .setPortDst(PortNumber.portNumber(portDst))
579 .setProtocol(protocol)
580 .setTenantId(tenantId)
581 .build();
582
583 PortChainId portChainId = findPortChainFromFiveTuple(fiveTuple);
584
585 if (portChainId == null) {
586 log.error("Packet does not match with any classifier");
587 return;
588 }
589
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530590 // Once the 5 tuple and port chain are identified, give this input for load balancing
591 LoadBalanceId id = loadBalanceSfc(portChainId, fiveTuple);
592 // Get nsh service path index
593 NshServicePathId nshSpi;
594 PortChain portChain = portChainService.getPortChain(portChainId);
595 if (nshSpiPortChainMap.containsKey(portChain.portChainId())) {
596 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
597 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
598 } else {
599 int nshSpiId = getNextNshSpi();
600 if (nshSpiId > MAX_NSH_SPI_ID) {
601 log.error("Reached max limit of service path index."
602 + "Failed to install SFC for port chain {}", portChain.portChainId());
603 return;
604 }
605 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
606 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(nshSpiId));
607 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530608 // download the required flow rules for classifier and forwarding
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530609 // install in OVS.
610 ConnectPoint connectPoint = flowClassifierInstaller.installLoadBalancedFlowClassifier(portChain,
611 fiveTuple, nshSpi);
612 serviceFunctionForwarder.installLoadBalancedForwardingRule(portChain.getLoadBalancePath(fiveTuple),
613 nshSpi);
614 sendPacket(context, connectPoint);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530615 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530616
617 /**
618 * Send packet back to classifier.
619 *
620 * @param context packet context
621 * @param connectPoint connect point of first service function
622 */
623 private void sendPacket(PacketContext context, ConnectPoint connectPoint) {
624
625 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
626 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
627 context.inPacket().unparsed());
628 packetService.emit(packet);
629 log.trace("Sending packet: {}", packet);
630 }
631 }
632
633 /**
634 * Encapsulate 5 bit load balance id to nsh spi.
635 *
636 * @param id load balance identifier
637 * @param nshSpiId nsh service path index
638 * @return updated service path index
639 */
640 protected int getNshServicePathId(LoadBalanceId id, int nshSpiId) {
641 int nshSpiNew = nshSpiId << 5;
642 nshSpiNew = nshSpiNew | id.loadBalanceId();
643 return nshSpiNew;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530644 }
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530645}