blob: d4035024a29dbd6ff9aeeb1788d10c4e8e48b22b [file] [log] [blame]
Mahesh Poojary S335e7c32015-10-29 10:16:51 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Ray Milkeyd84f89b2018-08-17 14:54:17 -070018import com.google.common.collect.Lists;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053019import org.onlab.packet.Ethernet;
20import org.onlab.packet.IPv4;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053021import org.onlab.packet.IpAddress;
22import org.onlab.packet.MacAddress;
Phaneendra Mandab3555032016-02-08 11:41:53 +053023import org.onlab.packet.TCP;
24import org.onlab.packet.UDP;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053025import org.onlab.util.ItemNotFoundException;
Jonathan Hart51539b82015-10-29 09:53:04 -070026import org.onlab.util.KryoNamespace;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053029import org.onosproject.core.IdGenerator;
30import org.onosproject.net.ConnectPoint;
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +053031import org.onosproject.net.NshServicePathId;
Phaneendra Mandab3555032016-02-08 11:41:53 +053032import org.onosproject.net.PortNumber;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053033import org.onosproject.net.flow.DefaultTrafficTreatment;
34import org.onosproject.net.flow.TrafficTreatment;
35import org.onosproject.net.packet.DefaultOutboundPacket;
36import org.onosproject.net.packet.OutboundPacket;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053037import org.onosproject.net.packet.PacketContext;
38import org.onosproject.net.packet.PacketProcessor;
39import org.onosproject.net.packet.PacketService;
Phaneendra Manda8db7d092016-06-04 00:17:24 +053040import org.onosproject.sfc.installer.impl.SfcFlowRuleInstallerImpl;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053041import org.onosproject.sfc.manager.SfcService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053042import org.onosproject.store.serializers.KryoNamespaces;
43import org.onosproject.store.service.DistributedSet;
44import org.onosproject.store.service.EventuallyConsistentMap;
45import org.onosproject.store.service.Serializer;
46import org.onosproject.store.service.StorageService;
47import org.onosproject.store.service.WallClockTimestamp;
Phaneendra Mandab3555032016-02-08 11:41:53 +053048import org.onosproject.vtnrsc.DefaultFiveTuple;
49import org.onosproject.vtnrsc.FiveTuple;
50import org.onosproject.vtnrsc.FixedIp;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053051import org.onosproject.vtnrsc.FlowClassifier;
52import org.onosproject.vtnrsc.FlowClassifierId;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053053import org.onosproject.vtnrsc.LoadBalanceId;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053054import org.onosproject.vtnrsc.PortChain;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053055import org.onosproject.vtnrsc.PortChainId;
Jonathan Hart51539b82015-10-29 09:53:04 -070056import org.onosproject.vtnrsc.PortPair;
57import org.onosproject.vtnrsc.PortPairGroup;
58import org.onosproject.vtnrsc.PortPairGroupId;
59import org.onosproject.vtnrsc.PortPairId;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053060import org.onosproject.vtnrsc.TenantId;
Phaneendra Mandab3555032016-02-08 11:41:53 +053061import org.onosproject.vtnrsc.VirtualPort;
62import org.onosproject.vtnrsc.VirtualPortId;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053063import org.onosproject.vtnrsc.event.VtnRscEvent;
64import org.onosproject.vtnrsc.event.VtnRscListener;
Phaneendra Mandab3555032016-02-08 11:41:53 +053065import org.onosproject.vtnrsc.flowclassifier.FlowClassifierService;
66import org.onosproject.vtnrsc.portchain.PortChainService;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053067import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053068import org.onosproject.vtnrsc.service.VtnRscService;
Phaneendra Mandab3555032016-02-08 11:41:53 +053069import org.onosproject.vtnrsc.virtualport.VirtualPortService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070070import org.osgi.service.component.annotations.Activate;
71import org.osgi.service.component.annotations.Component;
72import org.osgi.service.component.annotations.Deactivate;
73import org.osgi.service.component.annotations.Reference;
74import org.osgi.service.component.annotations.ReferenceCardinality;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053075import org.slf4j.Logger;
76
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077import java.util.Collection;
78import java.util.Iterator;
79import java.util.List;
80import java.util.ListIterator;
81import java.util.Set;
82import java.util.UUID;
83
84import static org.slf4j.LoggerFactory.getLogger;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053085
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053086/**
87 * Provides implementation of SFC Service.
88 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089@Component(immediate = true, service = SfcService.class)
Mahesh Poojary S335e7c32015-10-29 10:16:51 +053090public class SfcManager implements SfcService {
91
92 private final Logger log = getLogger(getClass());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053093
94 private String nshSpiIdTopic = "nsh-spi-id";
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053095 private static final String APP_ID = "org.onosproject.app.vtn";
Phaneendra Manda5c8257b2016-02-03 22:07:38 +053096 private static final int SFC_PRIORITY = 1000;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +053097 private static final int MAX_NSH_SPI_ID = 0x7FFFF;
98 private static final int MAX_LOAD_BALANCE_ID = 0x20;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +053099
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530101 protected VtnRscService vtnRscService;
102
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530104 protected CoreService coreService;
105
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530107 protected PacketService packetService;
108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530110 protected PortChainService portChainService;
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530113 protected PortPairGroupService portPairGroupService;
114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530116 protected FlowClassifierService flowClassifierService;
117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530119 protected VirtualPortService virtualPortService;
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530122 protected StorageService storageService;
123
124 protected SfcPacketProcessor processor = new SfcPacketProcessor();
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530125
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530126 protected ApplicationId appId;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530127 protected IdGenerator nshSpiIdGenerator;
128 protected EventuallyConsistentMap<PortChainId, Integer> nshSpiPortChainMap;
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530129 protected EventuallyConsistentMap<PortChainId, List<FiveTuple>> portChainFiveTupleMap;
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530130 protected DistributedSet<Integer> nshSpiIdFreeList;
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530131
132 private final VtnRscListener vtnRscListener = new InnerVtnRscListener();
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530133
134 @Activate
135 public void activate() {
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530136 appId = coreService.registerApplication(APP_ID);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530137 nshSpiIdGenerator = coreService.getIdGenerator(nshSpiIdTopic);
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530138
139 vtnRscService.addListener(vtnRscListener);
140
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530141 KryoNamespace.Builder serializer = KryoNamespace
142 .newBuilder()
143 .register(PortChainId.class, UUID.class, FiveTuple.class, IpAddress.class, PortNumber.class,
144 DefaultFiveTuple.class, IpAddress.Version.class, TenantId.class);
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530145
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530146 nshSpiPortChainMap = storageService.<PortChainId, Integer>eventuallyConsistentMapBuilder()
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530147 .withName("nshSpiPortChainMap").withSerializer(serializer)
Ray Milkey88cc3432017-03-30 17:19:08 -0700148 .withTimestampProvider((k, v) -> new WallClockTimestamp()).build();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530149
150 portChainFiveTupleMap = storageService.<PortChainId, List<FiveTuple>>eventuallyConsistentMapBuilder()
151 .withName("portChainFiveTupleMap").withSerializer(serializer)
Ray Milkey88cc3432017-03-30 17:19:08 -0700152 .withTimestampProvider((k, v) -> new WallClockTimestamp()).build();
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530153
154 nshSpiIdFreeList = storageService.<Integer>setBuilder()
155 .withName("nshSpiIdDeletedList")
156 .withSerializer(Serializer.using(KryoNamespaces.API))
157 .build()
158 .asDistributedSet();
159
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530160 packetService.addProcessor(processor, PacketProcessor.director(SFC_PRIORITY));
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530161 log.info("Started");
162 }
163
164 @Deactivate
165 public void deactivate() {
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530166 vtnRscService.removeListener(vtnRscListener);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530167 packetService.removeProcessor(processor);
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530168 log.info("Stopped");
169 }
170
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530171 /*
172 * Handle events.
173 */
174 private class InnerVtnRscListener implements VtnRscListener {
175 @Override
176 public void event(VtnRscEvent event) {
177
178 if (VtnRscEvent.Type.PORT_PAIR_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530179 PortPair portPair = event.subject().portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530180 onPortPairCreated(portPair);
181 } else if (VtnRscEvent.Type.PORT_PAIR_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530182 PortPair portPair = event.subject().portPair();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530183 onPortPairDeleted(portPair);
184 } else if (VtnRscEvent.Type.PORT_PAIR_UPDATE == 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 onPortPairCreated(portPair);
188 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530189 PortPairGroup portPairGroup = event.subject().portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530190 onPortPairGroupCreated(portPairGroup);
191 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530192 PortPairGroup portPairGroup = event.subject().portPairGroup();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530193 onPortPairGroupDeleted(portPairGroup);
194 } else if (VtnRscEvent.Type.PORT_PAIR_GROUP_UPDATE == 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 onPortPairGroupCreated(portPairGroup);
198 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530199 FlowClassifier flowClassifier = event.subject().flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530200 onFlowClassifierCreated(flowClassifier);
201 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530202 FlowClassifier flowClassifier = event.subject().flowClassifier();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530203 onFlowClassifierDeleted(flowClassifier);
204 } else if (VtnRscEvent.Type.FLOW_CLASSIFIER_UPDATE == 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 onFlowClassifierCreated(flowClassifier);
208 } else if (VtnRscEvent.Type.PORT_CHAIN_PUT == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530209 PortChain portChain = event.subject().portChain();
210 if (portChain.oldPortChain() != null) {
211 onPortChainDeleted(portChain.oldPortChain());
212 }
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530213 onPortChainCreated(portChain);
214 } else if (VtnRscEvent.Type.PORT_CHAIN_DELETE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530215 PortChain portChain = event.subject().portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530216 onPortChainDeleted(portChain);
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530217 portChainFiveTupleMap.remove(portChain.portChainId());
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530218 } else if (VtnRscEvent.Type.PORT_CHAIN_UPDATE == event.type()) {
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530219 PortChain portChain = event.subject().portChain();
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530220 onPortChainDeleted(portChain);
221 onPortChainCreated(portChain);
222 }
223 }
224 }
225
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530226 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530227 public void onPortPairCreated(PortPair portPair) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530228 log.debug("onPortPairCreated");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530229 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530230 }
231
232 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530233 public void onPortPairDeleted(PortPair portPair) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530234 log.debug("onPortPairDeleted");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530235 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530236 }
237
238 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530239 public void onPortPairGroupCreated(PortPairGroup portPairGroup) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530240 log.debug("onPortPairGroupCreated");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530241 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530242 }
243
244 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530245 public void onPortPairGroupDeleted(PortPairGroup portPairGroup) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530246 log.debug("onPortPairGroupDeleted");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530247 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530248 }
249
250 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530251 public void onFlowClassifierCreated(FlowClassifier flowClassifier) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530252 log.debug("onFlowClassifierCreated");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530253 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530254 }
255
256 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530257 public void onFlowClassifierDeleted(FlowClassifier flowClassifier) {
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530258 log.debug("onFlowClassifierDeleted");
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530259 // Do nothing
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530260 }
261
262 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530263 public void onPortChainCreated(PortChain portChain) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700264 NshServicePathId nshSpi;
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530265 log.info("On port chain created");
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530266
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530267 int spi = getNextNshSpi();
268 if (spi > MAX_NSH_SPI_ID) {
269 log.error("Reached max limit of service path index." + "Failed to install SFC for port chain {}",
270 portChain.portChainId().toString());
271 return;
272 }
273 nshSpi = NshServicePathId.of(spi);
274 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(spi));
275 if (!portChainFiveTupleMap.containsKey(portChain.portChainId())) {
276 portChainFiveTupleMap.put(portChain.portChainId(), Lists.newArrayList());
277 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530278 // Install classifier rule to send the packet to controller
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530279 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
280 flowRuleInstaller.installFlowClassifier(portChain, nshSpi);
281
282 // Install rules for already identified five tuples.
283 List<FiveTuple> list = portChainFiveTupleMap.get(portChain.portChainId());
284 for (FiveTuple fiveTuple : list) {
285 LoadBalanceId id = loadBalanceSfc(portChain.portChainId(), fiveTuple);
286 // Get nsh service path index
287 nshSpi = NshServicePathId.of(getNshServicePathId(id, spi));
288 // download the required flow rules for classifier and
289 // forwarding
290 flowRuleInstaller.installLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
291 }
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530292 }
293
294 @Override
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530295 public void onPortChainDeleted(PortChain portChain) {
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530296 log.info("onPortChainDeleted");
297 if (!nshSpiPortChainMap.containsKey(portChain.portChainId())) {
298 throw new ItemNotFoundException("Unable to find NSH SPI");
299 }
300
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530301 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
302 // Uninstall classifier rules
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530303 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
304 flowRuleInstaller.unInstallFlowClassifier(portChain, NshServicePathId.of(nshSpiId));
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530305 // remove from nshSpiPortChainMap and add to nshSpiIdFreeList
306 nshSpiPortChainMap.remove(portChain.portChainId());
307 nshSpiIdFreeList.add(nshSpiId);
Mahesh Poojary Huawei15092f62015-12-10 11:09:02 +0530308
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530309 // Uninstall load balanced classifier and forwarding rules.
310 NshServicePathId nshSpi;
311 LoadBalanceId id;
312 List<LoadBalanceId> processedIdList = Lists.newArrayList();
313 Set<FiveTuple> fiveTupleSet = portChain.getLoadBalanceIdMapKeys();
314 for (FiveTuple fiveTuple : fiveTupleSet) {
315 id = portChain.getLoadBalanceId(fiveTuple);
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530316 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530317 if (processedIdList.contains(id)) {
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530318 // Multiple five tuple can have single path. In this case only
319 // the classifier rule need to delete
320 flowRuleInstaller.unInstallLoadBalancedClassifierRules(portChain, fiveTuple, nshSpi);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530321 continue;
322 } else {
323 processedIdList.add(id);
324 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530325 flowRuleInstaller.unInstallLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
326 }
327
328 // Reset load for all the port pairs
329 List<PortPairGroupId> ppgIdlist = portChain.portPairGroups();
330 ListIterator<PortPairGroupId> ppgIdListIterator = ppgIdlist.listIterator();
331 while (ppgIdListIterator.hasNext()) {
332 PortPairGroupId portPairGroupId = ppgIdListIterator.next();
333 PortPairGroup ppg = portPairGroupService.getPortPairGroup(portPairGroupId);
334 ppg.resetLoad();
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530335 }
336 }
337
338 /**
339 * Get next nsh service path identifier.
340 *
341 * @return value of service path identifier
342 */
343 int getNextNshSpi() {
344 // If there is any free id use it. Otherwise generate new id.
345 if (nshSpiIdFreeList.isEmpty()) {
346 return (int) nshSpiIdGenerator.getNewId();
347 }
348 Iterator<Integer> it = nshSpiIdFreeList.iterator();
349 Integer value = it.next();
350 nshSpiIdFreeList.remove(value);
351 return value;
Mahesh Poojary S335e7c32015-10-29 10:16:51 +0530352 }
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530353
354 private class SfcPacketProcessor implements PacketProcessor {
355
Phaneendra Mandab3555032016-02-08 11:41:53 +0530356 /**
357 * Check for given ip match with the fixed ips for the virtual port.
358 *
359 * @param vPortId virtual port id
360 * @param ip ip address to match
361 * @return true if the ip match with the fixed ips in virtual port false otherwise
362 */
363 private boolean checkIpInVirtualPort(VirtualPortId vPortId, IpAddress ip) {
364 boolean found = false;
365 Set<FixedIp> ips = virtualPortService.getPort(vPortId).fixedIps();
366 for (FixedIp fixedIp : ips) {
367 if (fixedIp.ip().equals(ip)) {
368 found = true;
369 break;
370 }
371 }
372 return found;
373 }
374
375 /**
376 * Find the port chain for the received packet.
377 *
378 * @param fiveTuple five tuple info from the packet
nitinanandc97ff682017-03-24 18:03:14 +0530379 * @return portChainId id of port chain, null if portChain is not found
Phaneendra Mandab3555032016-02-08 11:41:53 +0530380 */
381 private PortChainId findPortChainFromFiveTuple(FiveTuple fiveTuple) {
382
383 PortChainId portChainId = null;
384
385 Iterable<PortChain> portChains = portChainService.getPortChains();
386 if (portChains == null) {
donghyeok.hoa73e5c32018-06-14 18:39:53 +0900387 log.error("Could not retrieve port chain list");
nitinanandc97ff682017-03-24 18:03:14 +0530388 return null;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530389 }
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) {
Jon Halla3fcf672017-03-28 16:53:22 -0700407 if (("TCP".equalsIgnoreCase(flowClassifier.protocol())
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530408 && fiveTuple.protocol() == IPv4.PROTOCOL_TCP)
Jon Halla3fcf672017-03-28 16:53:22 -0700409 || ("UDP".equalsIgnoreCase(flowClassifier.protocol())
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530410 && fiveTuple.protocol() == IPv4.PROTOCOL_UDP)
Jon Halla3fcf672017-03-28 16:53:22 -0700411 || ("ICMP".equalsIgnoreCase(flowClassifier.protocol())
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530412 && 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
donghyeok.hoa73e5c32018-06-14 18:39:53 +0900438 if (fiveTuple.portSrc().toLong() >= flowClassifier.minSrcPortRange() &&
Phaneendra Mandab3555032016-02-08 11:41:53 +0530439 fiveTuple.portSrc().toLong() <= flowClassifier.maxSrcPortRange()) {
440 match = true;
441 } else {
442 continue;
443 }
444
445 // Check whether destination port is set in flow classifier
donghyeok.hoa73e5c32018-06-14 18:39:53 +0900446 if (fiveTuple.portDst().toLong() >= flowClassifier.minSrcPortRange() &&
Phaneendra Mandab3555032016-02-08 11:41:53 +0530447 fiveTuple.portDst().toLong() <= flowClassifier.maxSrcPortRange()) {
448 match = true;
449 } else {
450 continue;
451 }
452
donghyeok.hoa73e5c32018-06-14 18:39:53 +0900453 // Check whether neutron source port is set in flow classifier
Phaneendra Mandab3555032016-02-08 11:41:53 +0530454 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();
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530510 MacAddress macDst = packet.getDestinationMAC();
Phaneendra Mandab3555032016-02-08 11:41:53 +0530511 TenantId tenantId = getTenantId(macSrc);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530512
513 if (ethType == Ethernet.TYPE_IPV4) {
514 IPv4 ipv4Packet = (IPv4) packet.getPayload();
515 ipSrc = IpAddress.valueOf(ipv4Packet.getSourceAddress());
516 ipDst = IpAddress.valueOf(ipv4Packet.getDestinationAddress());
Phaneendra Mandab3555032016-02-08 11:41:53 +0530517 protocol = ipv4Packet.getProtocol();
518 if (protocol == IPv4.PROTOCOL_TCP) {
519 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
520 portSrc = tcpPacket.getSourcePort();
521 portDst = tcpPacket.getDestinationPort();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530522 } else if (protocol == IPv4.PROTOCOL_UDP) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530523 UDP udpPacket = (UDP) ipv4Packet.getPayload();
524 portSrc = udpPacket.getSourcePort();
525 portDst = udpPacket.getDestinationPort();
Phaneendra Manda089274b2016-04-11 17:21:56 +0530526 } else if (protocol == IPv4.PROTOCOL_ICMP) {
527 // do nothing
528 } else {
529 // No need to process other packets received by controller.
530 return;
Phaneendra Mandab3555032016-02-08 11:41:53 +0530531 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530532 } else {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530533 return;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530534 }
535
Phaneendra Mandab3555032016-02-08 11:41:53 +0530536 FiveTuple fiveTuple = DefaultFiveTuple.builder()
537 .setIpSrc(ipSrc)
538 .setIpDst(ipDst)
539 .setPortSrc(PortNumber.portNumber(portSrc))
540 .setPortDst(PortNumber.portNumber(portDst))
541 .setProtocol(protocol)
542 .setTenantId(tenantId)
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530543 .setMacSrc(macSrc)
544 .setMacDst(macDst)
Phaneendra Mandab3555032016-02-08 11:41:53 +0530545 .build();
546
547 PortChainId portChainId = findPortChainFromFiveTuple(fiveTuple);
548
549 if (portChainId == null) {
Phaneendra Mandab3555032016-02-08 11:41:53 +0530550 return;
551 }
552
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530553 // Once the 5 tuple and port chain are identified, give this input for load balancing
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530554 addToPortChainIdFiveTupleMap(portChainId, fiveTuple);
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530555 LoadBalanceId id = loadBalanceSfc(portChainId, fiveTuple);
556 // Get nsh service path index
557 NshServicePathId nshSpi;
558 PortChain portChain = portChainService.getPortChain(portChainId);
559 if (nshSpiPortChainMap.containsKey(portChain.portChainId())) {
560 int nshSpiId = nshSpiPortChainMap.get(portChain.portChainId());
561 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
562 } else {
563 int nshSpiId = getNextNshSpi();
564 if (nshSpiId > MAX_NSH_SPI_ID) {
565 log.error("Reached max limit of service path index."
566 + "Failed to install SFC for port chain {}", portChain.portChainId());
567 return;
568 }
569 nshSpi = NshServicePathId.of(getNshServicePathId(id, nshSpiId));
570 nshSpiPortChainMap.put(portChain.portChainId(), new Integer(nshSpiId));
571 }
Phaneendra Mandab3555032016-02-08 11:41:53 +0530572 // download the required flow rules for classifier and forwarding
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530573 // install in OVS.
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530574 SfcFlowRuleInstallerImpl flowRuleInstaller = new SfcFlowRuleInstallerImpl(appId);
575 flowRuleInstaller.installLoadBalancedFlowRules(portChain, fiveTuple, nshSpi);
576 sendPacket(context);
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530577 }
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530578
579 /**
580 * Send packet back to classifier.
581 *
582 * @param context packet context
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530583 */
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530584 private void sendPacket(PacketContext context) {
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530585
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530586 ConnectPoint sourcePoint = context.inPacket().receivedFrom();
587
Phaneendra Mandab212bc92016-07-08 16:50:11 +0530588 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(PortNumber.TABLE).build();
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530589 OutboundPacket packet = new DefaultOutboundPacket(sourcePoint.deviceId(), treatment, context.inPacket()
590 .unparsed());
Phaneendra Manda275ff0c2016-02-25 11:50:24 +0530591 packetService.emit(packet);
592 log.trace("Sending packet: {}", packet);
593 }
594 }
595
596 /**
597 * Encapsulate 5 bit load balance id to nsh spi.
598 *
599 * @param id load balance identifier
600 * @param nshSpiId nsh service path index
601 * @return updated service path index
602 */
603 protected int getNshServicePathId(LoadBalanceId id, int nshSpiId) {
604 int nshSpiNew = nshSpiId << 5;
605 nshSpiNew = nshSpiNew | id.loadBalanceId();
606 return nshSpiNew;
Phaneendra Manda5c8257b2016-02-03 22:07:38 +0530607 }
Phaneendra Manda8db7d092016-06-04 00:17:24 +0530608
609 private void addToPortChainIdFiveTupleMap(PortChainId portChainId, FiveTuple fiveTuple) {
610 List<FiveTuple> list = portChainFiveTupleMap.get(portChainId);
611 list.add(fiveTuple);
612 portChainFiveTupleMap.put(portChainId, list);
613 }
614
615 /**
616 * Find the load balanced path set it to port chain for the given five
617 * tuple.
618 *
619 * @param portChainId port chain id
620 * @param fiveTuple five tuple info
621 * @return load balance id
622 */
623 private LoadBalanceId loadBalanceSfc(PortChainId portChainId, FiveTuple fiveTuple) {
624
625 // Get the port chain
626 PortChain portChain = portChainService.getPortChain(portChainId);
627 List<PortPairId> loadBalancePath = Lists.newArrayList();
628 LoadBalanceId id;
629 int paths = portChain.getLoadBalancePathSize();
630 if (paths >= MAX_LOAD_BALANCE_ID) {
631 log.info("Max limit reached for load balance paths. "
632 + "Reusing the created path for port chain {} with five tuple {}", portChainId, fiveTuple);
633 id = LoadBalanceId.of((byte) ((paths + 1) % MAX_LOAD_BALANCE_ID));
634 portChain.addLoadBalancePath(fiveTuple, id, portChain.getLoadBalancePath(id));
635 }
636
637 // Get the list of port pair groups from port chain
638 Iterable<PortPairGroupId> portPairGroups = portChain.portPairGroups();
639 for (final PortPairGroupId portPairGroupId : portPairGroups) {
640 PortPairGroup portPairGroup = portPairGroupService.getPortPairGroup(portPairGroupId);
641
642 // Get the list of port pair ids from port pair group.
643 Iterable<PortPairId> portPairs = portPairGroup.portPairs();
644 int minLoad = 0xFFF;
645 PortPairId minLoadPortPairId = null;
646 for (final PortPairId portPairId : portPairs) {
647 int load = portPairGroup.getLoad(portPairId);
648 if (load == 0) {
649 minLoadPortPairId = portPairId;
650 break;
651 } else {
652 // Check the port pair which has min load.
653 if (load < minLoad) {
654 minLoad = load;
655 minLoadPortPairId = portPairId;
656 }
657 }
658 }
659 if (minLoadPortPairId != null) {
660 loadBalancePath.add(minLoadPortPairId);
661 portPairGroup.addLoad(minLoadPortPairId);
662 }
663 }
664
665 // Check if the path already exists, if not create a new id
666 id = portChain.matchPath(loadBalancePath);
667 if (id == null) {
668 id = LoadBalanceId.of((byte) (paths + 1));
669 }
670
671 portChain.addLoadBalancePath(fiveTuple, id, loadBalancePath);
672 return id;
673 }
674
Mahesh Poojary Sc9c10f92015-11-30 17:18:05 +0530675}