Open Kilda Java Documentation
FlowSet.java
Go to the documentation of this file.
1 /* Copyright 2018 Telstra Open Source
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package org.openkilda.atdd.staging.helpers;
17 
18 import static java.lang.String.format;
19 import static java.util.Collections.unmodifiableSet;
20 
26 
27 import com.google.common.collect.ContiguousSet;
28 import com.google.common.collect.DiscreteDomain;
29 import com.google.common.collect.Range;
30 import com.google.common.collect.RangeSet;
31 import com.google.common.collect.TreeRangeSet;
32 
33 import java.util.HashSet;
34 import java.util.Optional;
35 import java.util.Set;
36 
40 public class FlowSet {
41 
42  private Set<FlowPayload> flows = new HashSet<>();
43  private RangeSet<Integer> allocatedVlans = TreeRangeSet.create();
44 
45  public Set<FlowPayload> getFlows() {
46  return unmodifiableSet(flows);
47  }
48 
52  public int allocateVlan() {
53  RangeSet<Integer> availableVlansRange = TreeRangeSet.create();
54  availableVlansRange.removeAll(allocatedVlans);
55  Integer vlan = availableVlansRange.asRanges().stream()
56  .flatMap(range -> ContiguousSet.create(range, DiscreteDomain.integers()).stream())
57  .findFirst().get();
58  allocatedVlans.add(Range.singleton(vlan));
59  return vlan;
60  }
61 
62  public void addFlow(String flowId, Switch srcSwitch, Switch destSwitch) {
63  FlowBuilder flow = new FlowBuilder(flowId, srcSwitch, destSwitch);
64  flows.add(flow.buildWithAnyPortsInUniqueVlan());
65  }
66 
67  public void addFlow(String flowId, Switch srcSwitch, int srcPort, Switch destSwitch, int destPort) {
68  FlowBuilder flow = new FlowBuilder(flowId, srcSwitch, destSwitch);
69  flows.add(flow.buildInUniqueVlan(srcPort, destPort));
70  }
71 
72  public FlowBuilder getFlowBuilder(String flowId, Switch srcSwitch, Switch destSwitch) {
73  return new FlowBuilder(flowId, srcSwitch, destSwitch);
74  }
75 
80  public FlowPayload buildWithAnyPortsInUniqueVlan(String flowId, Switch srcSwitch, Switch destSwitch,
81  int bandwidth) {
82  FlowBuilder flowBuilder = new FlowBuilder(flowId, srcSwitch, destSwitch);
83  FlowPayload flow = flowBuilder.buildWithAnyPortsInUniqueVlan();
84  flow.setMaximumBandwidth(bandwidth);
85  return flow;
86  }
87 
88  public class FlowBuilder {
89 
90  private String flowId;
91  private Switch srcSwitch;
92  private Switch destSwitch;
93 
97  public FlowBuilder(String flowId, Switch srcSwitch, Switch destSwitch) {
98  this.flowId = flowId;
99  this.srcSwitch = srcSwitch;
100  this.destSwitch = destSwitch;
101  }
102 
108  // Take the switch vlan ranges as the base
109  RangeSet<Integer> srcRangeSet = TreeRangeSet.create();
110  srcSwitch.getOutPorts().forEach(port -> srcRangeSet.addAll(port.getVlanRange()));
111  RangeSet<Integer> destRangeSet = TreeRangeSet.create();
112  destSwitch.getOutPorts().forEach(port -> destRangeSet.addAll(port.getVlanRange()));
113  // Exclude already allocated vlans
114  srcRangeSet.removeAll(allocatedVlans);
115  destRangeSet.removeAll(allocatedVlans);
116 
117  int srcVlan = chooseSrcVlan(srcRangeSet, destRangeSet);
118  int destVlan = chooseDestVlan(srcRangeSet, destRangeSet);
119 
120  boolean sameSwitchFlow = srcSwitch.getDpId().equals(destSwitch.getDpId());
121 
122  Optional<OutPort> srcOutPort = srcSwitch.getOutPorts().stream()
123  .filter(p -> p.getVlanRange().contains(srcVlan))
124  .findFirst();
125  int srcPort = srcOutPort
126  .orElseThrow(() -> new IllegalStateException("Unable to allocate a port in found vlan."))
127  .getPort();
128 
129  Optional<OutPort> destOutPort = destSwitch.getOutPorts().stream()
130  .filter(p -> p.getVlanRange().contains(destVlan))
131  .filter(p -> !sameSwitchFlow || p.getPort() != srcPort)
132  .findFirst();
133  int destPort = destOutPort
134  .orElseThrow(() -> {
135  if (sameSwitchFlow) {
136  return new IllegalStateException(
137  format("Unable to define a same switch flow for %s as no ports available.",
138  srcSwitch));
139  } else {
140  return new IllegalStateException("Unable to allocate a port in found vlan.");
141  }
142  })
143  .getPort();
144 
145  // Record used vlan to archive uniqueness
146  allocatedVlans.add(Range.singleton(srcVlan));
147  allocatedVlans.add(Range.singleton(destVlan));
148 
149  return buildFlowPayload(srcPort, srcVlan, destPort, destVlan);
150  }
151 
159  public FlowPayload buildInUniqueVlan(int srcPort, int destPort) {
160  RangeSet<Integer> srcRangeSet = TreeRangeSet.create();
161  srcRangeSet.addAll(srcSwitch.getOutPorts().stream()
162  .filter(port -> port.getPort() == srcPort)
163  .findFirst()
164  .orElseThrow(() -> new IllegalArgumentException(
165  format("Unable to define a flow for %d port on %s switch.", srcPort, srcSwitch))
166  ).getVlanRange());
167 
168  RangeSet<Integer> destRangeSet = TreeRangeSet.create();
169  destRangeSet.addAll(destSwitch.getOutPorts().stream()
170  .filter(port -> port.getPort() == destPort)
171  .findFirst()
172  .orElseThrow(() -> new IllegalArgumentException(
173  format("Unable to define a flow for %d port on %s switch.", destPort, destSwitch))
174  ).getVlanRange());
175  // Exclude already allocated vlans
176  srcRangeSet.removeAll(allocatedVlans);
177  destRangeSet.removeAll(allocatedVlans);
178 
179  int srcVlan = chooseSrcVlan(srcRangeSet, destRangeSet);
180  int destVlan = chooseDestVlan(srcRangeSet, destRangeSet);
181 
182  // Record used vlan to archive uniqueness
183  allocatedVlans.add(Range.singleton(srcVlan));
184  allocatedVlans.add(Range.singleton(destVlan));
185 
186  return buildFlowPayload(srcPort, srcVlan, destPort, destVlan);
187  }
188 
189  private int chooseSrcVlan(RangeSet<Integer> srcRangeSet, RangeSet<Integer> destRangeSet) {
190  if (srcRangeSet.isEmpty() || destRangeSet.isEmpty()) {
191  throw new IllegalStateException(
192  format("Unable to define a flow between %s and %s as no vlan available.", srcSwitch,
193  destSwitch));
194  }
195 
196  // Calculate intersection of the ranges
197  RangeSet<Integer> interRangeSet = TreeRangeSet.create(srcRangeSet);
198  interRangeSet.removeAll(destRangeSet.complement());
199  // Same vlan for source and destination
200  final Optional<Integer> sameVlan = interRangeSet.asRanges().stream()
201  .flatMap(range -> ContiguousSet.create(range, DiscreteDomain.integers()).stream())
202  .findFirst();
203 
204  if (sameVlan.isPresent()) {
205  return sameVlan.get();
206  } else {
207  // Cross vlan flow
208  Optional<Integer> srcVlanOpt = srcRangeSet.asRanges().stream()
209  .flatMap(range -> ContiguousSet.create(range, DiscreteDomain.integers()).stream())
210  .findFirst();
211  if (!srcVlanOpt.isPresent()) {
212  throw new IllegalStateException(
213  format("Unable to allocate a vlan for the switch %s.", srcSwitch));
214 
215  }
216  return srcVlanOpt.get();
217  }
218  }
219 
220  private int chooseDestVlan(RangeSet<Integer> srcRangeSet, RangeSet<Integer> destRangeSet) {
221  if (srcRangeSet.isEmpty() || destRangeSet.isEmpty()) {
222  throw new IllegalStateException(
223  format("Unable to define a flow between %s and %s as no vlan available.", srcSwitch,
224  destSwitch));
225  }
226 
227  // Calculate intersection of the ranges
228  RangeSet<Integer> interRangeSet = TreeRangeSet.create(srcRangeSet);
229  interRangeSet.removeAll(destRangeSet.complement());
230  // Same vlan for source and destination
231  final Optional<Integer> sameVlan = interRangeSet.asRanges().stream()
232  .flatMap(range -> ContiguousSet.create(range, DiscreteDomain.integers()).stream())
233  .findFirst();
234 
235  if (sameVlan.isPresent()) {
236  return sameVlan.get();
237  } else {
238  // Cross vlan flow
239  Optional<Integer> destVlanOpt = destRangeSet.asRanges().stream()
240  .flatMap(range -> ContiguousSet.create(range, DiscreteDomain.integers()).stream())
241  .findFirst();
242  if (!destVlanOpt.isPresent()) {
243  throw new IllegalStateException(
244  format("Unable to allocate a vlan for the switch %s.", destSwitch));
245  }
246  return destVlanOpt.get();
247  }
248  }
249 
250  private FlowPayload buildFlowPayload(int srcPort, int srcVlan, int destPort, int destVlan) {
251  FlowEndpointPayload srcEndpoint = new FlowEndpointPayload(srcSwitch.getDpId(), srcPort, srcVlan);
252  FlowEndpointPayload destEndpoint = new FlowEndpointPayload(destSwitch.getDpId(), destPort, destVlan);
253 
254  return new FlowPayload(flowId, srcEndpoint, destEndpoint,
255  1, false, flowId, null, FlowState.UP.getState());
256  }
257  }
258 }
259 
void setMaximumBandwidth(long maximumBandwidth)
FlowBuilder getFlowBuilder(String flowId, Switch srcSwitch, Switch destSwitch)
Definition: FlowSet.java:72
void addFlow(String flowId, Switch srcSwitch, int srcPort, Switch destSwitch, int destPort)
Definition: FlowSet.java:67
void addFlow(String flowId, Switch srcSwitch, Switch destSwitch)
Definition: FlowSet.java:62
FlowPayload buildInUniqueVlan(int srcPort, int destPort)
Definition: FlowSet.java:159
FlowPayload buildWithAnyPortsInUniqueVlan(String flowId, Switch srcSwitch, Switch destSwitch, int bandwidth)
Definition: FlowSet.java:80
FlowBuilder(String flowId, Switch srcSwitch, Switch destSwitch)
Definition: FlowSet.java:97