blob: b71fec7224118f429fee5091df146bc8400c1556 [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
nitinanandc97ff682017-03-24 18:03:14 +0530382 * @return portChainId id of port chain, null if portChain is not found
Phaneendra Mandab3555032016-02-08 11:41:53 +0530383 */
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");
nitinanandc97ff682017-03-24 18:03:14 +0530391 return null;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530392 }
393
394 // Identify the port chain to which the packet belongs
395 for (final PortChain portChain : portChains) {
396
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530397 if (!portChain.tenantId().equals(fiveTuple.tenantId())) {
398 continue;
399 }
400
Phaneendra Mandab3555032016-02-08 11:41:53 +0530401 Iterable<FlowClassifierId> flowClassifiers = portChain.flowClassifiers();
402
403 // One port chain can have multiple flow classifiers.
404 for (final FlowClassifierId flowClassifierId : flowClassifiers) {
405
406 FlowClassifier flowClassifier = flowClassifierService.getFlowClassifier(flowClassifierId);
407 boolean match = false;
408 // Check whether protocol is set in flow classifier
409 if (flowClassifier.protocol() != null) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530410 if ((flowClassifier.protocol().equalsIgnoreCase("TCP")
411 && fiveTuple.protocol() == IPv4.PROTOCOL_TCP)
412 || (flowClassifier.protocol().equalsIgnoreCase("UDP")
413 && fiveTuple.protocol() == IPv4.PROTOCOL_UDP)
414 || (flowClassifier.protocol().equalsIgnoreCase("ICMP")
415 && fiveTuple.protocol() == IPv4.PROTOCOL_ICMP)) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530416 match = true;
417 } else {
418 continue;
419 }
420 }
421
422 // Check whether source ip prefix is set in flow classifier
423 if (flowClassifier.srcIpPrefix() != null) {
424 if (flowClassifier.srcIpPrefix().contains(fiveTuple.ipSrc())) {
425 match = true;
426 } else {
427 continue;
428 }
429 }
430
431 // Check whether destination ip prefix is set in flow classifier
432 if (flowClassifier.dstIpPrefix() != null) {
433 if (flowClassifier.dstIpPrefix().contains(fiveTuple.ipDst())) {
434 match = true;
435 } else {
436 continue;
437 }
438 }
439
440 // Check whether source port is set in flow classifier
441 if (fiveTuple.portSrc().toLong() >= flowClassifier.minSrcPortRange() ||
442 fiveTuple.portSrc().toLong() <= flowClassifier.maxSrcPortRange()) {
443 match = true;
444 } else {
445 continue;
446 }
447
448 // Check whether destination port is set in flow classifier
449 if (fiveTuple.portDst().toLong() >= flowClassifier.minSrcPortRange() ||
450 fiveTuple.portDst().toLong() <= flowClassifier.maxSrcPortRange()) {
451 match = true;
452 } else {
453 continue;
454 }
455
456 // Check whether neutron source port is set in flow classfier
457 if ((flowClassifier.srcPort() != null) && (!flowClassifier.srcPort().portId().isEmpty())) {
458 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.srcPort().portId()),
459 fiveTuple.ipSrc());
460 if (!match) {
461 continue;
462 }
463 }
464
465 // Check whether destination neutron destination port is set in flow classifier
466 if ((flowClassifier.dstPort() != null) && (!flowClassifier.dstPort().portId().isEmpty())) {
467 match = checkIpInVirtualPort(VirtualPortId.portId(flowClassifier.dstPort().portId()),
468 fiveTuple.ipDst());
469 if (!match) {
470 continue;
471 }
472 }
473
474 if (match) {
475 portChainId = portChain.portChainId();
476 break;
477 }
478 }
479 }
480 return portChainId;
481 }
482
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530483 /**
Phaneendra Mandab3555032016-02-08 11:41:53 +0530484 * Get the tenant id for the given mac address.
485 *
486 * @param mac mac address
487 * @return tenantId tenant id for the given mac address
488 */
489 private TenantId getTenantId(MacAddress mac) {
490 Collection<VirtualPort> virtualPorts = virtualPortService.getPorts();
491 for (VirtualPort virtualPort : virtualPorts) {
492 if (virtualPort.macAddress().equals(mac)) {
493 return virtualPort.tenantId();
494 }
495 }
496 return null;
497 }
498
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530499 @Override
500 public void process(PacketContext context) {
501 Ethernet packet = context.inPacket().parsed();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530502 if (packet == null || portChainService.getPortChainCount() == 0) {
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530503 return;
504 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530505 // get the five tuple parameters for the packet
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530506 short ethType = packet.getEtherType();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530507 IpAddress ipSrc = null;
508 IpAddress ipDst = null;
509 int portSrc = 0;
510 int portDst = 0;
511 byte protocol = 0;
512 MacAddress macSrc = packet.getSourceMAC();
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530513 MacAddress macDst = packet.getDestinationMAC();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530514 TenantId tenantId = getTenantId(macSrc);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530515
516 if (ethType == Ethernet.TYPE_IPV4) {
517 IPv4 ipv4Packet = (IPv4) packet.getPayload();
518 ipSrc = IpAddress.valueOf(ipv4Packet.getSourceAddress());
519 ipDst = IpAddress.valueOf(ipv4Packet.getDestinationAddress());
Phaneendra Mandab3555032016-02-08 11:41:53 +0530520 protocol = ipv4Packet.getProtocol();
521 if (protocol == IPv4.PROTOCOL_TCP) {
522 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
523 portSrc = tcpPacket.getSourcePort();
524 portDst = tcpPacket.getDestinationPort();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530525 } else if (protocol == IPv4.PROTOCOL_UDP) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530526 UDP udpPacket = (UDP) ipv4Packet.getPayload();
527 portSrc = udpPacket.getSourcePort();
528 portDst = udpPacket.getDestinationPort();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530529 } else if (protocol == IPv4.PROTOCOL_ICMP) {
530 // do nothing
531 } else {
532 // No need to process other packets received by controller.
533 return;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530534 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530535 } else {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530536 return;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530537 }
538
Phaneendra Mandab3555032016-02-08 11:41:53 +0530539 FiveTuple fiveTuple = DefaultFiveTuple.builder()
540 .setIpSrc(ipSrc)
541 .setIpDst(ipDst)
542 .setPortSrc(PortNumber.portNumber(portSrc))
543 .setPortDst(PortNumber.portNumber(portDst))
544 .setProtocol(protocol)
545 .setTenantId(tenantId)
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530546 .setMacSrc(macSrc)
547 .setMacDst(macDst)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530548 .build();
549
550 PortChainId portChainId = findPortChainFromFiveTuple(fiveTuple);
551
552 if (portChainId == null) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530553 return;
554 }
555
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530556 // Once the 5 tuple and port chain are identified, give this input for load balancing
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530557 addToPortChainIdFiveTupleMap(portChainId, fiveTuple);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530558 LoadBalanceId id = loadBalanceSfc(portChainId, fiveTuple);
559 // Get nsh service path index
560 NshServicePathId nshSpi;
561 PortChain portChain = portChainService.getPortChain(portChainId);
562 if (nshSpiPortChainMap.containsKey(portChain.portChainId())) {
563 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
564 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
565 } else {
566 int nshSpiId = getNextNshSpi();
567 if (nshSpiId > MAX_NSH_SPI_ID) {
568 log.error("Reached max limit of service path index."
569 + "Failed to install SFC for port chain {}", portChain.portChainId());
570 return;
571 }
572 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
573 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(nshSpiId));
574 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530575 // download the required flow rules for classifier and forwarding
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530576 // install in OVS.
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530577 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
578 flowRuleInstaller.installLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
579 sendPacket(context);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530580 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530581
582 /**
583 * Send packet back to classifier.
584 *
585 * @param context packet context
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530586 */
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530587 private void sendPacket(PacketContext context) {
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530588
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530589 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
590
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530591 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(PortNumber.TABLE).build();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530592 OutboundPacket packet = new DefaultOutboundPacket(sourcePoint.deviceId(), treatment, context.inPacket()
593 .unparsed());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530594 packetService.emit(packet);
595 log.trace("Sending packet: {}", packet);
596 }
597 }
598
599 /**
600 * Encapsulate 5 bit load balance id to nsh spi.
601 *
602 * @param id load balance identifier
603 * @param nshSpiId nsh service path index
604 * @return updated service path index
605 */
606 protected int getNshServicePathId(LoadBalanceId id, int nshSpiId) {
607 int nshSpiNew = nshSpiId << 5;
608 nshSpiNew = nshSpiNew | id.loadBalanceId();
609 return nshSpiNew;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530610 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530611
612 private void addToPortChainIdFiveTupleMap(PortChainId portChainId, FiveTuple fiveTuple) {
613 List<FiveTuple> list = portChainFiveTupleMap.get(portChainId);
614 list.add(fiveTuple);
615 portChainFiveTupleMap.put(portChainId, list);
616 }
617
618 /**
619 * Find the load balanced path set it to port chain for the given five
620 * tuple.
621 *
622 * @param portChainId port chain id
623 * @param fiveTuple five tuple info
624 * @return load balance id
625 */
626 private LoadBalanceId loadBalanceSfc(PortChainId portChainId, FiveTuple fiveTuple) {
627
628 // Get the port chain
629 PortChain portChain = portChainService.getPortChain(portChainId);
630 List<PortPairId> loadBalancePath = Lists.newArrayList();
631 LoadBalanceId id;
632 int paths = portChain.getLoadBalancePathSize();
633 if (paths >= MAX_LOAD_BALANCE_ID) {
634 log.info("Max limit reached for load balance paths. "
635 + "Reusing the created path for port chain {} with five tuple {}", portChainId, fiveTuple);
636 id = LoadBalanceId.of((byte) ((paths + 1) % MAX_LOAD_BALANCE_ID));
637 portChain.addLoadBalancePath(fiveTuple, id, portChain.getLoadBalancePath(id));
638 }
639
640 // Get the list of port pair groups from port chain
641 Iterable<PortPairGroupId> portPairGroups = portChain.portPairGroups();
642 for (final PortPairGroupId portPairGroupId : portPairGroups) {
643 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
644
645 // Get the list of port pair ids from port pair group.
646 Iterable<PortPairId> portPairs = portPairGroup.portPairs();
647 int minLoad = 0xFFF;
648 PortPairId minLoadPortPairId = null;
649 for (final PortPairId portPairId : portPairs) {
650 int load = portPairGroup.getLoad(portPairId);
651 if (load == 0) {
652 minLoadPortPairId = portPairId;
653 break;
654 } else {
655 // Check the port pair which has min load.
656 if (load < minLoad) {
657 minLoad = load;
658 minLoadPortPairId = portPairId;
659 }
660 }
661 }
662 if (minLoadPortPairId != null) {
663 loadBalancePath.add(minLoadPortPairId);
664 portPairGroup.addLoad(minLoadPortPairId);
665 }
666 }
667
668 // Check if the path already exists, if not create a new id
669 id = portChain.matchPath(loadBalancePath);
670 if (id == null) {
671 id = LoadBalanceId.of((byte) (paths + 1));
672 }
673
674 portChain.addLoadBalancePath(fiveTuple, id, loadBalancePath);
675 return id;
676 }
677
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530678}