blob: 5aa7fcd8301cba31e856406b605ee63de0af6223 [file] [log] [blame]
Thomas Vachuska0d933862018-04-06 00:29:30 -07001/*
2 * Copyright 2018-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.layout;
18
19import com.google.common.collect.HashMultiset;
20import com.google.common.collect.Multiset;
21import com.google.common.collect.Sets;
22import org.onosproject.net.ConnectPoint;
23import org.onosproject.net.Device;
24import org.onosproject.net.DeviceId;
25import org.onosproject.net.Host;
26import org.onosproject.net.HostId;
27import org.onosproject.utils.Comparators;
28
29import java.util.List;
30import java.util.Set;
31import java.util.stream.Collectors;
32
33/**
34 * Arranges access network according to roles assigned to devices and hosts.
35 */
36public class AccessNetworkLayout extends LayoutAlgorithm {
37
38 private static final double COMPUTE_Y = -400.0;
39 private static final double SERVICE_Y = -200.0;
40 private static final double SPINE_Y = 0.0;
41 private static final double AGGREGATION_Y = +200.0;
42 private static final double ACCESS_Y = +400.0;
43 private static final double HOSTS_Y = +700.0;
44 private static final double GATEWAY_X = 900.0;
45
46 private static final int HOSTS_PER_ROW = 6;
47 private static final double ROW_GAP = 70;
48 private static final double COL_GAP = 50;
49 private static final double COMPUTE_GAP = 60.0;
50 private static final double COMPUTE_OFFSET = 400.0;
51 private static final double GATEWAY_GAP = 200.0;
52 private static final double GATEWAY_OFFSET = -200.0;
53
54 private int spine, aggregation, accessLeaf, serviceLeaf, compute, gateway;
55
56 @Override
57 protected boolean classify(Device device) {
58 if (!super.classify(device)) {
59 String role;
60
61 // Does the device have any hosts attached? If not, it's a spine
62 if (hostService.getConnectedHosts(device.id()).isEmpty()) {
63 // Does the device have any aggregate links to other devices?
64 Multiset<DeviceId> destinations = HashMultiset.create();
65 linkService.getDeviceEgressLinks(device.id()).stream()
66 .map(l -> l.dst().deviceId()).forEach(destinations::add);
67
68 // If yes, it's the main spine; otherwise it's an aggregate spine
69 role = destinations.entrySet().stream().anyMatch(e -> e.getCount() > 1) ?
70 SPINE : AGGREGATION;
71 } else {
72 // Does the device have any multi-home hosts attached?
73 // If yes, it's a service leaf; otherwise it's an access leaf
74 role = hostService.getConnectedHosts(device.id()).stream()
75 .map(Host::locations).anyMatch(s -> s.size() > 1) ?
76 LEAF : ACCESS;
77 }
78 deviceCategories.put(role, device.id());
79 }
80 return true;
81 }
82
83 @Override
84 protected boolean classify(Host host) {
85 if (!super.classify(host)) {
86 // Is the host attached to an access leaf?
87 // If so, it's an access host; otherwise it's a service host or gateway
88 String role = host.locations().stream().map(ConnectPoint::deviceId)
89 .anyMatch(d -> deviceCategories.get(ACCESS)
90 .contains(deviceService.getDevice(d).id())) ?
91 ACCESS : COMPUTE;
92 hostCategories.put(role, host.id());
93 }
94 return true;
95 }
96
97 @Override
98 public void apply() {
99 placeSpines();
100 placeServiceLeavesAndHosts();
101 placeAccessLeavesAndHosts();
102 }
103
104 private void placeSpines() {
105 spine = 1;
106 List<DeviceId> spines = deviceCategories.get(SPINE);
107 spines.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR)
108 .forEach(d -> place(d, c(spine++, spines.size()), SPINE_Y));
109 }
110
111 private void placeServiceLeavesAndHosts() {
112 List<DeviceId> leaves = deviceCategories.get(LEAF);
113 List<HostId> computes = hostCategories.get(COMPUTE);
114 List<HostId> gateways = hostCategories.get(GATEWAY);
115 Set<HostId> placed = Sets.newHashSet();
116
117 serviceLeaf = 1;
118 leaves.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR).forEach(id -> {
119 gateway = 1;
120 place(id, c(serviceLeaf++, leaves.size()), SERVICE_Y);
121
122 List<HostId> gwHosts = hostService.getConnectedHosts(id).stream()
123 .map(Host::id)
124 .filter(gateways::contains)
125 .filter(hid -> !placed.contains(hid))
126 .sorted(Comparators.ELEMENT_ID_COMPARATOR)
127 .collect(Collectors.toList());
128
129 gwHosts.forEach(hid -> {
130 place(hid, serviceLeaf <= 2 ? -GATEWAY_X : GATEWAY_X,
131 c(gateway++, gwHosts.size(), GATEWAY_GAP, GATEWAY_OFFSET));
132 placed.add(hid);
133 });
134
135 compute = 1;
136 List<HostId> hosts = hostService.getConnectedHosts(id).stream()
137 .map(Host::id)
138 .filter(computes::contains)
139 .filter(hid -> !placed.contains(hid))
140 .sorted(Comparators.ELEMENT_ID_COMPARATOR)
141 .collect(Collectors.toList());
142
143 hosts.forEach(hid -> {
144 place(hid, c(compute++, hosts.size(), COMPUTE_GAP,
145 serviceLeaf <= 2 ? -COMPUTE_OFFSET : COMPUTE_OFFSET),
146 COMPUTE_Y);
147 placed.add(hid);
148 });
149
150 });
151 }
152
153 private void placeAccessLeavesAndHosts() {
154 List<DeviceId> spines = deviceCategories.get(AGGREGATION);
155 List<DeviceId> leaves = deviceCategories.get(ACCESS);
156 Set<DeviceId> placed = Sets.newHashSet();
157
158 aggregation = 1;
159 accessLeaf = 1;
Thomas Vachuska834cc082018-04-24 22:39:22 -0400160 if (spines.isEmpty()) {
161 leaves.forEach(lid -> placeAccessLeafAndHosts(lid, leaves.size(), placed));
162 } else {
163 spines.stream().sorted(Comparators.ELEMENT_ID_COMPARATOR).forEach(id -> {
164 place(id, c(aggregation++, spines.size()), AGGREGATION_Y);
165 linkService.getDeviceEgressLinks(id).stream()
166 .map(l -> l.dst().deviceId())
167 .filter(leaves::contains)
168 .filter(lid -> !placed.contains(lid))
169 .sorted(Comparators.ELEMENT_ID_COMPARATOR)
170 .forEach(lid -> placeAccessLeafAndHosts(lid, leaves.size(), placed));
171 });
172 }
173 }
174
175 private void placeAccessLeafAndHosts(DeviceId leafId, int leafCount, Set<DeviceId> placed) {
176 double x = c(accessLeaf++, leafCount);
177 place(leafId, x, ACCESS_Y);
178 placed.add(leafId);
179 placeHostBlock(hostService.getConnectedHosts(leafId).stream()
180 .map(Host::id)
181 .sorted(Comparators.ELEMENT_ID_COMPARATOR)
182 .collect(Collectors.toList()), x, HOSTS_Y,
183 HOSTS_PER_ROW, ROW_GAP, COL_GAP);
Thomas Vachuska0d933862018-04-06 00:29:30 -0700184 }
185
186}