blob: 02923c2a4e8ce8f9f0bf24c91d9bcbfcf0736ad5 [file] [log] [blame]
Daniele Moro8d630f12021-06-15 20:53:22 +02001/*
2 * Copyright 2021-present Open Networking Foundation
3 *
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 */
16
17package org.onosproject.pipelines.fabric.impl.behaviour.upf;
18
19import com.google.common.collect.BiMap;
20import com.google.common.collect.ImmutableBiMap;
21import com.google.common.collect.Maps;
Daniele Moro8d630f12021-06-15 20:53:22 +020022import org.onlab.util.ImmutableByteSequence;
23import org.onlab.util.KryoNamespace;
Daniele Moro8d630f12021-06-15 20:53:22 +020024import org.onosproject.store.serializers.KryoNamespaces;
25import org.onosproject.store.service.ConsistentMap;
Daniele Moro8d630f12021-06-15 20:53:22 +020026import org.onosproject.store.service.MapEvent;
27import org.onosproject.store.service.MapEventListener;
28import org.onosproject.store.service.Serializer;
29import org.onosproject.store.service.StorageService;
30import org.osgi.service.component.annotations.Activate;
31import org.osgi.service.component.annotations.Component;
32import org.osgi.service.component.annotations.Deactivate;
33import org.osgi.service.component.annotations.Reference;
34import org.osgi.service.component.annotations.ReferenceCardinality;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
Daniele Moro8d630f12021-06-15 20:53:22 +020038import java.util.Map;
39import java.util.Objects;
Daniele Moro8d630f12021-06-15 20:53:22 +020040
41/**
42 * Distributed implementation of FabricUpfStore.
43 */
44// FIXME: this store is generic and not tied to a single device, should we have a store based on deviceId?
45@Component(immediate = true, service = FabricUpfStore.class)
46public final class DistributedFabricUpfStore implements FabricUpfStore {
47
48 private final Logger log = LoggerFactory.getLogger(getClass());
49
50 @Reference(cardinality = ReferenceCardinality.MANDATORY)
51 protected StorageService storageService;
52
53 protected static final String FAR_ID_MAP_NAME = "fabric-upf-far-id";
Daniele Moro8d630f12021-06-15 20:53:22 +020054 protected static final KryoNamespace.Builder SERIALIZER = KryoNamespace.newBuilder()
55 .register(KryoNamespaces.API)
56 .register(UpfRuleIdentifier.class);
57
58 // TODO: check queue IDs for BMv2, is priority inverted?
59 // Mapping between scheduling priority ranges with BMv2 priority queues
60 private static final BiMap<Integer, Integer> SCHEDULING_PRIORITY_MAP
61 = new ImmutableBiMap.Builder<Integer, Integer>()
62 // Highest scheduling priority for 3GPP is 1 and highest BMv2 queue priority is 7
63 .put(1, 5)
64 .put(6, 4)
65 .put(7, 3)
66 .put(8, 2)
67 .put(9, 1)
68 .build();
69
70 // Distributed local FAR ID to global FAR ID mapping
71 protected ConsistentMap<UpfRuleIdentifier, Integer> farIdMap;
72 private MapEventListener<UpfRuleIdentifier, Integer> farIdMapListener;
73 // Local, reversed copy of farIdMapper for better reverse lookup performance
74 protected Map<Integer, UpfRuleIdentifier> reverseFarIdMap;
75 private int nextGlobalFarId = 1;
76
Daniele Moro8d630f12021-06-15 20:53:22 +020077 @Activate
78 protected void activate() {
79 // Allow unit test to inject farIdMap here.
80 if (storageService != null) {
81 this.farIdMap = storageService.<UpfRuleIdentifier, Integer>consistentMapBuilder()
82 .withName(FAR_ID_MAP_NAME)
83 .withRelaxedReadConsistency()
84 .withSerializer(Serializer.using(SERIALIZER.build()))
85 .build();
Daniele Moro8d630f12021-06-15 20:53:22 +020086 }
87 farIdMapListener = new FarIdMapListener();
88 farIdMap.addListener(farIdMapListener);
89
90 reverseFarIdMap = Maps.newHashMap();
91 farIdMap.entrySet().forEach(entry -> reverseFarIdMap.put(entry.getValue().value(), entry.getKey()));
92
93 log.info("Started");
94 }
95
96 @Deactivate
97 protected void deactivate() {
98 farIdMap.removeListener(farIdMapListener);
99 farIdMap.destroy();
100 reverseFarIdMap.clear();
101
102 log.info("Stopped");
103 }
104
105 @Override
106 public void reset() {
107 farIdMap.clear();
108 reverseFarIdMap.clear();
Daniele Moro8d630f12021-06-15 20:53:22 +0200109 nextGlobalFarId = 0;
110 }
111
112 @Override
113 public Map<UpfRuleIdentifier, Integer> getFarIdMap() {
114 return Map.copyOf(farIdMap.asJavaMap());
115 }
116
117 @Override
118 public int globalFarIdOf(UpfRuleIdentifier farIdPair) {
119 int globalFarId = farIdMap.compute(farIdPair,
120 (k, existingId) -> {
121 return Objects.requireNonNullElseGet(existingId, () -> nextGlobalFarId++);
122 }).value();
123 log.info("{} translated to GlobalFarId={}", farIdPair, globalFarId);
124 return globalFarId;
125 }
126
127 @Override
128 public int globalFarIdOf(ImmutableByteSequence pfcpSessionId, int sessionLocalFarId) {
129 UpfRuleIdentifier farId = new UpfRuleIdentifier(pfcpSessionId, sessionLocalFarId);
130 return globalFarIdOf(farId);
131
132 }
133
134 @Override
135 public String queueIdOf(int schedulingPriority) {
136 return (SCHEDULING_PRIORITY_MAP.get(schedulingPriority)).toString();
137 }
138
139 @Override
140 public String schedulingPriorityOf(int queueId) {
141 return (SCHEDULING_PRIORITY_MAP.inverse().get(queueId)).toString();
142 }
143
144 @Override
145 public UpfRuleIdentifier localFarIdOf(int globalFarId) {
146 return reverseFarIdMap.get(globalFarId);
147 }
148
Daniele Moro8d630f12021-06-15 20:53:22 +0200149 // NOTE: FarIdMapListener is run on the same thread intentionally in order to ensure that
150 // reverseFarIdMap update always finishes right after farIdMap is updated
151 private class FarIdMapListener implements MapEventListener<UpfRuleIdentifier, Integer> {
152 @Override
153 public void event(MapEvent<UpfRuleIdentifier, Integer> event) {
154 switch (event.type()) {
155 case INSERT:
156 reverseFarIdMap.put(event.newValue().value(), event.key());
157 break;
158 case UPDATE:
159 reverseFarIdMap.remove(event.oldValue().value());
160 reverseFarIdMap.put(event.newValue().value(), event.key());
161 break;
162 case REMOVE:
163 reverseFarIdMap.remove(event.oldValue().value());
164 break;
165 default:
166 break;
167 }
168 }
169 }
170}