blob: 9aefe126d138d441859b5662bc6532955f1427bd [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;
Jian Li5b22f112020-10-05 22:36:41 +090086import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.deriveResourceName;
Daniel Parkc4d06402018-05-28 15:57:37 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getIntfNameFromPciAddress;
Daniel Park7e8c4d82018-08-13 23:47:49 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
Jian Li5ecfd1a2018-12-10 11:41:03 +090089import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
93 * Provides implementation of administering and interfacing OpenStack network,
94 * subnet, and port.
95 */
daniel parkb5817102018-02-15 00:18:51 +090096
Jian Li5ecfd1a2018-12-10 11:41:03 +090097@Component(
98 immediate = true,
99 service = { OpenstackNetworkAdminService.class, OpenstackNetworkService.class }
100)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101public class OpenstackNetworkManager
102 extends ListenerRegistry<OpenstackNetworkEvent, OpenstackNetworkListener>
103 implements OpenstackNetworkAdminService, OpenstackNetworkService {
104
105 protected final Logger log = getLogger(getClass());
106
107 private static final String MSG_NETWORK = "OpenStack network %s %s";
SONA Project6bc5c4a2018-12-14 23:49:52 +0900108 private static final String MSG_NETWORK_TYPE = "OpenStack network type %s %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109 private static final String MSG_SUBNET = "OpenStack subnet %s %s";
110 private static final String MSG_PORT = "OpenStack port %s %s";
111 private static final String MSG_CREATED = "created";
112 private static final String MSG_UPDATED = "updated";
113 private static final String MSG_REMOVED = "removed";
114
SONA Project6bc5c4a2018-12-14 23:49:52 +0900115 private static final String ERR_NOT_FOUND = " does not exist";
116 private static final String ERR_DUPLICATE = " already exists";
117
Jian Li5ecfd1a2018-12-10 11:41:03 +0900118 private static final String ERR_NULL_NETWORK =
119 "OpenStack network cannot be null";
120 private static final String ERR_NULL_NETWORK_ID =
121 "OpenStack network ID cannot be null";
122 private static final String ERR_NULL_SUBNET =
123 "OpenStack subnet cannot be null";
124 private static final String ERR_NULL_SUBNET_ID =
125 "OpenStack subnet ID cannot be null";
126 private static final String ERR_NULL_SUBNET_NET_ID =
127 "OpenStack subnet network ID cannot be null";
128 private static final String ERR_NULL_SUBNET_CIDR =
129 "OpenStack subnet CIDR cannot be null";
130 private static final String ERR_NULL_PORT =
131 "OpenStack port cannot be null";
132 private static final String ERR_NULL_PORT_ID =
133 "OpenStack port ID cannot be null";
134 private static final String ERR_NULL_PORT_NET_ID =
135 "OpenStack port network ID cannot be null";
Jian Lie6e609f2019-05-14 17:45:54 +0900136 private static final String ERR_NULL_PEER_ROUTER =
137 "External peer router cannot be null";
138 private static final String ERR_NULL_PEER_ROUTER_IP =
139 "External peer router IP cannot be null";
140 private static final String ERR_NULL_PEER_ROUTER_MAC =
141 "External peer router MAC cannot be null";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142
143 private static final String ERR_IN_USE = " still in use";
Daniel Parkc4d06402018-05-28 15:57:37 +0900144
Jian Lie6110b72018-07-06 19:06:36 +0900145 private static final int PREFIX_LENGTH = 32;
146
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 protected CoreService coreService;
150
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900152 protected PacketService packetService;
153
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900155 protected DeviceService deviceService;
156
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700157 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 protected OpenstackNetworkStore osNetworkStore;
159
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900161 protected StorageService storageService;
162
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900164 protected OpenstackNodeService osNodeService;
165
Jian Li5ecfd1a2018-12-10 11:41:03 +0900166 private final OpenstackNetworkStoreDelegate
167 delegate = new InternalNetworkStoreDelegate();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168
SONA Project6bc5c4a2018-12-14 23:49:52 +0900169 private ConsistentMap<String, OpenstackNetwork> augmentedNetworkMap;
daniel parkb5817102018-02-15 00:18:51 +0900170
Jian Li5ecfd1a2018-12-10 11:41:03 +0900171 private static final KryoNamespace
SONA Project6bc5c4a2018-12-14 23:49:52 +0900172 SERIALIZER_AUGMENTED_NETWORK_MAP = KryoNamespace.newBuilder()
173 .register(KryoNamespaces.API)
174 .register(OpenstackNetwork.Type.class)
175 .register(OpenstackNetwork.class)
176 .register(DefaultOpenstackNetwork.class)
177 .build();
178
daniel parkb5817102018-02-15 00:18:51 +0900179 private ApplicationId appId;
180
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 @Activate
182 protected void activate() {
daniel parkb5817102018-02-15 00:18:51 +0900183 appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
184
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 osNetworkStore.setDelegate(delegate);
186 log.info("Started");
daniel parkb5817102018-02-15 00:18:51 +0900187
SONA Project6bc5c4a2018-12-14 23:49:52 +0900188 augmentedNetworkMap = storageService.<String, OpenstackNetwork>consistentMapBuilder()
189 .withSerializer(Serializer.using(SERIALIZER_AUGMENTED_NETWORK_MAP))
190 .withName("augmented-networkmap")
191 .withApplicationId(appId)
192 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 }
194
195 @Deactivate
196 protected void deactivate() {
197 osNetworkStore.unsetDelegate(delegate);
198 log.info("Stopped");
199 }
200
201 @Override
202 public void createNetwork(Network osNet) {
203 checkNotNull(osNet, ERR_NULL_NETWORK);
204 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900205
206 osNetworkStore.createNetwork(osNet);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900207
208 OpenstackNetwork finalAugmentedNetwork = buildAugmentedNetworkFromType(osNet);
209 augmentedNetworkMap.compute(osNet.getId(), (id, existing) -> {
210 final String error = osNet.getId() + ERR_DUPLICATE;
211 checkArgument(existing == null, error);
212 return finalAugmentedNetwork;
213 });
214
Jian Li5b22f112020-10-05 22:36:41 +0900215 log.info(String.format(MSG_NETWORK, deriveResourceName(osNet), MSG_CREATED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216 }
217
218 @Override
219 public void updateNetwork(Network osNet) {
220 checkNotNull(osNet, ERR_NULL_NETWORK);
221 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900222
223 osNetworkStore.updateNetwork(osNet);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900224
225 OpenstackNetwork finalAugmentedNetwork = buildAugmentedNetworkFromType(osNet);
226 augmentedNetworkMap.compute(osNet.getId(), (id, existing) -> {
227 final String error = osNet.getId() + ERR_NOT_FOUND;
228 checkArgument(existing != null, error);
229 return finalAugmentedNetwork;
230 });
231
Hyunsun Moon44aac662017-02-18 02:07:01 +0900232 log.info(String.format(MSG_NETWORK, osNet.getId(), MSG_UPDATED));
233 }
234
235 @Override
236 public void removeNetwork(String netId) {
237 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
238 synchronized (this) {
239 if (isNetworkInUse(netId)) {
240 final String error = String.format(MSG_NETWORK, netId, ERR_IN_USE);
241 throw new IllegalStateException(error);
242 }
243 Network osNet = osNetworkStore.removeNetwork(netId);
244 if (osNet != null) {
Jian Li5b22f112020-10-05 22:36:41 +0900245 log.info(String.format(MSG_NETWORK, deriveResourceName(osNet), MSG_REMOVED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900246 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900247
248 Versioned<OpenstackNetwork> augmentedNetwork = augmentedNetworkMap.remove(netId);
249 if (augmentedNetwork != null) {
250 log.info(String.format(MSG_NETWORK_TYPE,
251 augmentedNetwork.value().type(), MSG_REMOVED));
252 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900253 }
254 }
255
256 @Override
257 public void createSubnet(Subnet osSubnet) {
258 checkNotNull(osSubnet, ERR_NULL_SUBNET);
259 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
260 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
261 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
262
263 osNetworkStore.createSubnet(osSubnet);
264 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_CREATED));
265 }
266
267 @Override
268 public void updateSubnet(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.updateSubnet(osSubnet);
275 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_UPDATED));
276 }
277
278 @Override
279 public void removeSubnet(String subnetId) {
280 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
281 synchronized (this) {
282 if (isSubnetInUse(subnetId)) {
283 final String error = String.format(MSG_SUBNET, subnetId, ERR_IN_USE);
284 throw new IllegalStateException(error);
285 }
286 Subnet osSubnet = osNetworkStore.removeSubnet(subnetId);
287 if (osSubnet != null) {
288 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_REMOVED));
289 }
290 }
291 }
292
293 @Override
294 public void createPort(Port osPort) {
295 checkNotNull(osPort, ERR_NULL_PORT);
296 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
297 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
298
299 osNetworkStore.createPort(osPort);
300 log.info(String.format(MSG_PORT, osPort.getId(), MSG_CREATED));
301 }
302
303 @Override
304 public void updatePort(Port osPort) {
305 checkNotNull(osPort, ERR_NULL_PORT);
306 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
307 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
308
309 osNetworkStore.updatePort(osPort);
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900310 log.info(String.format(MSG_PORT, osPort.getId(), MSG_UPDATED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311 }
312
313 @Override
314 public void removePort(String portId) {
315 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
316 synchronized (this) {
317 if (isPortInUse(portId)) {
318 final String error = String.format(MSG_PORT, portId, ERR_IN_USE);
319 throw new IllegalStateException(error);
320 }
321 Port osPort = osNetworkStore.removePort(portId);
322 if (osPort != null) {
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900323 log.info(String.format(MSG_PORT, osPort.getId(), MSG_REMOVED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324 }
325 }
326 }
327
328 @Override
Hyunsun Moonc7219222017-03-27 11:05:59 +0900329 public void clear() {
330 osNetworkStore.clear();
Daniel Park2fe39662019-02-20 16:04:40 +0900331 augmentedNetworkMap.clear();
Hyunsun Moonc7219222017-03-27 11:05:59 +0900332 }
333
334 @Override
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 public Network network(String netId) {
336 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
337 return osNetworkStore.network(netId);
338 }
339
340 @Override
341 public Set<Network> networks() {
342 return osNetworkStore.networks();
343 }
344
345 @Override
346 public Subnet subnet(String subnetId) {
347 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
348 return osNetworkStore.subnet(subnetId);
349 }
350
351 @Override
352 public Set<Subnet> subnets() {
353 return osNetworkStore.subnets();
354 }
355
356 @Override
357 public Set<Subnet> subnets(String netId) {
358 Set<Subnet> osSubnets = osNetworkStore.subnets().stream()
359 .filter(subnet -> Objects.equals(subnet.getNetworkId(), netId))
360 .collect(Collectors.toSet());
361 return ImmutableSet.copyOf(osSubnets);
362 }
363
364 @Override
365 public Port port(String portId) {
366 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
367 return osNetworkStore.port(portId);
368 }
369
370 @Override
371 public Port port(org.onosproject.net.Port port) {
372 String portName = port.annotations().value(PORT_NAME);
373 if (Strings.isNullOrEmpty(portName)) {
374 return null;
375 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900376
Daniel Park7e8c4d82018-08-13 23:47:49 +0900377 try {
378 Optional<Port> osPort;
379 switch (vnicType(portName)) {
380 case NORMAL:
381 osPort = osNetworkStore.ports()
382 .stream()
383 .filter(p -> p.getId().contains(portName.substring(3)))
384 .findFirst();
385 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900386 case DIRECT:
387 //Additional prefixes will be added
388 osPort = osNetworkStore.ports()
389 .stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900390 .filter(p -> p.getvNicType().equals(DIRECT) &&
391 p.getProfile().get(PCISLOT) != null)
392 .filter(p -> requireNonNull(
393 getIntfNameFromPciAddress(p)).equals(portName))
Daniel Park7e8c4d82018-08-13 23:47:49 +0900394 .findFirst();
395 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900396 default:
397 return null;
398 }
399 } catch (IllegalArgumentException e) {
400 log.error("IllegalArgumentException occurred because of {}", e);
Daniel Parkc4d06402018-05-28 15:57:37 +0900401 return null;
402 }
403 }
404
Hyunsun Moon44aac662017-02-18 02:07:01 +0900405 @Override
406 public Set<Port> ports() {
daniel parkb5817102018-02-15 00:18:51 +0900407 return ImmutableSet.copyOf(osNetworkStore.ports());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900408 }
409
410 @Override
411 public Set<Port> ports(String netId) {
412 Set<Port> osPorts = osNetworkStore.ports().stream()
413 .filter(port -> Objects.equals(port.getNetworkId(), netId))
414 .collect(Collectors.toSet());
415 return ImmutableSet.copyOf(osPorts);
416 }
417
daniel parkb5817102018-02-15 00:18:51 +0900418 @Override
Jian Lie6110b72018-07-06 19:06:36 +0900419 public Set<IpPrefix> getFixedIpsByNetworkType(String type) {
420 if (type == null) {
421 return Sets.newHashSet();
422 }
423
Jian Lie6110b72018-07-06 19:06:36 +0900424 Set<String> networkIds = Sets.newConcurrentHashSet();
425
426 switch (type.toUpperCase()) {
Jian Li621f73c2018-12-15 01:49:22 +0900427 case Constants.FLAT :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900428 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
429 .filter(e -> e.getValue().type() == FLAT)
430 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900431 break;
Jian Li621f73c2018-12-15 01:49:22 +0900432 case Constants.VXLAN :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900433 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
Jian Li621f73c2018-12-15 01:49:22 +0900434 .filter(e -> e.getValue().type() == VXLAN)
SONA Project6bc5c4a2018-12-14 23:49:52 +0900435 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900436 break;
Jian Li621f73c2018-12-15 01:49:22 +0900437 case Constants.GRE :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900438 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
Jian Li621f73c2018-12-15 01:49:22 +0900439 .filter(e -> e.getValue().type() == GRE)
SONA Project6bc5c4a2018-12-14 23:49:52 +0900440 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Li2d68c192018-12-13 15:52:59 +0900441 break;
Jian Li621f73c2018-12-15 01:49:22 +0900442 case Constants.VLAN :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900443 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
444 .filter(e -> e.getValue().type() == VLAN)
445 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900446 break;
Jian Li621f73c2018-12-15 01:49:22 +0900447 case Constants.GENEVE :
448 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
449 .filter(e -> e.getValue().type() == GENEVE)
450 .map(Map.Entry::getKey).collect(Collectors.toSet());
451 break;
Jian Lie6110b72018-07-06 19:06:36 +0900452 default:
453 break;
454 }
455
456 Set<IP> ips = Sets.newConcurrentHashSet();
457 for (String networkId : networkIds) {
458 osNetworkStore.ports()
459 .stream()
460 .filter(p -> p.getNetworkId().equals(networkId))
461 .filter(p -> p.getFixedIps() != null)
462 .forEach(p -> ips.addAll(p.getFixedIps()));
463 }
464
465 return ips.stream().map(ip -> IpPrefix.valueOf(
466 IpAddress.valueOf(ip.getIpAddress()), PREFIX_LENGTH))
467 .collect(Collectors.toSet());
468 }
469
470 @Override
daniel parkb5817102018-02-15 00:18:51 +0900471 public ExternalPeerRouter externalPeerRouter(IpAddress ipAddress) {
Jian Lie6e609f2019-05-14 17:45:54 +0900472 return osNetworkStore.externalPeerRouter(ipAddress.toString());
daniel parkb5817102018-02-15 00:18:51 +0900473 }
474
475 @Override
daniel park576969a2018-03-09 07:07:41 +0900476 public ExternalPeerRouter externalPeerRouter(ExternalGateway externalGateway) {
477 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
478
479 if (ipAddress == null) {
480 return null;
481 }
482
Jian Lie6e609f2019-05-14 17:45:54 +0900483 return externalPeerRouter(ipAddress);
daniel park576969a2018-03-09 07:07:41 +0900484 }
485
486 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900487 public void deriveExternalPeerRouterMac(ExternalGateway externalGateway,
488 Router router, VlanId vlanId) {
daniel parkb5817102018-02-15 00:18:51 +0900489 log.info("deriveExternalPeerRouterMac called");
490
491 IpAddress sourceIp = getExternalGatewaySourceIp(externalGateway, router);
492 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
493
494 if (sourceIp == null || targetIp == null) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900495 log.warn("Failed to derive external router mac address because " +
496 "source IP {} or target IP {} is null", sourceIp, targetIp);
daniel parkb5817102018-02-15 00:18:51 +0900497 return;
498 }
499
Jian Lie6e609f2019-05-14 17:45:54 +0900500 ExternalPeerRouter peerRouter = osNetworkStore.externalPeerRouter(targetIp.toString());
501
502 // if peer router's MAC address is not NONE, we assume that peer router's
503 // MAC address has been derived
504 if (peerRouter != null && !peerRouter.macAddress().equals(MacAddress.NONE)) {
daniel parkb5817102018-02-15 00:18:51 +0900505 return;
506 }
507
508 MacAddress sourceMac = Constants.DEFAULT_GATEWAY_MAC;
509 Ethernet ethRequest = ARP.buildArpRequest(sourceMac.toBytes(),
510 sourceIp.toOctets(),
511 targetIp.toOctets(),
daniel park576969a2018-03-09 07:07:41 +0900512 vlanId.id());
daniel parkb5817102018-02-15 00:18:51 +0900513
Jian Li5ecfd1a2018-12-10 11:41:03 +0900514 if (osNodeService.completeNodes(GATEWAY).isEmpty()) {
daniel parkb5817102018-02-15 00:18:51 +0900515 log.warn("There's no complete gateway");
516 return;
517 }
Jian Li5ecfd1a2018-12-10 11:41:03 +0900518 OpenstackNode gatewayNode = osNodeService.completeNodes(GATEWAY)
daniel parkb5817102018-02-15 00:18:51 +0900519 .stream()
520 .findFirst()
521 .orElse(null);
522
523 if (gatewayNode == null) {
524 return;
525 }
526
Daniel Park75e3d7f2018-05-29 14:43:53 +0900527 if (gatewayNode.uplinkPortNum() == null) {
daniel parkb5817102018-02-15 00:18:51 +0900528 log.warn("There's no uplink port for gateway node {}", gatewayNode.toString());
529 return;
530 }
531
532 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Daniel Park75e3d7f2018-05-29 14:43:53 +0900533 .setOutput(gatewayNode.uplinkPortNum())
daniel parkb5817102018-02-15 00:18:51 +0900534 .build();
535
536 packetService.emit(new DefaultOutboundPacket(
537 gatewayNode.intgBridge(),
538 treatment,
539 ByteBuffer.wrap(ethRequest.serialize())));
540
Jian Lie6e609f2019-05-14 17:45:54 +0900541 ExternalPeerRouter derivedRouter = DefaultExternalPeerRouter.builder()
542 .ipAddress(targetIp)
543 .macAddress(MacAddress.NONE)
544 .vlanId(vlanId)
545 .build();
546 osNetworkStore.createExternalPeerRouter(derivedRouter);
Jian Li5ecfd1a2018-12-10 11:41:03 +0900547 log.info("Initializes external peer router map with peer router IP {}",
548 targetIp.toString());
daniel parkb5817102018-02-15 00:18:51 +0900549 }
550
551 @Override
552 public void deleteExternalPeerRouter(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900553 if (externalGateway == null) {
554 return;
555 }
556
daniel parkb5817102018-02-15 00:18:51 +0900557 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
Jian Lie6e609f2019-05-14 17:45:54 +0900558 deleteExternalPeerRouter(targetIp.toString());
daniel parkb5817102018-02-15 00:18:51 +0900559 }
560
daniel parkeeb8e042018-02-21 14:06:58 +0900561 @Override
562 public void deleteExternalPeerRouter(String ipAddress) {
Jian Lie6e609f2019-05-14 17:45:54 +0900563 osNetworkStore.removeExternalPeerRouter(ipAddress);
daniel parkeeb8e042018-02-21 14:06:58 +0900564 }
daniel parkb5817102018-02-15 00:18:51 +0900565
566 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900567 public void updateExternalPeerRouterMac(IpAddress ipAddress,
568 MacAddress macAddress) {
Jian Lie6e609f2019-05-14 17:45:54 +0900569 updateExternalPeerRouter(ipAddress, macAddress, null);
daniel parkb5817102018-02-15 00:18:51 +0900570 }
571
daniel parkb5817102018-02-15 00:18:51 +0900572 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900573 public void updateExternalPeerRouter(IpAddress ipAddress,
574 MacAddress macAddress,
575 VlanId vlanId) {
Jian Lie6e609f2019-05-14 17:45:54 +0900576 checkNotNull(ipAddress, ERR_NULL_PEER_ROUTER_IP);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900577
Jian Lie6e609f2019-05-14 17:45:54 +0900578 ExternalPeerRouter existingPeerRouter =
579 osNetworkStore.externalPeerRouter(ipAddress.toString());
580
581 if (existingPeerRouter != null) {
582 ExternalPeerRouter.Builder urBuilder = DefaultExternalPeerRouter.builder()
583 .ipAddress(ipAddress);
584
585 if (macAddress == null) {
586 urBuilder.macAddress(existingPeerRouter.macAddress());
587 } else {
588 urBuilder.macAddress(macAddress);
589 }
590
591 if (vlanId == null) {
592 urBuilder.vlanId(existingPeerRouter.vlanId());
593 } else {
594 urBuilder.vlanId(vlanId);
595 }
596 osNetworkStore.updateExternalPeerRouter(urBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900597 }
598 }
599
600 @Override
601 public MacAddress externalPeerRouterMac(ExternalGateway externalGateway) {
602 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
603
604 if (ipAddress == null) {
605 return null;
606 }
Jian Lie6e609f2019-05-14 17:45:54 +0900607
608 ExternalPeerRouter peerRouter =
609 osNetworkStore.externalPeerRouter(ipAddress.toString());
610
611 if (peerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900612 throw new NoSuchElementException();
Jian Lie6e609f2019-05-14 17:45:54 +0900613 } else {
614 return peerRouter.macAddress();
daniel parkb5817102018-02-15 00:18:51 +0900615 }
616 }
617
618 @Override
619 public void updateExternalPeerRouterVlan(IpAddress ipAddress, VlanId vlanId) {
Jian Lie6e609f2019-05-14 17:45:54 +0900620 updateExternalPeerRouter(ipAddress, null, vlanId);
daniel parkb5817102018-02-15 00:18:51 +0900621 }
622
623 @Override
624 public Set<ExternalPeerRouter> externalPeerRouters() {
Jian Lie6e609f2019-05-14 17:45:54 +0900625 return ImmutableSet.copyOf(osNetworkStore.externalPeerRouters());
daniel parkb5817102018-02-15 00:18:51 +0900626 }
Daniel Park577b69c2018-07-16 17:29:34 +0900627
628 @Override
629 public IpPrefix ipPrefix(String portId) {
630 checkNotNull(portId);
631
632 Port port = port(portId);
633
634 checkNotNull(port);
635
636 IpAddress ipAddress = port.getFixedIps().stream()
637 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
638 .findAny().orElse(null);
639
640 checkNotNull(ipAddress);
641
642 Network network = network(port.getNetworkId());
643
644 checkNotNull(network);
645
646 return subnets(network.getId()).stream()
647 .map(s -> IpPrefix.valueOf(s.getCidr()))
648 .filter(prefix -> prefix.contains(ipAddress))
649 .findAny().orElse(null);
650 }
651
652 @Override
SONA Project6bc5c4a2018-12-14 23:49:52 +0900653 public Type networkType(String netId) {
654 OpenstackNetwork network = augmentedNetworkMap.asJavaMap().get(netId);
Daniel Park577b69c2018-07-16 17:29:34 +0900655
656 checkNotNull(network);
657
SONA Project6bc5c4a2018-12-14 23:49:52 +0900658 return network.type();
Daniel Park577b69c2018-07-16 17:29:34 +0900659 }
660
661 @Override
662 public String gatewayIp(String portId) {
663 checkNotNull(portId);
664
665 Port port = port(portId);
666
667 checkNotNull(port);
668
669 IpAddress ipAddress = port.getFixedIps().stream()
670 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
671 .findAny().orElse(null);
672
673 checkNotNull(ipAddress);
674
675 Network network = network(port.getNetworkId());
676
677 checkNotNull(network);
678
679 return subnets(network.getId()).stream()
680 .filter(s -> IpPrefix.valueOf(s.getCidr()).contains(ipAddress))
Jian Lib7873422018-08-18 22:34:39 +0900681 .map(Subnet::getGateway)
Daniel Park577b69c2018-07-16 17:29:34 +0900682 .findAny().orElse(null);
683 }
684
Jian Li0b93b002018-07-31 13:41:08 +0900685 @Override
686 public String segmentId(String netId) {
687 Network network = network(netId);
688
689 checkNotNull(network);
690
691 return network.getProviderSegID();
692 }
693
SONA Project6bc5c4a2018-12-14 23:49:52 +0900694 private OpenstackNetwork buildAugmentedNetworkFromType(Network osNet) {
695 OpenstackNetwork augmentedNetwork = null;
696 if (osNet.getNetworkType() == null) {
697 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), GENEVE);
698 } else {
699 switch (osNet.getNetworkType()) {
700 case FLAT:
701 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), FLAT);
702 break;
703 case VLAN:
704 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), VLAN);
705 break;
706 case VXLAN:
707 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), VXLAN);
708 break;
709 case GRE:
710 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), GRE);
711 break;
712 case LOCAL:
713 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), LOCAL);
714 break;
715 default:
716 break;
717 }
718 }
719
720 return augmentedNetwork;
721 }
722
Hyunsun Moon44aac662017-02-18 02:07:01 +0900723 private boolean isNetworkInUse(String netId) {
724 return !subnets(netId).isEmpty() && !ports(netId).isEmpty();
725 }
726
727 private boolean isSubnetInUse(String subnetId) {
728 // TODO add something if needed
729 return false;
730 }
731
732 private boolean isPortInUse(String portId) {
733 // TODO add something if needed
734 return false;
735 }
736
737 private class InternalNetworkStoreDelegate implements OpenstackNetworkStoreDelegate {
738
739 @Override
740 public void notify(OpenstackNetworkEvent event) {
741 if (event != null) {
Jian Li78885a22018-03-02 11:33:02 +0900742 log.trace("send openstack switching event {}", event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900743 process(event);
744 }
745 }
746 }
daniel park576969a2018-03-09 07:07:41 +0900747
Jian Li5ecfd1a2018-12-10 11:41:03 +0900748 private IpAddress getExternalGatewaySourceIp(ExternalGateway externalGateway,
749 Router router) {
daniel park576969a2018-03-09 07:07:41 +0900750 Port exGatewayPort = ports(externalGateway.getNetworkId())
751 .stream()
752 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
753 .findAny().orElse(null);
754 if (exGatewayPort == null) {
Jian Li5b22f112020-10-05 22:36:41 +0900755 log.warn("no external gateway port for router({})", deriveResourceName(router));
daniel park576969a2018-03-09 07:07:41 +0900756 return null;
757 }
758
759 IP ipAddress = exGatewayPort.getFixedIps().stream().findFirst().orElse(null);
760
761 return ipAddress == null ? null : IpAddress.valueOf(ipAddress.getIpAddress());
762 }
763
764 private IpAddress getExternalPeerRouterIp(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900765 if (externalGateway == null) {
766 return null;
767 }
daniel park576969a2018-03-09 07:07:41 +0900768 Optional<Subnet> externalSubnet = subnets(externalGateway.getNetworkId())
769 .stream()
770 .findFirst();
771
Jian Li5ecfd1a2018-12-10 11:41:03 +0900772 return externalSubnet.map(subnet ->
773 IpAddress.valueOf(subnet.getGateway())).orElse(null);
daniel park576969a2018-03-09 07:07:41 +0900774 }
Jian Lib7873422018-08-18 22:34:39 +0900775}