blob: d3e36bf064e741e72bb2a9cc128d48a3ba56ee30 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003 *
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.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
Jian Lie6110b72018-07-06 19:06:36 +090020import com.google.common.collect.Sets;
daniel parkb5817102018-02-15 00:18:51 +090021import org.onlab.packet.ARP;
22import org.onlab.packet.Ethernet;
23import org.onlab.packet.IpAddress;
Jian Lie6110b72018-07-06 19:06:36 +090024import org.onlab.packet.IpPrefix;
daniel parkb5817102018-02-15 00:18:51 +090025import org.onlab.packet.MacAddress;
26import org.onlab.packet.VlanId;
27import org.onlab.util.KryoNamespace;
28import org.onosproject.core.ApplicationId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090029import org.onosproject.core.CoreService;
30import org.onosproject.event.ListenerRegistry;
daniel parkb5817102018-02-15 00:18:51 +090031import org.onosproject.net.device.DeviceService;
32import org.onosproject.net.flow.DefaultTrafficTreatment;
33import org.onosproject.net.flow.TrafficTreatment;
34import org.onosproject.net.packet.DefaultOutboundPacket;
35import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.openstacknetworking.api.Constants;
daniel parkb5817102018-02-15 00:18:51 +090037import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
SONA Project6bc5c4a2018-12-14 23:49:52 +090038import org.onosproject.openstacknetworking.api.OpenstackNetwork;
39import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
41import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
42import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
43import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
44import org.onosproject.openstacknetworking.api.OpenstackNetworkStore;
45import org.onosproject.openstacknetworking.api.OpenstackNetworkStoreDelegate;
daniel parkb5817102018-02-15 00:18:51 +090046import org.onosproject.openstacknode.api.OpenstackNode;
47import org.onosproject.openstacknode.api.OpenstackNodeService;
48import org.onosproject.store.serializers.KryoNamespaces;
49import org.onosproject.store.service.ConsistentMap;
50import org.onosproject.store.service.Serializer;
51import org.onosproject.store.service.StorageService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090052import org.onosproject.store.service.Versioned;
daniel parkb5817102018-02-15 00:18:51 +090053import org.openstack4j.model.network.ExternalGateway;
54import org.openstack4j.model.network.IP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.Network;
56import org.openstack4j.model.network.Port;
daniel parkb5817102018-02-15 00:18:51 +090057import org.openstack4j.model.network.Router;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Subnet;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070059import org.osgi.service.component.annotations.Activate;
60import org.osgi.service.component.annotations.Component;
61import org.osgi.service.component.annotations.Deactivate;
62import org.osgi.service.component.annotations.Reference;
63import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.slf4j.Logger;
65
daniel parkb5817102018-02-15 00:18:51 +090066import java.nio.ByteBuffer;
SONA Project6bc5c4a2018-12-14 23:49:52 +090067import java.util.Map;
daniel parkb5817102018-02-15 00:18:51 +090068import java.util.NoSuchElementException;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069import java.util.Objects;
70import java.util.Optional;
71import java.util.Set;
72import java.util.stream.Collectors;
73
74import static com.google.common.base.Preconditions.checkArgument;
75import static com.google.common.base.Preconditions.checkNotNull;
Jian Li5ecfd1a2018-12-10 11:41:03 +090076import static java.util.Objects.requireNonNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090077import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parkc4d06402018-05-28 15:57:37 +090078import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
79import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
SONA Project6bc5c4a2018-12-14 23:49:52 +090080import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
81import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
82import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
83import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.LOCAL;
84import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
85import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Daniel Parkc4d06402018-05-28 15:57:37 +090086import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getIntfNameFromPciAddress;
Daniel Park7e8c4d82018-08-13 23:47:49 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
Jian Li5ecfd1a2018-12-10 11:41:03 +090088import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089import static org.slf4j.LoggerFactory.getLogger;
90
91/**
92 * Provides implementation of administering and interfacing OpenStack network,
93 * subnet, and port.
94 */
daniel parkb5817102018-02-15 00:18:51 +090095
Jian Li5ecfd1a2018-12-10 11:41:03 +090096@Component(
97 immediate = true,
98 service = { OpenstackNetworkAdminService.class, OpenstackNetworkService.class }
99)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900100public class OpenstackNetworkManager
101 extends ListenerRegistry<OpenstackNetworkEvent, OpenstackNetworkListener>
102 implements OpenstackNetworkAdminService, OpenstackNetworkService {
103
104 protected final Logger log = getLogger(getClass());
105
106 private static final String MSG_NETWORK = "OpenStack network %s %s";
SONA Project6bc5c4a2018-12-14 23:49:52 +0900107 private static final String MSG_NETWORK_TYPE = "OpenStack network type %s %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108 private static final String MSG_SUBNET = "OpenStack subnet %s %s";
109 private static final String MSG_PORT = "OpenStack port %s %s";
110 private static final String MSG_CREATED = "created";
111 private static final String MSG_UPDATED = "updated";
112 private static final String MSG_REMOVED = "removed";
113
SONA Project6bc5c4a2018-12-14 23:49:52 +0900114 private static final String ERR_NOT_FOUND = " does not exist";
115 private static final String ERR_DUPLICATE = " already exists";
116
Jian Li5ecfd1a2018-12-10 11:41:03 +0900117 private static final String ERR_NULL_NETWORK =
118 "OpenStack network cannot be null";
119 private static final String ERR_NULL_NETWORK_ID =
120 "OpenStack network ID cannot be null";
121 private static final String ERR_NULL_SUBNET =
122 "OpenStack subnet cannot be null";
123 private static final String ERR_NULL_SUBNET_ID =
124 "OpenStack subnet ID cannot be null";
125 private static final String ERR_NULL_SUBNET_NET_ID =
126 "OpenStack subnet network ID cannot be null";
127 private static final String ERR_NULL_SUBNET_CIDR =
128 "OpenStack subnet CIDR cannot be null";
129 private static final String ERR_NULL_PORT =
130 "OpenStack port cannot be null";
131 private static final String ERR_NULL_PORT_ID =
132 "OpenStack port ID cannot be null";
133 private static final String ERR_NULL_PORT_NET_ID =
134 "OpenStack port network ID cannot be null";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135
136 private static final String ERR_IN_USE = " still in use";
Daniel Parkc4d06402018-05-28 15:57:37 +0900137
Jian Lie6110b72018-07-06 19:06:36 +0900138 private static final int PREFIX_LENGTH = 32;
139
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 protected CoreService coreService;
143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900145 protected PacketService packetService;
146
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900148 protected DeviceService deviceService;
149
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151 protected OpenstackNetworkStore osNetworkStore;
152
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900154 protected StorageService storageService;
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900157 protected OpenstackNodeService osNodeService;
158
Jian Li5ecfd1a2018-12-10 11:41:03 +0900159 private final OpenstackNetworkStoreDelegate
160 delegate = new InternalNetworkStoreDelegate();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161
daniel parkb5817102018-02-15 00:18:51 +0900162 private ConsistentMap<String, ExternalPeerRouter> externalPeerRouterMap;
SONA Project6bc5c4a2018-12-14 23:49:52 +0900163 private ConsistentMap<String, OpenstackNetwork> augmentedNetworkMap;
daniel parkb5817102018-02-15 00:18:51 +0900164
Jian Li5ecfd1a2018-12-10 11:41:03 +0900165 private static final KryoNamespace
166 SERIALIZER_EXTERNAL_PEER_ROUTER_MAP = KryoNamespace.newBuilder()
daniel parkb5817102018-02-15 00:18:51 +0900167 .register(KryoNamespaces.API)
168 .register(ExternalPeerRouter.class)
169 .register(DefaultExternalPeerRouter.class)
170 .register(MacAddress.class)
171 .register(IpAddress.class)
172 .register(VlanId.class)
173 .build();
174
SONA Project6bc5c4a2018-12-14 23:49:52 +0900175 private static final KryoNamespace
176 SERIALIZER_AUGMENTED_NETWORK_MAP = KryoNamespace.newBuilder()
177 .register(KryoNamespaces.API)
178 .register(OpenstackNetwork.Type.class)
179 .register(OpenstackNetwork.class)
180 .register(DefaultOpenstackNetwork.class)
181 .build();
182
daniel parkb5817102018-02-15 00:18:51 +0900183 private ApplicationId appId;
184
185
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 @Activate
187 protected void activate() {
daniel parkb5817102018-02-15 00:18:51 +0900188 appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
189
Hyunsun Moon44aac662017-02-18 02:07:01 +0900190 osNetworkStore.setDelegate(delegate);
191 log.info("Started");
daniel parkb5817102018-02-15 00:18:51 +0900192
193 externalPeerRouterMap = storageService.<String, ExternalPeerRouter>consistentMapBuilder()
194 .withSerializer(Serializer.using(SERIALIZER_EXTERNAL_PEER_ROUTER_MAP))
195 .withName("external-routermap")
196 .withApplicationId(appId)
197 .build();
SONA Project6bc5c4a2018-12-14 23:49:52 +0900198
199 augmentedNetworkMap = storageService.<String, OpenstackNetwork>consistentMapBuilder()
200 .withSerializer(Serializer.using(SERIALIZER_AUGMENTED_NETWORK_MAP))
201 .withName("augmented-networkmap")
202 .withApplicationId(appId)
203 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900204 }
205
206 @Deactivate
207 protected void deactivate() {
208 osNetworkStore.unsetDelegate(delegate);
209 log.info("Stopped");
210 }
211
212 @Override
213 public void createNetwork(Network osNet) {
214 checkNotNull(osNet, ERR_NULL_NETWORK);
215 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216
217 osNetworkStore.createNetwork(osNet);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900218
219 OpenstackNetwork finalAugmentedNetwork = buildAugmentedNetworkFromType(osNet);
220 augmentedNetworkMap.compute(osNet.getId(), (id, existing) -> {
221 final String error = osNet.getId() + ERR_DUPLICATE;
222 checkArgument(existing == null, error);
223 return finalAugmentedNetwork;
224 });
225
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 log.info(String.format(MSG_NETWORK, osNet.getName(), MSG_CREATED));
227 }
228
229 @Override
230 public void updateNetwork(Network osNet) {
231 checkNotNull(osNet, ERR_NULL_NETWORK);
232 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233
234 osNetworkStore.updateNetwork(osNet);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900235
236 OpenstackNetwork finalAugmentedNetwork = buildAugmentedNetworkFromType(osNet);
237 augmentedNetworkMap.compute(osNet.getId(), (id, existing) -> {
238 final String error = osNet.getId() + ERR_NOT_FOUND;
239 checkArgument(existing != null, error);
240 return finalAugmentedNetwork;
241 });
242
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 log.info(String.format(MSG_NETWORK, osNet.getId(), MSG_UPDATED));
244 }
245
246 @Override
247 public void removeNetwork(String netId) {
248 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
249 synchronized (this) {
250 if (isNetworkInUse(netId)) {
251 final String error = String.format(MSG_NETWORK, netId, ERR_IN_USE);
252 throw new IllegalStateException(error);
253 }
254 Network osNet = osNetworkStore.removeNetwork(netId);
255 if (osNet != null) {
256 log.info(String.format(MSG_NETWORK, osNet.getName(), MSG_REMOVED));
257 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900258
259 Versioned<OpenstackNetwork> augmentedNetwork = augmentedNetworkMap.remove(netId);
260 if (augmentedNetwork != null) {
261 log.info(String.format(MSG_NETWORK_TYPE,
262 augmentedNetwork.value().type(), MSG_REMOVED));
263 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264 }
265 }
266
267 @Override
268 public void createSubnet(Subnet osSubnet) {
269 checkNotNull(osSubnet, ERR_NULL_SUBNET);
270 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
271 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
272 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
273
274 osNetworkStore.createSubnet(osSubnet);
275 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_CREATED));
276 }
277
278 @Override
279 public void updateSubnet(Subnet osSubnet) {
280 checkNotNull(osSubnet, ERR_NULL_SUBNET);
281 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
282 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
283 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
284
285 osNetworkStore.updateSubnet(osSubnet);
286 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_UPDATED));
287 }
288
289 @Override
290 public void removeSubnet(String subnetId) {
291 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
292 synchronized (this) {
293 if (isSubnetInUse(subnetId)) {
294 final String error = String.format(MSG_SUBNET, subnetId, ERR_IN_USE);
295 throw new IllegalStateException(error);
296 }
297 Subnet osSubnet = osNetworkStore.removeSubnet(subnetId);
298 if (osSubnet != null) {
299 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_REMOVED));
300 }
301 }
302 }
303
304 @Override
305 public void createPort(Port osPort) {
306 checkNotNull(osPort, ERR_NULL_PORT);
307 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
308 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
309
310 osNetworkStore.createPort(osPort);
311 log.info(String.format(MSG_PORT, osPort.getId(), MSG_CREATED));
312 }
313
314 @Override
315 public void updatePort(Port osPort) {
316 checkNotNull(osPort, ERR_NULL_PORT);
317 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
318 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
319
320 osNetworkStore.updatePort(osPort);
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900321 log.info(String.format(MSG_PORT, osPort.getId(), MSG_UPDATED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900322 }
323
324 @Override
325 public void removePort(String portId) {
326 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
327 synchronized (this) {
328 if (isPortInUse(portId)) {
329 final String error = String.format(MSG_PORT, portId, ERR_IN_USE);
330 throw new IllegalStateException(error);
331 }
332 Port osPort = osNetworkStore.removePort(portId);
333 if (osPort != null) {
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900334 log.info(String.format(MSG_PORT, osPort.getId(), MSG_REMOVED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 }
336 }
337 }
338
339 @Override
Hyunsun Moonc7219222017-03-27 11:05:59 +0900340 public void clear() {
341 osNetworkStore.clear();
Daniel Park2fe39662019-02-20 16:04:40 +0900342 augmentedNetworkMap.clear();
343 externalPeerRouterMap.clear();
Hyunsun Moonc7219222017-03-27 11:05:59 +0900344 }
345
346 @Override
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 public Network network(String netId) {
348 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
349 return osNetworkStore.network(netId);
350 }
351
352 @Override
353 public Set<Network> networks() {
354 return osNetworkStore.networks();
355 }
356
357 @Override
358 public Subnet subnet(String subnetId) {
359 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
360 return osNetworkStore.subnet(subnetId);
361 }
362
363 @Override
364 public Set<Subnet> subnets() {
365 return osNetworkStore.subnets();
366 }
367
368 @Override
369 public Set<Subnet> subnets(String netId) {
370 Set<Subnet> osSubnets = osNetworkStore.subnets().stream()
371 .filter(subnet -> Objects.equals(subnet.getNetworkId(), netId))
372 .collect(Collectors.toSet());
373 return ImmutableSet.copyOf(osSubnets);
374 }
375
376 @Override
377 public Port port(String portId) {
378 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
379 return osNetworkStore.port(portId);
380 }
381
382 @Override
383 public Port port(org.onosproject.net.Port port) {
384 String portName = port.annotations().value(PORT_NAME);
385 if (Strings.isNullOrEmpty(portName)) {
386 return null;
387 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900388
Daniel Park7e8c4d82018-08-13 23:47:49 +0900389 try {
390 Optional<Port> osPort;
391 switch (vnicType(portName)) {
392 case NORMAL:
393 osPort = osNetworkStore.ports()
394 .stream()
395 .filter(p -> p.getId().contains(portName.substring(3)))
396 .findFirst();
397 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900398 case DIRECT:
399 //Additional prefixes will be added
400 osPort = osNetworkStore.ports()
401 .stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900402 .filter(p -> p.getvNicType().equals(DIRECT) &&
403 p.getProfile().get(PCISLOT) != null)
404 .filter(p -> requireNonNull(
405 getIntfNameFromPciAddress(p)).equals(portName))
Daniel Park7e8c4d82018-08-13 23:47:49 +0900406 .findFirst();
407 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900408 default:
409 return null;
410 }
411 } catch (IllegalArgumentException e) {
412 log.error("IllegalArgumentException occurred because of {}", e);
Daniel Parkc4d06402018-05-28 15:57:37 +0900413 return null;
414 }
415 }
416
Hyunsun Moon44aac662017-02-18 02:07:01 +0900417 @Override
418 public Set<Port> ports() {
daniel parkb5817102018-02-15 00:18:51 +0900419 return ImmutableSet.copyOf(osNetworkStore.ports());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900420 }
421
422 @Override
423 public Set<Port> ports(String netId) {
424 Set<Port> osPorts = osNetworkStore.ports().stream()
425 .filter(port -> Objects.equals(port.getNetworkId(), netId))
426 .collect(Collectors.toSet());
427 return ImmutableSet.copyOf(osPorts);
428 }
429
daniel parkb5817102018-02-15 00:18:51 +0900430 @Override
Jian Lie6110b72018-07-06 19:06:36 +0900431 public Set<IpPrefix> getFixedIpsByNetworkType(String type) {
432 if (type == null) {
433 return Sets.newHashSet();
434 }
435
Jian Lie6110b72018-07-06 19:06:36 +0900436 Set<String> networkIds = Sets.newConcurrentHashSet();
437
438 switch (type.toUpperCase()) {
Jian Li621f73c2018-12-15 01:49:22 +0900439 case Constants.FLAT :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900440 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
441 .filter(e -> e.getValue().type() == FLAT)
442 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900443 break;
Jian Li621f73c2018-12-15 01:49:22 +0900444 case Constants.VXLAN :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900445 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
Jian Li621f73c2018-12-15 01:49:22 +0900446 .filter(e -> e.getValue().type() == VXLAN)
SONA Project6bc5c4a2018-12-14 23:49:52 +0900447 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900448 break;
Jian Li621f73c2018-12-15 01:49:22 +0900449 case Constants.GRE :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900450 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
Jian Li621f73c2018-12-15 01:49:22 +0900451 .filter(e -> e.getValue().type() == GRE)
SONA Project6bc5c4a2018-12-14 23:49:52 +0900452 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Li2d68c192018-12-13 15:52:59 +0900453 break;
Jian Li621f73c2018-12-15 01:49:22 +0900454 case Constants.VLAN :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900455 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
456 .filter(e -> e.getValue().type() == VLAN)
457 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900458 break;
Jian Li621f73c2018-12-15 01:49:22 +0900459 case Constants.GENEVE :
460 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
461 .filter(e -> e.getValue().type() == GENEVE)
462 .map(Map.Entry::getKey).collect(Collectors.toSet());
463 break;
Jian Lie6110b72018-07-06 19:06:36 +0900464 default:
465 break;
466 }
467
468 Set<IP> ips = Sets.newConcurrentHashSet();
469 for (String networkId : networkIds) {
470 osNetworkStore.ports()
471 .stream()
472 .filter(p -> p.getNetworkId().equals(networkId))
473 .filter(p -> p.getFixedIps() != null)
474 .forEach(p -> ips.addAll(p.getFixedIps()));
475 }
476
477 return ips.stream().map(ip -> IpPrefix.valueOf(
478 IpAddress.valueOf(ip.getIpAddress()), PREFIX_LENGTH))
479 .collect(Collectors.toSet());
480 }
481
482 @Override
daniel parkb5817102018-02-15 00:18:51 +0900483 public ExternalPeerRouter externalPeerRouter(IpAddress ipAddress) {
484 if (externalPeerRouterMap.containsKey(ipAddress.toString())) {
485 return externalPeerRouterMap.get(ipAddress.toString()).value();
486 }
487 return null;
488 }
489
490 @Override
daniel park576969a2018-03-09 07:07:41 +0900491 public ExternalPeerRouter externalPeerRouter(ExternalGateway externalGateway) {
492 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
493
494 if (ipAddress == null) {
495 return null;
496 }
497
498 if (externalPeerRouterMap.containsKey(ipAddress.toString())) {
499 return externalPeerRouterMap.get(ipAddress.toString()).value();
500 } else {
501 return null;
502 }
503 }
504
505 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900506 public void deriveExternalPeerRouterMac(ExternalGateway externalGateway,
507 Router router, VlanId vlanId) {
daniel parkb5817102018-02-15 00:18:51 +0900508 log.info("deriveExternalPeerRouterMac called");
509
510 IpAddress sourceIp = getExternalGatewaySourceIp(externalGateway, router);
511 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
512
513 if (sourceIp == null || targetIp == null) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900514 log.warn("Failed to derive external router mac address because " +
515 "source IP {} or target IP {} is null", sourceIp, targetIp);
daniel parkb5817102018-02-15 00:18:51 +0900516 return;
517 }
518
519 if (externalPeerRouterMap.containsKey(targetIp.toString()) &&
520 !externalPeerRouterMap.get(
Jian Li5e2ad4a2018-07-16 13:40:53 +0900521 targetIp.toString()).value().macAddress().equals(MacAddress.NONE)) {
daniel parkb5817102018-02-15 00:18:51 +0900522 return;
523 }
524
525 MacAddress sourceMac = Constants.DEFAULT_GATEWAY_MAC;
526 Ethernet ethRequest = ARP.buildArpRequest(sourceMac.toBytes(),
527 sourceIp.toOctets(),
528 targetIp.toOctets(),
daniel park576969a2018-03-09 07:07:41 +0900529 vlanId.id());
daniel parkb5817102018-02-15 00:18:51 +0900530
Jian Li5ecfd1a2018-12-10 11:41:03 +0900531 if (osNodeService.completeNodes(GATEWAY).isEmpty()) {
daniel parkb5817102018-02-15 00:18:51 +0900532 log.warn("There's no complete gateway");
533 return;
534 }
Jian Li5ecfd1a2018-12-10 11:41:03 +0900535 OpenstackNode gatewayNode = osNodeService.completeNodes(GATEWAY)
daniel parkb5817102018-02-15 00:18:51 +0900536 .stream()
537 .findFirst()
538 .orElse(null);
539
540 if (gatewayNode == null) {
541 return;
542 }
543
Daniel Park75e3d7f2018-05-29 14:43:53 +0900544 if (gatewayNode.uplinkPortNum() == null) {
daniel parkb5817102018-02-15 00:18:51 +0900545 log.warn("There's no uplink port for gateway node {}", gatewayNode.toString());
546 return;
547 }
548
549 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Daniel Park75e3d7f2018-05-29 14:43:53 +0900550 .setOutput(gatewayNode.uplinkPortNum())
daniel parkb5817102018-02-15 00:18:51 +0900551 .build();
552
553 packetService.emit(new DefaultOutboundPacket(
554 gatewayNode.intgBridge(),
555 treatment,
556 ByteBuffer.wrap(ethRequest.serialize())));
557
Jian Li5e2ad4a2018-07-16 13:40:53 +0900558 externalPeerRouterMap.put(targetIp.toString(),
Jian Lib7873422018-08-18 22:34:39 +0900559 DefaultExternalPeerRouter.builder()
560 .ipAddress(targetIp)
561 .macAddress(MacAddress.NONE)
562 .vlanId(vlanId)
563 .build());
daniel parkb5817102018-02-15 00:18:51 +0900564
Jian Li5ecfd1a2018-12-10 11:41:03 +0900565 log.info("Initializes external peer router map with peer router IP {}",
566 targetIp.toString());
daniel parkb5817102018-02-15 00:18:51 +0900567 }
568
569 @Override
570 public void deleteExternalPeerRouter(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900571 if (externalGateway == null) {
572 return;
573 }
574
daniel parkb5817102018-02-15 00:18:51 +0900575 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
576 if (targetIp == null) {
577 return;
578 }
579
580 if (externalPeerRouterMap.containsKey(targetIp.toString())) {
581 externalPeerRouterMap.remove(targetIp.toString());
582 }
583 }
584
daniel parkeeb8e042018-02-21 14:06:58 +0900585 @Override
586 public void deleteExternalPeerRouter(String ipAddress) {
587 if (ipAddress == null) {
588 return;
589 }
590
591 if (externalPeerRouterMap.containsKey(ipAddress)) {
592 externalPeerRouterMap.remove(ipAddress);
593 }
594
595 }
daniel parkb5817102018-02-15 00:18:51 +0900596
597 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900598 public void updateExternalPeerRouterMac(IpAddress ipAddress,
599 MacAddress macAddress) {
daniel parkb5817102018-02-15 00:18:51 +0900600 try {
601 externalPeerRouterMap.computeIfPresent(ipAddress.toString(), (id, existing) ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900602 DefaultExternalPeerRouter.builder()
603 .ipAddress(ipAddress)
604 .macAddress(macAddress)
605 .vlanId(existing.vlanId())
606 .build());
Jian Lid4066ea2018-06-07 01:44:45 +0900607
608 log.info("Updated external peer router map {}",
609 externalPeerRouterMap.get(ipAddress.toString()).value().toString());
daniel parkb5817102018-02-15 00:18:51 +0900610 } catch (Exception e) {
Jian Li6a47fd02018-11-27 21:51:03 +0900611 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900612 }
daniel parkb5817102018-02-15 00:18:51 +0900613 }
614
daniel parkb5817102018-02-15 00:18:51 +0900615 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900616 public void updateExternalPeerRouter(IpAddress ipAddress,
617 MacAddress macAddress,
618 VlanId vlanId) {
daniel parkb5817102018-02-15 00:18:51 +0900619 try {
620 externalPeerRouterMap.computeIfPresent(ipAddress.toString(), (id, existing) ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900621 DefaultExternalPeerRouter.builder()
622 .ipAddress(ipAddress)
623 .macAddress(macAddress)
624 .vlanId(vlanId)
625 .build());
626
daniel parkb5817102018-02-15 00:18:51 +0900627 } catch (Exception e) {
Jian Li6a47fd02018-11-27 21:51:03 +0900628 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900629 }
630 }
631
632 @Override
633 public MacAddress externalPeerRouterMac(ExternalGateway externalGateway) {
634 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
635
636 if (ipAddress == null) {
637 return null;
638 }
639 if (externalPeerRouterMap.containsKey(ipAddress.toString())) {
Jian Li5e2ad4a2018-07-16 13:40:53 +0900640 return externalPeerRouterMap.get(ipAddress.toString()).value().macAddress();
daniel parkb5817102018-02-15 00:18:51 +0900641 } else {
642 throw new NoSuchElementException();
643 }
644 }
645
646 @Override
647 public void updateExternalPeerRouterVlan(IpAddress ipAddress, VlanId vlanId) {
648
649 try {
daniel park576969a2018-03-09 07:07:41 +0900650 externalPeerRouterMap.computeIfPresent(ipAddress.toString(), (id, existing) ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900651 DefaultExternalPeerRouter.builder()
652 .ipAddress(ipAddress)
653 .macAddress(existing.macAddress())
654 .vlanId(vlanId).build());
daniel park576969a2018-03-09 07:07:41 +0900655
daniel parkb5817102018-02-15 00:18:51 +0900656 } catch (Exception e) {
Jian Li6a47fd02018-11-27 21:51:03 +0900657 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900658 }
659 }
660
661 @Override
662 public Set<ExternalPeerRouter> externalPeerRouters() {
Jian Li78885a22018-03-02 11:33:02 +0900663 return ImmutableSet.copyOf(externalPeerRouterMap.asJavaMap().values());
daniel parkb5817102018-02-15 00:18:51 +0900664 }
Daniel Park577b69c2018-07-16 17:29:34 +0900665
666 @Override
667 public IpPrefix ipPrefix(String portId) {
668 checkNotNull(portId);
669
670 Port port = port(portId);
671
672 checkNotNull(port);
673
674 IpAddress ipAddress = port.getFixedIps().stream()
675 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
676 .findAny().orElse(null);
677
678 checkNotNull(ipAddress);
679
680 Network network = network(port.getNetworkId());
681
682 checkNotNull(network);
683
684 return subnets(network.getId()).stream()
685 .map(s -> IpPrefix.valueOf(s.getCidr()))
686 .filter(prefix -> prefix.contains(ipAddress))
687 .findAny().orElse(null);
688 }
689
690 @Override
SONA Project6bc5c4a2018-12-14 23:49:52 +0900691 public Type networkType(String netId) {
692 OpenstackNetwork network = augmentedNetworkMap.asJavaMap().get(netId);
Daniel Park577b69c2018-07-16 17:29:34 +0900693
694 checkNotNull(network);
695
SONA Project6bc5c4a2018-12-14 23:49:52 +0900696 return network.type();
Daniel Park577b69c2018-07-16 17:29:34 +0900697 }
698
699 @Override
700 public String gatewayIp(String portId) {
701 checkNotNull(portId);
702
703 Port port = port(portId);
704
705 checkNotNull(port);
706
707 IpAddress ipAddress = port.getFixedIps().stream()
708 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
709 .findAny().orElse(null);
710
711 checkNotNull(ipAddress);
712
713 Network network = network(port.getNetworkId());
714
715 checkNotNull(network);
716
717 return subnets(network.getId()).stream()
718 .filter(s -> IpPrefix.valueOf(s.getCidr()).contains(ipAddress))
Jian Lib7873422018-08-18 22:34:39 +0900719 .map(Subnet::getGateway)
Daniel Park577b69c2018-07-16 17:29:34 +0900720 .findAny().orElse(null);
721 }
722
Jian Li0b93b002018-07-31 13:41:08 +0900723 @Override
724 public String segmentId(String netId) {
725 Network network = network(netId);
726
727 checkNotNull(network);
728
729 return network.getProviderSegID();
730 }
731
SONA Project6bc5c4a2018-12-14 23:49:52 +0900732 private OpenstackNetwork buildAugmentedNetworkFromType(Network osNet) {
733 OpenstackNetwork augmentedNetwork = null;
734 if (osNet.getNetworkType() == null) {
735 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), GENEVE);
736 } else {
737 switch (osNet.getNetworkType()) {
738 case FLAT:
739 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), FLAT);
740 break;
741 case VLAN:
742 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), VLAN);
743 break;
744 case VXLAN:
745 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), VXLAN);
746 break;
747 case GRE:
748 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), GRE);
749 break;
750 case LOCAL:
751 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), LOCAL);
752 break;
753 default:
754 break;
755 }
756 }
757
758 return augmentedNetwork;
759 }
760
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 private boolean isNetworkInUse(String netId) {
762 return !subnets(netId).isEmpty() && !ports(netId).isEmpty();
763 }
764
765 private boolean isSubnetInUse(String subnetId) {
766 // TODO add something if needed
767 return false;
768 }
769
770 private boolean isPortInUse(String portId) {
771 // TODO add something if needed
772 return false;
773 }
774
775 private class InternalNetworkStoreDelegate implements OpenstackNetworkStoreDelegate {
776
777 @Override
778 public void notify(OpenstackNetworkEvent event) {
779 if (event != null) {
Jian Li78885a22018-03-02 11:33:02 +0900780 log.trace("send openstack switching event {}", event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900781 process(event);
782 }
783 }
784 }
daniel park576969a2018-03-09 07:07:41 +0900785
Jian Li5ecfd1a2018-12-10 11:41:03 +0900786 private IpAddress getExternalGatewaySourceIp(ExternalGateway externalGateway,
787 Router router) {
daniel park576969a2018-03-09 07:07:41 +0900788 Port exGatewayPort = ports(externalGateway.getNetworkId())
789 .stream()
790 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
791 .findAny().orElse(null);
792 if (exGatewayPort == null) {
793 log.warn("no external gateway port for router({})", router.getName());
794 return null;
795 }
796
797 IP ipAddress = exGatewayPort.getFixedIps().stream().findFirst().orElse(null);
798
799 return ipAddress == null ? null : IpAddress.valueOf(ipAddress.getIpAddress());
800 }
801
802 private IpAddress getExternalPeerRouterIp(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900803 if (externalGateway == null) {
804 return null;
805 }
daniel park576969a2018-03-09 07:07:41 +0900806 Optional<Subnet> externalSubnet = subnets(externalGateway.getNetworkId())
807 .stream()
808 .findFirst();
809
Jian Li5ecfd1a2018-12-10 11:41:03 +0900810 return externalSubnet.map(subnet ->
811 IpAddress.valueOf(subnet.getGateway())).orElse(null);
daniel park576969a2018-03-09 07:07:41 +0900812 }
Jian Lib7873422018-08-18 22:34:39 +0900813}