blob: 3292e23cd11fdff8c78bb10e87966c1e62a6525b [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;
Phaneendra Manda8db7d092016-06-04 00:17:24 +053023import java.util.ListIterator;
Phaneendra Mandab3555032016-02-08 11:41:53 +053024import java.util.Set;
Phaneendra Manda8db7d092016-06-04 00:17:24 +053025import java.util.UUID;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053026
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053030import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053032import org.apache.felix.scr.annotations.Service;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053033import org.onlab.packet.Ethernet;
34import org.onlab.packet.IPv4;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053035import org.onlab.packet.IpAddress;
36import org.onlab.packet.MacAddress;
Phaneendra Mandab3555032016-02-08 11:41:53 +053037import org.onlab.packet.TCP;
38import org.onlab.packet.UDP;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053039import org.onlab.util.ItemNotFoundException;
Jonathan Hart51539b82015-10-29 09:53:04 -070040import org.onlab.util.KryoNamespace;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053043import org.onosproject.core.IdGenerator;
44import org.onosproject.net.ConnectPoint;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053045import org.onosproject.net.NshServicePathId;
Phaneendra Mandab3555032016-02-08 11:41:53 +053046import org.onosproject.net.PortNumber;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053047import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.packet.DefaultOutboundPacket;
50import org.onosproject.net.packet.OutboundPacket;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053051import org.onosproject.net.packet.PacketContext;
52import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
Phaneendra Manda8db7d092016-06-04 00:17:24 +053054import org.onosproject.sfc.installer.impl.SfcFlowRuleInstallerImpl;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053055import org.onosproject.sfc.manager.SfcService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053056import org.onosproject.store.serializers.KryoNamespaces;
57import org.onosproject.store.service.DistributedSet;
58import org.onosproject.store.service.EventuallyConsistentMap;
59import org.onosproject.store.service.Serializer;
60import org.onosproject.store.service.StorageService;
61import org.onosproject.store.service.WallClockTimestamp;
Phaneendra Mandab3555032016-02-08 11:41:53 +053062import org.onosproject.vtnrsc.DefaultFiveTuple;
63import org.onosproject.vtnrsc.FiveTuple;
64import org.onosproject.vtnrsc.FixedIp;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053065import org.onosproject.vtnrsc.FlowClassifier;
66import org.onosproject.vtnrsc.FlowClassifierId;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053067import org.onosproject.vtnrsc.LoadBalanceId;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053068import org.onosproject.vtnrsc.PortChain;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053069import org.onosproject.vtnrsc.PortChainId;
Jonathan Hart51539b82015-10-29 09:53:04 -070070import org.onosproject.vtnrsc.PortPair;
71import org.onosproject.vtnrsc.PortPairGroup;
72import org.onosproject.vtnrsc.PortPairGroupId;
73import org.onosproject.vtnrsc.PortPairId;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053074import org.onosproject.vtnrsc.TenantId;
Phaneendra Mandab3555032016-02-08 11:41:53 +053075import org.onosproject.vtnrsc.VirtualPort;
76import org.onosproject.vtnrsc.VirtualPortId;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053077import org.onosproject.vtnrsc.event.VtnRscEvent;
78import org.onosproject.vtnrsc.event.VtnRscListener;
Phaneendra Mandab3555032016-02-08 11:41:53 +053079import org.onosproject.vtnrsc.flowclassifier.FlowClassifierService;
80import org.onosproject.vtnrsc.portchain.PortChainService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053081import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053082import org.onosproject.vtnrsc.service.VtnRscService;
Phaneendra Mandab3555032016-02-08 11:41:53 +053083import org.onosproject.vtnrsc.virtualport.VirtualPortService;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053084import org.slf4j.Logger;
85
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053086import com.google.common.collect.Lists;
87
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053088/**
89 * Provides implementation of SFC Service.
90 */
91@Component(immediate = true)
92@Service
93public class SfcManager implements SfcService {
94
95 private final Logger log = getLogger(getClass());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053096
97 private String nshSpiIdTopic = "nsh-spi-id";
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053098 private static final String APP_ID = "org.onosproject.app.vtn";
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053099 private static final int SFC_PRIORITY = 1000;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530100 private static final int MAX_NSH_SPI_ID = 0x7FFFF;
101 private static final int MAX_LOAD_BALANCE_ID = 0x20;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected VtnRscService vtnRscService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected CoreService coreService;
108
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected PacketService packetService;
111
Phaneendra Mandab3555032016-02-08 11:41:53 +0530112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected PortChainService portChainService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530116 protected PortPairGroupService portPairGroupService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530119 protected FlowClassifierService flowClassifierService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected VirtualPortService virtualPortService;
123
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected StorageService storageService;
126
127 protected SfcPacketProcessor processor = new SfcPacketProcessor();
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530128
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530129 protected ApplicationId appId;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530130 protected IdGenerator nshSpiIdGenerator;
131 protected EventuallyConsistentMap<PortChainId, Integer> nshSpiPortChainMap;
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530132 protected EventuallyConsistentMap<PortChainId, List<FiveTuple>> portChainFiveTupleMap;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530133 protected DistributedSet<Integer> nshSpiIdFreeList;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530134
135 private final VtnRscListener vtnRscListener = new InnerVtnRscListener();
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530136
137 @Activate
138 public void activate() {
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530139 appId = coreService.registerApplication(APP_ID);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530140 nshSpiIdGenerator = coreService.getIdGenerator(nshSpiIdTopic);
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530141
142 vtnRscService.addListener(vtnRscListener);
143
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530144 KryoNamespace.Builder serializer = KryoNamespace
145 .newBuilder()
146 .register(PortChainId.class, UUID.class, FiveTuple.class, IpAddress.class, PortNumber.class,
147 DefaultFiveTuple.class, IpAddress.Version.class, TenantId.class);
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530148
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530149 nshSpiPortChainMap = storageService.<PortChainId, Integer>eventuallyConsistentMapBuilder()
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530150 .withName("nshSpiPortChainMap").withSerializer(serializer)
151 .withTimestampProvider((k, v) ->new WallClockTimestamp()).build();
152
153 portChainFiveTupleMap = storageService.<PortChainId, List<FiveTuple>>eventuallyConsistentMapBuilder()
154 .withName("portChainFiveTupleMap").withSerializer(serializer)
155 .withTimestampProvider((k, v) ->new WallClockTimestamp()).build();
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530156
157 nshSpiIdFreeList = storageService.<Integer>setBuilder()
158 .withName("nshSpiIdDeletedList")
159 .withSerializer(Serializer.using(KryoNamespaces.API))
160 .build()
161 .asDistributedSet();
162
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530163 packetService.addProcessor(processor, PacketProcessor.director(SFC_PRIORITY));
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530164 log.info("Started");
165 }
166
167 @Deactivate
168 public void deactivate() {
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530169 vtnRscService.removeListener(vtnRscListener);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530170 packetService.removeProcessor(processor);
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530171 log.info("Stopped");
172 }
173
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530174 /*
175 * Handle events.
176 */
177 private class InnerVtnRscListener implements VtnRscListener {
178 @Override
179 public void event(VtnRscEvent event) {
180
181 if (VtnRscEvent.Type.PORT_PAIR_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530182 PortPair portPair = event.subject().portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530183 onPortPairCreated(portPair);
184 } else if (VtnRscEvent.Type.PORT_PAIR_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530185 PortPair portPair = event.subject().portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530186 onPortPairDeleted(portPair);
187 } else if (VtnRscEvent.Type.PORT_PAIR_UPDATE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530188 PortPair portPair = event.subject().portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530189 onPortPairDeleted(portPair);
190 onPortPairCreated(portPair);
191 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530192 PortPairGroup portPairGroup = event.subject().portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530193 onPortPairGroupCreated(portPairGroup);
194 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530195 PortPairGroup portPairGroup = event.subject().portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530196 onPortPairGroupDeleted(portPairGroup);
197 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_UPDATE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530198 PortPairGroup portPairGroup = event.subject().portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530199 onPortPairGroupDeleted(portPairGroup);
200 onPortPairGroupCreated(portPairGroup);
201 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530202 FlowClassifier flowClassifier = event.subject().flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530203 onFlowClassifierCreated(flowClassifier);
204 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530205 FlowClassifier flowClassifier = event.subject().flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530206 onFlowClassifierDeleted(flowClassifier);
207 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_UPDATE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530208 FlowClassifier flowClassifier = event.subject().flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530209 onFlowClassifierDeleted(flowClassifier);
210 onFlowClassifierCreated(flowClassifier);
211 } else if (VtnRscEvent.Type.PORT_CHAIN_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530212 PortChain portChain = event.subject().portChain();
213 if (portChain.oldPortChain() != null) {
214 onPortChainDeleted(portChain.oldPortChain());
215 }
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530216 onPortChainCreated(portChain);
217 } else if (VtnRscEvent.Type.PORT_CHAIN_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530218 PortChain portChain = event.subject().portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530219 onPortChainDeleted(portChain);
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530220 portChainFiveTupleMap.remove(portChain.portChainId());
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530221 } else if (VtnRscEvent.Type.PORT_CHAIN_UPDATE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530222 PortChain portChain = event.subject().portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530223 onPortChainDeleted(portChain);
224 onPortChainCreated(portChain);
225 }
226 }
227 }
228
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530229 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530230 public void onPortPairCreated(PortPair portPair) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530231 log.debug("onPortPairCreated");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530232 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530233 }
234
235 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530236 public void onPortPairDeleted(PortPair portPair) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530237 log.debug("onPortPairDeleted");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530238 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530239 }
240
241 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530242 public void onPortPairGroupCreated(PortPairGroup portPairGroup) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530243 log.debug("onPortPairGroupCreated");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530244 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530245 }
246
247 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530248 public void onPortPairGroupDeleted(PortPairGroup portPairGroup) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530249 log.debug("onPortPairGroupDeleted");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530250 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530251 }
252
253 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530254 public void onFlowClassifierCreated(FlowClassifier flowClassifier) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530255 log.debug("onFlowClassifierCreated");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530256 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530257 }
258
259 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530260 public void onFlowClassifierDeleted(FlowClassifier flowClassifier) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530261 log.debug("onFlowClassifierDeleted");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530262 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530263 }
264
265 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530266 public void onPortChainCreated(PortChain portChain) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700267 NshServicePathId nshSpi;
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530268 log.info("On port chain created");
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530269
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530270 int spi = getNextNshSpi();
271 if (spi > MAX_NSH_SPI_ID) {
272 log.error("Reached max limit of service path index." + "Failed to install SFC for port chain {}",
273 portChain.portChainId().toString());
274 return;
275 }
276 nshSpi = NshServicePathId.of(spi);
277 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(spi));
278 if (!portChainFiveTupleMap.containsKey(portChain.portChainId())) {
279 portChainFiveTupleMap.put(portChain.portChainId(), Lists.newArrayList());
280 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530281 // Install classifier rule to send the packet to controller
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530282 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
283 flowRuleInstaller.installFlowClassifier(portChain, nshSpi);
284
285 // Install rules for already identified five tuples.
286 List<FiveTuple> list = portChainFiveTupleMap.get(portChain.portChainId());
287 for (FiveTuple fiveTuple : list) {
288 LoadBalanceId id = loadBalanceSfc(portChain.portChainId(), fiveTuple);
289 // Get nsh service path index
290 nshSpi = NshServicePathId.of(getNshServicePathId(id, spi));
291 // download the required flow rules for classifier and
292 // forwarding
293 flowRuleInstaller.installLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
294 }
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530295 }
296
297 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530298 public void onPortChainDeleted(PortChain portChain) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530299 log.info("onPortChainDeleted");
300 if (!nshSpiPortChainMap.containsKey(portChain.portChainId())) {
301 throw new ItemNotFoundException("Unable to find NSH SPI");
302 }
303
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530304 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
305 // Uninstall classifier rules
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530306 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
307 flowRuleInstaller.unInstallFlowClassifier(portChain, NshServicePathId.of(nshSpiId));
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530308 // remove from nshSpiPortChainMap and add to nshSpiIdFreeList
309 nshSpiPortChainMap.remove(portChain.portChainId());
310 nshSpiIdFreeList.add(nshSpiId);
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530311
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530312 // Uninstall load balanced classifier and forwarding rules.
313 NshServicePathId nshSpi;
314 LoadBalanceId id;
315 List<LoadBalanceId> processedIdList = Lists.newArrayList();
316 Set<FiveTuple> fiveTupleSet = portChain.getLoadBalanceIdMapKeys();
317 for (FiveTuple fiveTuple : fiveTupleSet) {
318 id = portChain.getLoadBalanceId(fiveTuple);
319 if (processedIdList.contains(id)) {
320 // multiple five tuple can have single path.
321 continue;
322 } else {
323 processedIdList.add(id);
324 }
325 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530326 flowRuleInstaller.unInstallLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
327 }
328
329 // Reset load for all the port pairs
330 List<PortPairGroupId> ppgIdlist = portChain.portPairGroups();
331 ListIterator<PortPairGroupId> ppgIdListIterator = ppgIdlist.listIterator();
332 while (ppgIdListIterator.hasNext()) {
333 PortPairGroupId portPairGroupId = ppgIdListIterator.next();
334 PortPairGroup ppg = portPairGroupService.getPortPairGroup(portPairGroupId);
335 ppg.resetLoad();
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530336 }
337 }
338
339 /**
340 * Get next nsh service path identifier.
341 *
342 * @return value of service path identifier
343 */
344 int getNextNshSpi() {
345 // If there is any free id use it. Otherwise generate new id.
346 if (nshSpiIdFreeList.isEmpty()) {
347 return (int) nshSpiIdGenerator.getNewId();
348 }
349 Iterator<Integer> it = nshSpiIdFreeList.iterator();
350 Integer value = it.next();
351 nshSpiIdFreeList.remove(value);
352 return value;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530353 }
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530354
355 private class SfcPacketProcessor implements PacketProcessor {
356
Phaneendra Mandab3555032016-02-08 11:41:53 +0530357 /**
358 * Check for given ip match with the fixed ips for the virtual port.
359 *
360 * @param vPortId virtual port id
361 * @param ip ip address to match
362 * @return true if the ip match with the fixed ips in virtual port false otherwise
363 */
364 private boolean checkIpInVirtualPort(VirtualPortId vPortId, IpAddress ip) {
365 boolean found = false;
366 Set<FixedIp> ips = virtualPortService.getPort(vPortId).fixedIps();
367 for (FixedIp fixedIp : ips) {
368 if (fixedIp.ip().equals(ip)) {
369 found = true;
370 break;
371 }
372 }
373 return found;
374 }
375
376 /**
377 * Find the port chain for the received packet.
378 *
379 * @param fiveTuple five tuple info from the packet
380 * @return portChainId id of port chain
381 */
382 private PortChainId findPortChainFromFiveTuple(FiveTuple fiveTuple) {
383
384 PortChainId portChainId = null;
385
386 Iterable<PortChain> portChains = portChainService.getPortChains();
387 if (portChains == null) {
388 log.error("Could not retrive port chain list");
389 }
390
391 // Identify the port chain to which the packet belongs
392 for (final PortChain portChain : portChains) {
393
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530394 if (!portChain.tenantId().equals(fiveTuple.tenantId())) {
395 continue;
396 }
397
Phaneendra Mandab3555032016-02-08 11:41:53 +0530398 Iterable<FlowClassifierId> flowClassifiers = portChain.flowClassifiers();
399
400 // One port chain can have multiple flow classifiers.
401 for (final FlowClassifierId flowClassifierId : flowClassifiers) {
402
403 FlowClassifier flowClassifier = flowClassifierService.getFlowClassifier(flowClassifierId);
404 boolean match = false;
405 // Check whether protocol is set in flow classifier
406 if (flowClassifier.protocol() != null) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530407 if ((flowClassifier.protocol().equalsIgnoreCase("TCP")
408 && fiveTuple.protocol() == IPv4.PROTOCOL_TCP)
409 || (flowClassifier.protocol().equalsIgnoreCase("UDP")
410 && fiveTuple.protocol() == IPv4.PROTOCOL_UDP)
411 || (flowClassifier.protocol().equalsIgnoreCase("ICMP")
412 && fiveTuple.protocol() == IPv4.PROTOCOL_ICMP)) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530413 match = true;
414 } else {
415 continue;
416 }
417 }
418
419 // Check whether source ip prefix is set in flow classifier
420 if (flowClassifier.srcIpPrefix() != null) {
421 if (flowClassifier.srcIpPrefix().contains(fiveTuple.ipSrc())) {
422 match = true;
423 } else {
424 continue;
425 }
426 }
427
428 // Check whether destination ip prefix is set in flow classifier
429 if (flowClassifier.dstIpPrefix() != null) {
430 if (flowClassifier.dstIpPrefix().contains(fiveTuple.ipDst())) {
431 match = true;
432 } else {
433 continue;
434 }
435 }
436
437 // Check whether source port is set in flow classifier
438 if (fiveTuple.portSrc().toLong() >= flowClassifier.minSrcPortRange() ||
439 fiveTuple.portSrc().toLong() <= flowClassifier.maxSrcPortRange()) {
440 match = true;
441 } else {
442 continue;
443 }
444
445 // Check whether destination port is set in flow classifier
446 if (fiveTuple.portDst().toLong() >= flowClassifier.minSrcPortRange() ||
447 fiveTuple.portDst().toLong() <= flowClassifier.maxSrcPortRange()) {
448 match = true;
449 } else {
450 continue;
451 }
452
453 // Check whether neutron source port is set in flow classfier
454 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
455 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.srcPort().portId()),
456 fiveTuple.ipSrc());
457 if (!match) {
458 continue;
459 }
460 }
461
462 // Check whether destination neutron destination port is set in flow classifier
463 if ((flowClassifier.dstPort() != null) && (!flowClassifier.dstPort().portId().isEmpty())) {
464 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.dstPort().portId()),
465 fiveTuple.ipDst());
466 if (!match) {
467 continue;
468 }
469 }
470
471 if (match) {
472 portChainId = portChain.portChainId();
473 break;
474 }
475 }
476 }
477 return portChainId;
478 }
479
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530480 /**
Phaneendra Mandab3555032016-02-08 11:41:53 +0530481 * Get the tenant id for the given mac address.
482 *
483 * @param mac mac address
484 * @return tenantId tenant id for the given mac address
485 */
486 private TenantId getTenantId(MacAddress mac) {
487 Collection<VirtualPort> virtualPorts = virtualPortService.getPorts();
488 for (VirtualPort virtualPort : virtualPorts) {
489 if (virtualPort.macAddress().equals(mac)) {
490 return virtualPort.tenantId();
491 }
492 }
493 return null;
494 }
495
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530496 @Override
497 public void process(PacketContext context) {
498 Ethernet packet = context.inPacket().parsed();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530499 if (packet == null || portChainService.getPortChainCount() == 0) {
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530500 return;
501 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530502 // get the five tuple parameters for the packet
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530503 short ethType = packet.getEtherType();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530504 IpAddress ipSrc = null;
505 IpAddress ipDst = null;
506 int portSrc = 0;
507 int portDst = 0;
508 byte protocol = 0;
509 MacAddress macSrc = packet.getSourceMAC();
510 TenantId tenantId = getTenantId(macSrc);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530511
512 if (ethType == Ethernet.TYPE_IPV4) {
513 IPv4 ipv4Packet = (IPv4) packet.getPayload();
514 ipSrc = IpAddress.valueOf(ipv4Packet.getSourceAddress());
515 ipDst = IpAddress.valueOf(ipv4Packet.getDestinationAddress());
Phaneendra Mandab3555032016-02-08 11:41:53 +0530516 protocol = ipv4Packet.getProtocol();
517 if (protocol == IPv4.PROTOCOL_TCP) {
518 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
519 portSrc = tcpPacket.getSourcePort();
520 portDst = tcpPacket.getDestinationPort();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530521 } else if (protocol == IPv4.PROTOCOL_UDP) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530522 UDP udpPacket = (UDP) ipv4Packet.getPayload();
523 portSrc = udpPacket.getSourcePort();
524 portDst = udpPacket.getDestinationPort();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530525 } else if (protocol == IPv4.PROTOCOL_ICMP) {
526 // do nothing
527 } else {
528 // No need to process other packets received by controller.
529 return;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530530 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530531 } else {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530532 return;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530533 }
534
Phaneendra Mandab3555032016-02-08 11:41:53 +0530535 FiveTuple fiveTuple = DefaultFiveTuple.builder()
536 .setIpSrc(ipSrc)
537 .setIpDst(ipDst)
538 .setPortSrc(PortNumber.portNumber(portSrc))
539 .setPortDst(PortNumber.portNumber(portDst))
540 .setProtocol(protocol)
541 .setTenantId(tenantId)
542 .build();
543
544 PortChainId portChainId = findPortChainFromFiveTuple(fiveTuple);
545
546 if (portChainId == null) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530547 return;
548 }
549
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530550 // Once the 5 tuple and port chain are identified, give this input for load balancing
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530551 addToPortChainIdFiveTupleMap(portChainId, fiveTuple);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530552 LoadBalanceId id = loadBalanceSfc(portChainId, fiveTuple);
553 // Get nsh service path index
554 NshServicePathId nshSpi;
555 PortChain portChain = portChainService.getPortChain(portChainId);
556 if (nshSpiPortChainMap.containsKey(portChain.portChainId())) {
557 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
558 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
559 } else {
560 int nshSpiId = getNextNshSpi();
561 if (nshSpiId > MAX_NSH_SPI_ID) {
562 log.error("Reached max limit of service path index."
563 + "Failed to install SFC for port chain {}", portChain.portChainId());
564 return;
565 }
566 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
567 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(nshSpiId));
568 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530569 // download the required flow rules for classifier and forwarding
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530570 // install in OVS.
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530571 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
572 flowRuleInstaller.installLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
573 sendPacket(context);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530574 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530575
576 /**
577 * Send packet back to classifier.
578 *
579 * @param context packet context
580 * @param connectPoint connect point of first service function
581 */
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530582 private void sendPacket(PacketContext context) {
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530583
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530584 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
585
586 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(sourcePoint.port()).build();
587 OutboundPacket packet = new DefaultOutboundPacket(sourcePoint.deviceId(), treatment, context.inPacket()
588 .unparsed());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530589 packetService.emit(packet);
590 log.trace("Sending packet: {}", packet);
591 }
592 }
593
594 /**
595 * Encapsulate 5 bit load balance id to nsh spi.
596 *
597 * @param id load balance identifier
598 * @param nshSpiId nsh service path index
599 * @return updated service path index
600 */
601 protected int getNshServicePathId(LoadBalanceId id, int nshSpiId) {
602 int nshSpiNew = nshSpiId << 5;
603 nshSpiNew = nshSpiNew | id.loadBalanceId();
604 return nshSpiNew;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530605 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530606
607 private void addToPortChainIdFiveTupleMap(PortChainId portChainId, FiveTuple fiveTuple) {
608 List<FiveTuple> list = portChainFiveTupleMap.get(portChainId);
609 list.add(fiveTuple);
610 portChainFiveTupleMap.put(portChainId, list);
611 }
612
613 /**
614 * Find the load balanced path set it to port chain for the given five
615 * tuple.
616 *
617 * @param portChainId port chain id
618 * @param fiveTuple five tuple info
619 * @return load balance id
620 */
621 private LoadBalanceId loadBalanceSfc(PortChainId portChainId, FiveTuple fiveTuple) {
622
623 // Get the port chain
624 PortChain portChain = portChainService.getPortChain(portChainId);
625 List<PortPairId> loadBalancePath = Lists.newArrayList();
626 LoadBalanceId id;
627 int paths = portChain.getLoadBalancePathSize();
628 if (paths >= MAX_LOAD_BALANCE_ID) {
629 log.info("Max limit reached for load balance paths. "
630 + "Reusing the created path for port chain {} with five tuple {}", portChainId, fiveTuple);
631 id = LoadBalanceId.of((byte) ((paths + 1) % MAX_LOAD_BALANCE_ID));
632 portChain.addLoadBalancePath(fiveTuple, id, portChain.getLoadBalancePath(id));
633 }
634
635 // Get the list of port pair groups from port chain
636 Iterable<PortPairGroupId> portPairGroups = portChain.portPairGroups();
637 for (final PortPairGroupId portPairGroupId : portPairGroups) {
638 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
639
640 // Get the list of port pair ids from port pair group.
641 Iterable<PortPairId> portPairs = portPairGroup.portPairs();
642 int minLoad = 0xFFF;
643 PortPairId minLoadPortPairId = null;
644 for (final PortPairId portPairId : portPairs) {
645 int load = portPairGroup.getLoad(portPairId);
646 if (load == 0) {
647 minLoadPortPairId = portPairId;
648 break;
649 } else {
650 // Check the port pair which has min load.
651 if (load < minLoad) {
652 minLoad = load;
653 minLoadPortPairId = portPairId;
654 }
655 }
656 }
657 if (minLoadPortPairId != null) {
658 loadBalancePath.add(minLoadPortPairId);
659 portPairGroup.addLoad(minLoadPortPairId);
660 }
661 }
662
663 // Check if the path already exists, if not create a new id
664 id = portChain.matchPath(loadBalancePath);
665 if (id == null) {
666 id = LoadBalanceId.of((byte) (paths + 1));
667 }
668
669 portChain.addLoadBalancePath(fiveTuple, id, loadBalancePath);
670 return id;
671 }
672
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530673}