blob: 171195e4e2153bd2ee7aec94ba04ec90e761f3c0 [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);
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530319 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530320 if (processedIdList.contains(id)) {
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530321 // Multiple five tuple can have single path. In this case only
322 // the classifier rule need to delete
323 flowRuleInstaller.unInstallLoadBalancedClassifierRules(portChain, fiveTuple, nshSpi);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530324 continue;
325 } else {
326 processedIdList.add(id);
327 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530328 flowRuleInstaller.unInstallLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
329 }
330
331 // Reset load for all the port pairs
332 List<PortPairGroupId> ppgIdlist = portChain.portPairGroups();
333 ListIterator<PortPairGroupId> ppgIdListIterator = ppgIdlist.listIterator();
334 while (ppgIdListIterator.hasNext()) {
335 PortPairGroupId portPairGroupId = ppgIdListIterator.next();
336 PortPairGroup ppg = portPairGroupService.getPortPairGroup(portPairGroupId);
337 ppg.resetLoad();
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530338 }
339 }
340
341 /**
342 * Get next nsh service path identifier.
343 *
344 * @return value of service path identifier
345 */
346 int getNextNshSpi() {
347 // If there is any free id use it. Otherwise generate new id.
348 if (nshSpiIdFreeList.isEmpty()) {
349 return (int) nshSpiIdGenerator.getNewId();
350 }
351 Iterator<Integer> it = nshSpiIdFreeList.iterator();
352 Integer value = it.next();
353 nshSpiIdFreeList.remove(value);
354 return value;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530355 }
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530356
357 private class SfcPacketProcessor implements PacketProcessor {
358
Phaneendra Mandab3555032016-02-08 11:41:53 +0530359 /**
360 * Check for given ip match with the fixed ips for the virtual port.
361 *
362 * @param vPortId virtual port id
363 * @param ip ip address to match
364 * @return true if the ip match with the fixed ips in virtual port false otherwise
365 */
366 private boolean checkIpInVirtualPort(VirtualPortId vPortId, IpAddress ip) {
367 boolean found = false;
368 Set<FixedIp> ips = virtualPortService.getPort(vPortId).fixedIps();
369 for (FixedIp fixedIp : ips) {
370 if (fixedIp.ip().equals(ip)) {
371 found = true;
372 break;
373 }
374 }
375 return found;
376 }
377
378 /**
379 * Find the port chain for the received packet.
380 *
381 * @param fiveTuple five tuple info from the packet
382 * @return portChainId id of port chain
383 */
384 private PortChainId findPortChainFromFiveTuple(FiveTuple fiveTuple) {
385
386 PortChainId portChainId = null;
387
388 Iterable<PortChain> portChains = portChainService.getPortChains();
389 if (portChains == null) {
390 log.error("Could not retrive port chain list");
391 }
392
393 // Identify the port chain to which the packet belongs
394 for (final PortChain portChain : portChains) {
395
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530396 if (!portChain.tenantId().equals(fiveTuple.tenantId())) {
397 continue;
398 }
399
Phaneendra Mandab3555032016-02-08 11:41:53 +0530400 Iterable<FlowClassifierId> flowClassifiers = portChain.flowClassifiers();
401
402 // One port chain can have multiple flow classifiers.
403 for (final FlowClassifierId flowClassifierId : flowClassifiers) {
404
405 FlowClassifier flowClassifier = flowClassifierService.getFlowClassifier(flowClassifierId);
406 boolean match = false;
407 // Check whether protocol is set in flow classifier
408 if (flowClassifier.protocol() != null) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530409 if ((flowClassifier.protocol().equalsIgnoreCase("TCP")
410 && fiveTuple.protocol() == IPv4.PROTOCOL_TCP)
411 || (flowClassifier.protocol().equalsIgnoreCase("UDP")
412 && fiveTuple.protocol() == IPv4.PROTOCOL_UDP)
413 || (flowClassifier.protocol().equalsIgnoreCase("ICMP")
414 && fiveTuple.protocol() == IPv4.PROTOCOL_ICMP)) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530415 match = true;
416 } else {
417 continue;
418 }
419 }
420
421 // Check whether source ip prefix is set in flow classifier
422 if (flowClassifier.srcIpPrefix() != null) {
423 if (flowClassifier.srcIpPrefix().contains(fiveTuple.ipSrc())) {
424 match = true;
425 } else {
426 continue;
427 }
428 }
429
430 // Check whether destination ip prefix is set in flow classifier
431 if (flowClassifier.dstIpPrefix() != null) {
432 if (flowClassifier.dstIpPrefix().contains(fiveTuple.ipDst())) {
433 match = true;
434 } else {
435 continue;
436 }
437 }
438
439 // Check whether source port is set in flow classifier
440 if (fiveTuple.portSrc().toLong() >= flowClassifier.minSrcPortRange() ||
441 fiveTuple.portSrc().toLong() <= flowClassifier.maxSrcPortRange()) {
442 match = true;
443 } else {
444 continue;
445 }
446
447 // Check whether destination port is set in flow classifier
448 if (fiveTuple.portDst().toLong() >= flowClassifier.minSrcPortRange() ||
449 fiveTuple.portDst().toLong() <= flowClassifier.maxSrcPortRange()) {
450 match = true;
451 } else {
452 continue;
453 }
454
455 // Check whether neutron source port is set in flow classfier
456 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
457 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.srcPort().portId()),
458 fiveTuple.ipSrc());
459 if (!match) {
460 continue;
461 }
462 }
463
464 // Check whether destination neutron destination port is set in flow classifier
465 if ((flowClassifier.dstPort() != null) && (!flowClassifier.dstPort().portId().isEmpty())) {
466 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.dstPort().portId()),
467 fiveTuple.ipDst());
468 if (!match) {
469 continue;
470 }
471 }
472
473 if (match) {
474 portChainId = portChain.portChainId();
475 break;
476 }
477 }
478 }
479 return portChainId;
480 }
481
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530482 /**
Phaneendra Mandab3555032016-02-08 11:41:53 +0530483 * Get the tenant id for the given mac address.
484 *
485 * @param mac mac address
486 * @return tenantId tenant id for the given mac address
487 */
488 private TenantId getTenantId(MacAddress mac) {
489 Collection<VirtualPort> virtualPorts = virtualPortService.getPorts();
490 for (VirtualPort virtualPort : virtualPorts) {
491 if (virtualPort.macAddress().equals(mac)) {
492 return virtualPort.tenantId();
493 }
494 }
495 return null;
496 }
497
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530498 @Override
499 public void process(PacketContext context) {
500 Ethernet packet = context.inPacket().parsed();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530501 if (packet == null || portChainService.getPortChainCount() == 0) {
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530502 return;
503 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530504 // get the five tuple parameters for the packet
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530505 short ethType = packet.getEtherType();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530506 IpAddress ipSrc = null;
507 IpAddress ipDst = null;
508 int portSrc = 0;
509 int portDst = 0;
510 byte protocol = 0;
511 MacAddress macSrc = packet.getSourceMAC();
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530512 MacAddress macDst = packet.getDestinationMAC();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530513 TenantId tenantId = getTenantId(macSrc);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530514
515 if (ethType == Ethernet.TYPE_IPV4) {
516 IPv4 ipv4Packet = (IPv4) packet.getPayload();
517 ipSrc = IpAddress.valueOf(ipv4Packet.getSourceAddress());
518 ipDst = IpAddress.valueOf(ipv4Packet.getDestinationAddress());
Phaneendra Mandab3555032016-02-08 11:41:53 +0530519 protocol = ipv4Packet.getProtocol();
520 if (protocol == IPv4.PROTOCOL_TCP) {
521 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
522 portSrc = tcpPacket.getSourcePort();
523 portDst = tcpPacket.getDestinationPort();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530524 } else if (protocol == IPv4.PROTOCOL_UDP) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530525 UDP udpPacket = (UDP) ipv4Packet.getPayload();
526 portSrc = udpPacket.getSourcePort();
527 portDst = udpPacket.getDestinationPort();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530528 } else if (protocol == IPv4.PROTOCOL_ICMP) {
529 // do nothing
530 } else {
531 // No need to process other packets received by controller.
532 return;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530533 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530534 } else {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530535 return;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530536 }
537
Phaneendra Mandab3555032016-02-08 11:41:53 +0530538 FiveTuple fiveTuple = DefaultFiveTuple.builder()
539 .setIpSrc(ipSrc)
540 .setIpDst(ipDst)
541 .setPortSrc(PortNumber.portNumber(portSrc))
542 .setPortDst(PortNumber.portNumber(portDst))
543 .setProtocol(protocol)
544 .setTenantId(tenantId)
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530545 .setMacSrc(macSrc)
546 .setMacDst(macDst)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530547 .build();
548
549 PortChainId portChainId = findPortChainFromFiveTuple(fiveTuple);
550
551 if (portChainId == null) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530552 return;
553 }
554
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530555 // Once the 5 tuple and port chain are identified, give this input for load balancing
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530556 addToPortChainIdFiveTupleMap(portChainId, fiveTuple);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530557 LoadBalanceId id = loadBalanceSfc(portChainId, fiveTuple);
558 // Get nsh service path index
559 NshServicePathId nshSpi;
560 PortChain portChain = portChainService.getPortChain(portChainId);
561 if (nshSpiPortChainMap.containsKey(portChain.portChainId())) {
562 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
563 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
564 } else {
565 int nshSpiId = getNextNshSpi();
566 if (nshSpiId > MAX_NSH_SPI_ID) {
567 log.error("Reached max limit of service path index."
568 + "Failed to install SFC for port chain {}", portChain.portChainId());
569 return;
570 }
571 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
572 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(nshSpiId));
573 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530574 // download the required flow rules for classifier and forwarding
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530575 // install in OVS.
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530576 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
577 flowRuleInstaller.installLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
578 sendPacket(context);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530579 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530580
581 /**
582 * Send packet back to classifier.
583 *
584 * @param context packet context
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530585 */
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530586 private void sendPacket(PacketContext context) {
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530587
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530588 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
589
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530590 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(PortNumber.TABLE).build();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530591 OutboundPacket packet = new DefaultOutboundPacket(sourcePoint.deviceId(), treatment, context.inPacket()
592 .unparsed());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530593 packetService.emit(packet);
594 log.trace("Sending packet: {}", packet);
595 }
596 }
597
598 /**
599 * Encapsulate 5 bit load balance id to nsh spi.
600 *
601 * @param id load balance identifier
602 * @param nshSpiId nsh service path index
603 * @return updated service path index
604 */
605 protected int getNshServicePathId(LoadBalanceId id, int nshSpiId) {
606 int nshSpiNew = nshSpiId << 5;
607 nshSpiNew = nshSpiNew | id.loadBalanceId();
608 return nshSpiNew;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530609 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530610
611 private void addToPortChainIdFiveTupleMap(PortChainId portChainId, FiveTuple fiveTuple) {
612 List<FiveTuple> list = portChainFiveTupleMap.get(portChainId);
613 list.add(fiveTuple);
614 portChainFiveTupleMap.put(portChainId, list);
615 }
616
617 /**
618 * Find the load balanced path set it to port chain for the given five
619 * tuple.
620 *
621 * @param portChainId port chain id
622 * @param fiveTuple five tuple info
623 * @return load balance id
624 */
625 private LoadBalanceId loadBalanceSfc(PortChainId portChainId, FiveTuple fiveTuple) {
626
627 // Get the port chain
628 PortChain portChain = portChainService.getPortChain(portChainId);
629 List<PortPairId> loadBalancePath = Lists.newArrayList();
630 LoadBalanceId id;
631 int paths = portChain.getLoadBalancePathSize();
632 if (paths >= MAX_LOAD_BALANCE_ID) {
633 log.info("Max limit reached for load balance paths. "
634 + "Reusing the created path for port chain {} with five tuple {}", portChainId, fiveTuple);
635 id = LoadBalanceId.of((byte) ((paths + 1) % MAX_LOAD_BALANCE_ID));
636 portChain.addLoadBalancePath(fiveTuple, id, portChain.getLoadBalancePath(id));
637 }
638
639 // Get the list of port pair groups from port chain
640 Iterable<PortPairGroupId> portPairGroups = portChain.portPairGroups();
641 for (final PortPairGroupId portPairGroupId : portPairGroups) {
642 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
643
644 // Get the list of port pair ids from port pair group.
645 Iterable<PortPairId> portPairs = portPairGroup.portPairs();
646 int minLoad = 0xFFF;
647 PortPairId minLoadPortPairId = null;
648 for (final PortPairId portPairId : portPairs) {
649 int load = portPairGroup.getLoad(portPairId);
650 if (load == 0) {
651 minLoadPortPairId = portPairId;
652 break;
653 } else {
654 // Check the port pair which has min load.
655 if (load < minLoad) {
656 minLoad = load;
657 minLoadPortPairId = portPairId;
658 }
659 }
660 }
661 if (minLoadPortPairId != null) {
662 loadBalancePath.add(minLoadPortPairId);
663 portPairGroup.addLoad(minLoadPortPairId);
664 }
665 }
666
667 // Check if the path already exists, if not create a new id
668 id = portChain.matchPath(loadBalancePath);
669 if (id == null) {
670 id = LoadBalanceId.of((byte) (paths + 1));
671 }
672
673 portChain.addLoadBalancePath(fiveTuple, id, loadBalancePath);
674 return id;
675 }
676
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530677}