blob: c79f12c3df0070787c04ed673252a71be76ac013 [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";
Jian Lie6e609f2019-05-14 17:45:54 +0900135 private static final String ERR_NULL_PEER_ROUTER =
136 "External peer router cannot be null";
137 private static final String ERR_NULL_PEER_ROUTER_IP =
138 "External peer router IP cannot be null";
139 private static final String ERR_NULL_PEER_ROUTER_MAC =
140 "External peer router MAC cannot be null";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141
142 private static final String ERR_IN_USE = " still in use";
Daniel Parkc4d06402018-05-28 15:57:37 +0900143
Jian Lie6110b72018-07-06 19:06:36 +0900144 private static final int PREFIX_LENGTH = 32;
145
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 protected CoreService coreService;
149
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900151 protected PacketService packetService;
152
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900154 protected DeviceService deviceService;
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 protected OpenstackNetworkStore osNetworkStore;
158
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900160 protected StorageService storageService;
161
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900163 protected OpenstackNodeService osNodeService;
164
Jian Li5ecfd1a2018-12-10 11:41:03 +0900165 private final OpenstackNetworkStoreDelegate
166 delegate = new InternalNetworkStoreDelegate();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167
SONA Project6bc5c4a2018-12-14 23:49:52 +0900168 private ConsistentMap<String, OpenstackNetwork> augmentedNetworkMap;
daniel parkb5817102018-02-15 00:18:51 +0900169
Jian Li5ecfd1a2018-12-10 11:41:03 +0900170 private static final KryoNamespace
SONA Project6bc5c4a2018-12-14 23:49:52 +0900171 SERIALIZER_AUGMENTED_NETWORK_MAP = KryoNamespace.newBuilder()
172 .register(KryoNamespaces.API)
173 .register(OpenstackNetwork.Type.class)
174 .register(OpenstackNetwork.class)
175 .register(DefaultOpenstackNetwork.class)
176 .build();
177
daniel parkb5817102018-02-15 00:18:51 +0900178 private ApplicationId appId;
179
Hyunsun Moon44aac662017-02-18 02:07:01 +0900180 @Activate
181 protected void activate() {
daniel parkb5817102018-02-15 00:18:51 +0900182 appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
183
Hyunsun Moon44aac662017-02-18 02:07:01 +0900184 osNetworkStore.setDelegate(delegate);
185 log.info("Started");
daniel parkb5817102018-02-15 00:18:51 +0900186
SONA Project6bc5c4a2018-12-14 23:49:52 +0900187 augmentedNetworkMap = storageService.<String, OpenstackNetwork>consistentMapBuilder()
188 .withSerializer(Serializer.using(SERIALIZER_AUGMENTED_NETWORK_MAP))
189 .withName("augmented-networkmap")
190 .withApplicationId(appId)
191 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900192 }
193
194 @Deactivate
195 protected void deactivate() {
196 osNetworkStore.unsetDelegate(delegate);
197 log.info("Stopped");
198 }
199
200 @Override
201 public void createNetwork(Network osNet) {
202 checkNotNull(osNet, ERR_NULL_NETWORK);
203 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900204
205 osNetworkStore.createNetwork(osNet);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900206
207 OpenstackNetwork finalAugmentedNetwork = buildAugmentedNetworkFromType(osNet);
208 augmentedNetworkMap.compute(osNet.getId(), (id, existing) -> {
209 final String error = osNet.getId() + ERR_DUPLICATE;
210 checkArgument(existing == null, error);
211 return finalAugmentedNetwork;
212 });
213
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 log.info(String.format(MSG_NETWORK, osNet.getName(), MSG_CREATED));
215 }
216
217 @Override
218 public void updateNetwork(Network osNet) {
219 checkNotNull(osNet, ERR_NULL_NETWORK);
220 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900221
222 osNetworkStore.updateNetwork(osNet);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900223
224 OpenstackNetwork finalAugmentedNetwork = buildAugmentedNetworkFromType(osNet);
225 augmentedNetworkMap.compute(osNet.getId(), (id, existing) -> {
226 final String error = osNet.getId() + ERR_NOT_FOUND;
227 checkArgument(existing != null, error);
228 return finalAugmentedNetwork;
229 });
230
Hyunsun Moon44aac662017-02-18 02:07:01 +0900231 log.info(String.format(MSG_NETWORK, osNet.getId(), MSG_UPDATED));
232 }
233
234 @Override
235 public void removeNetwork(String netId) {
236 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
237 synchronized (this) {
238 if (isNetworkInUse(netId)) {
239 final String error = String.format(MSG_NETWORK, netId, ERR_IN_USE);
240 throw new IllegalStateException(error);
241 }
242 Network osNet = osNetworkStore.removeNetwork(netId);
243 if (osNet != null) {
244 log.info(String.format(MSG_NETWORK, osNet.getName(), MSG_REMOVED));
245 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900246
247 Versioned<OpenstackNetwork> augmentedNetwork = augmentedNetworkMap.remove(netId);
248 if (augmentedNetwork != null) {
249 log.info(String.format(MSG_NETWORK_TYPE,
250 augmentedNetwork.value().type(), MSG_REMOVED));
251 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900252 }
253 }
254
255 @Override
256 public void createSubnet(Subnet osSubnet) {
257 checkNotNull(osSubnet, ERR_NULL_SUBNET);
258 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
259 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
260 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
261
262 osNetworkStore.createSubnet(osSubnet);
263 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_CREATED));
264 }
265
266 @Override
267 public void updateSubnet(Subnet osSubnet) {
268 checkNotNull(osSubnet, ERR_NULL_SUBNET);
269 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
270 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
271 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
272
273 osNetworkStore.updateSubnet(osSubnet);
274 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_UPDATED));
275 }
276
277 @Override
278 public void removeSubnet(String subnetId) {
279 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
280 synchronized (this) {
281 if (isSubnetInUse(subnetId)) {
282 final String error = String.format(MSG_SUBNET, subnetId, ERR_IN_USE);
283 throw new IllegalStateException(error);
284 }
285 Subnet osSubnet = osNetworkStore.removeSubnet(subnetId);
286 if (osSubnet != null) {
287 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_REMOVED));
288 }
289 }
290 }
291
292 @Override
293 public void createPort(Port osPort) {
294 checkNotNull(osPort, ERR_NULL_PORT);
295 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
296 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
297
298 osNetworkStore.createPort(osPort);
299 log.info(String.format(MSG_PORT, osPort.getId(), MSG_CREATED));
300 }
301
302 @Override
303 public void updatePort(Port osPort) {
304 checkNotNull(osPort, ERR_NULL_PORT);
305 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
306 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
307
308 osNetworkStore.updatePort(osPort);
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900309 log.info(String.format(MSG_PORT, osPort.getId(), MSG_UPDATED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900310 }
311
312 @Override
313 public void removePort(String portId) {
314 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
315 synchronized (this) {
316 if (isPortInUse(portId)) {
317 final String error = String.format(MSG_PORT, portId, ERR_IN_USE);
318 throw new IllegalStateException(error);
319 }
320 Port osPort = osNetworkStore.removePort(portId);
321 if (osPort != null) {
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900322 log.info(String.format(MSG_PORT, osPort.getId(), MSG_REMOVED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900323 }
324 }
325 }
326
327 @Override
Hyunsun Moonc7219222017-03-27 11:05:59 +0900328 public void clear() {
329 osNetworkStore.clear();
Daniel Park2fe39662019-02-20 16:04:40 +0900330 augmentedNetworkMap.clear();
Hyunsun Moonc7219222017-03-27 11:05:59 +0900331 }
332
333 @Override
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334 public Network network(String netId) {
335 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
336 return osNetworkStore.network(netId);
337 }
338
339 @Override
340 public Set<Network> networks() {
341 return osNetworkStore.networks();
342 }
343
344 @Override
345 public Subnet subnet(String subnetId) {
346 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
347 return osNetworkStore.subnet(subnetId);
348 }
349
350 @Override
351 public Set<Subnet> subnets() {
352 return osNetworkStore.subnets();
353 }
354
355 @Override
356 public Set<Subnet> subnets(String netId) {
357 Set<Subnet> osSubnets = osNetworkStore.subnets().stream()
358 .filter(subnet -> Objects.equals(subnet.getNetworkId(), netId))
359 .collect(Collectors.toSet());
360 return ImmutableSet.copyOf(osSubnets);
361 }
362
363 @Override
364 public Port port(String portId) {
365 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
366 return osNetworkStore.port(portId);
367 }
368
369 @Override
370 public Port port(org.onosproject.net.Port port) {
371 String portName = port.annotations().value(PORT_NAME);
372 if (Strings.isNullOrEmpty(portName)) {
373 return null;
374 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900375
Daniel Park7e8c4d82018-08-13 23:47:49 +0900376 try {
377 Optional<Port> osPort;
378 switch (vnicType(portName)) {
379 case NORMAL:
380 osPort = osNetworkStore.ports()
381 .stream()
382 .filter(p -> p.getId().contains(portName.substring(3)))
383 .findFirst();
384 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900385 case DIRECT:
386 //Additional prefixes will be added
387 osPort = osNetworkStore.ports()
388 .stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900389 .filter(p -> p.getvNicType().equals(DIRECT) &&
390 p.getProfile().get(PCISLOT) != null)
391 .filter(p -> requireNonNull(
392 getIntfNameFromPciAddress(p)).equals(portName))
Daniel Park7e8c4d82018-08-13 23:47:49 +0900393 .findFirst();
394 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900395 default:
396 return null;
397 }
398 } catch (IllegalArgumentException e) {
399 log.error("IllegalArgumentException occurred because of {}", e);
Daniel Parkc4d06402018-05-28 15:57:37 +0900400 return null;
401 }
402 }
403
Hyunsun Moon44aac662017-02-18 02:07:01 +0900404 @Override
405 public Set<Port> ports() {
daniel parkb5817102018-02-15 00:18:51 +0900406 return ImmutableSet.copyOf(osNetworkStore.ports());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900407 }
408
409 @Override
410 public Set<Port> ports(String netId) {
411 Set<Port> osPorts = osNetworkStore.ports().stream()
412 .filter(port -> Objects.equals(port.getNetworkId(), netId))
413 .collect(Collectors.toSet());
414 return ImmutableSet.copyOf(osPorts);
415 }
416
daniel parkb5817102018-02-15 00:18:51 +0900417 @Override
Jian Lie6110b72018-07-06 19:06:36 +0900418 public Set<IpPrefix> getFixedIpsByNetworkType(String type) {
419 if (type == null) {
420 return Sets.newHashSet();
421 }
422
Jian Lie6110b72018-07-06 19:06:36 +0900423 Set<String> networkIds = Sets.newConcurrentHashSet();
424
425 switch (type.toUpperCase()) {
Jian Li621f73c2018-12-15 01:49:22 +0900426 case Constants.FLAT :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900427 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
428 .filter(e -> e.getValue().type() == FLAT)
429 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900430 break;
Jian Li621f73c2018-12-15 01:49:22 +0900431 case Constants.VXLAN :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900432 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
Jian Li621f73c2018-12-15 01:49:22 +0900433 .filter(e -> e.getValue().type() == VXLAN)
SONA Project6bc5c4a2018-12-14 23:49:52 +0900434 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900435 break;
Jian Li621f73c2018-12-15 01:49:22 +0900436 case Constants.GRE :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900437 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
Jian Li621f73c2018-12-15 01:49:22 +0900438 .filter(e -> e.getValue().type() == GRE)
SONA Project6bc5c4a2018-12-14 23:49:52 +0900439 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Li2d68c192018-12-13 15:52:59 +0900440 break;
Jian Li621f73c2018-12-15 01:49:22 +0900441 case Constants.VLAN :
SONA Project6bc5c4a2018-12-14 23:49:52 +0900442 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
443 .filter(e -> e.getValue().type() == VLAN)
444 .map(Map.Entry::getKey).collect(Collectors.toSet());
Jian Lie6110b72018-07-06 19:06:36 +0900445 break;
Jian Li621f73c2018-12-15 01:49:22 +0900446 case Constants.GENEVE :
447 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
448 .filter(e -> e.getValue().type() == GENEVE)
449 .map(Map.Entry::getKey).collect(Collectors.toSet());
450 break;
Jian Lie6110b72018-07-06 19:06:36 +0900451 default:
452 break;
453 }
454
455 Set<IP> ips = Sets.newConcurrentHashSet();
456 for (String networkId : networkIds) {
457 osNetworkStore.ports()
458 .stream()
459 .filter(p -> p.getNetworkId().equals(networkId))
460 .filter(p -> p.getFixedIps() != null)
461 .forEach(p -> ips.addAll(p.getFixedIps()));
462 }
463
464 return ips.stream().map(ip -> IpPrefix.valueOf(
465 IpAddress.valueOf(ip.getIpAddress()), PREFIX_LENGTH))
466 .collect(Collectors.toSet());
467 }
468
469 @Override
daniel parkb5817102018-02-15 00:18:51 +0900470 public ExternalPeerRouter externalPeerRouter(IpAddress ipAddress) {
Jian Lie6e609f2019-05-14 17:45:54 +0900471 return osNetworkStore.externalPeerRouter(ipAddress.toString());
daniel parkb5817102018-02-15 00:18:51 +0900472 }
473
474 @Override
daniel park576969a2018-03-09 07:07:41 +0900475 public ExternalPeerRouter externalPeerRouter(ExternalGateway externalGateway) {
476 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
477
478 if (ipAddress == null) {
479 return null;
480 }
481
Jian Lie6e609f2019-05-14 17:45:54 +0900482 return externalPeerRouter(ipAddress);
daniel park576969a2018-03-09 07:07:41 +0900483 }
484
485 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900486 public void deriveExternalPeerRouterMac(ExternalGateway externalGateway,
487 Router router, VlanId vlanId) {
daniel parkb5817102018-02-15 00:18:51 +0900488 log.info("deriveExternalPeerRouterMac called");
489
490 IpAddress sourceIp = getExternalGatewaySourceIp(externalGateway, router);
491 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
492
493 if (sourceIp == null || targetIp == null) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900494 log.warn("Failed to derive external router mac address because " +
495 "source IP {} or target IP {} is null", sourceIp, targetIp);
daniel parkb5817102018-02-15 00:18:51 +0900496 return;
497 }
498
Jian Lie6e609f2019-05-14 17:45:54 +0900499 ExternalPeerRouter peerRouter = osNetworkStore.externalPeerRouter(targetIp.toString());
500
501 // if peer router's MAC address is not NONE, we assume that peer router's
502 // MAC address has been derived
503 if (peerRouter != null && !peerRouter.macAddress().equals(MacAddress.NONE)) {
daniel parkb5817102018-02-15 00:18:51 +0900504 return;
505 }
506
507 MacAddress sourceMac = Constants.DEFAULT_GATEWAY_MAC;
508 Ethernet ethRequest = ARP.buildArpRequest(sourceMac.toBytes(),
509 sourceIp.toOctets(),
510 targetIp.toOctets(),
daniel park576969a2018-03-09 07:07:41 +0900511 vlanId.id());
daniel parkb5817102018-02-15 00:18:51 +0900512
Jian Li5ecfd1a2018-12-10 11:41:03 +0900513 if (osNodeService.completeNodes(GATEWAY).isEmpty()) {
daniel parkb5817102018-02-15 00:18:51 +0900514 log.warn("There's no complete gateway");
515 return;
516 }
Jian Li5ecfd1a2018-12-10 11:41:03 +0900517 OpenstackNode gatewayNode = osNodeService.completeNodes(GATEWAY)
daniel parkb5817102018-02-15 00:18:51 +0900518 .stream()
519 .findFirst()
520 .orElse(null);
521
522 if (gatewayNode == null) {
523 return;
524 }
525
Daniel Park75e3d7f2018-05-29 14:43:53 +0900526 if (gatewayNode.uplinkPortNum() == null) {
daniel parkb5817102018-02-15 00:18:51 +0900527 log.warn("There's no uplink port for gateway node {}", gatewayNode.toString());
528 return;
529 }
530
531 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Daniel Park75e3d7f2018-05-29 14:43:53 +0900532 .setOutput(gatewayNode.uplinkPortNum())
daniel parkb5817102018-02-15 00:18:51 +0900533 .build();
534
535 packetService.emit(new DefaultOutboundPacket(
536 gatewayNode.intgBridge(),
537 treatment,
538 ByteBuffer.wrap(ethRequest.serialize())));
539
Jian Lie6e609f2019-05-14 17:45:54 +0900540 ExternalPeerRouter derivedRouter = DefaultExternalPeerRouter.builder()
541 .ipAddress(targetIp)
542 .macAddress(MacAddress.NONE)
543 .vlanId(vlanId)
544 .build();
545 osNetworkStore.createExternalPeerRouter(derivedRouter);
Jian Li5ecfd1a2018-12-10 11:41:03 +0900546 log.info("Initializes external peer router map with peer router IP {}",
547 targetIp.toString());
daniel parkb5817102018-02-15 00:18:51 +0900548 }
549
550 @Override
551 public void deleteExternalPeerRouter(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900552 if (externalGateway == null) {
553 return;
554 }
555
daniel parkb5817102018-02-15 00:18:51 +0900556 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
Jian Lie6e609f2019-05-14 17:45:54 +0900557 deleteExternalPeerRouter(targetIp.toString());
daniel parkb5817102018-02-15 00:18:51 +0900558 }
559
daniel parkeeb8e042018-02-21 14:06:58 +0900560 @Override
561 public void deleteExternalPeerRouter(String ipAddress) {
Jian Lie6e609f2019-05-14 17:45:54 +0900562 osNetworkStore.removeExternalPeerRouter(ipAddress);
daniel parkeeb8e042018-02-21 14:06:58 +0900563 }
daniel parkb5817102018-02-15 00:18:51 +0900564
565 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900566 public void updateExternalPeerRouterMac(IpAddress ipAddress,
567 MacAddress macAddress) {
Jian Lie6e609f2019-05-14 17:45:54 +0900568 updateExternalPeerRouter(ipAddress, macAddress, null);
daniel parkb5817102018-02-15 00:18:51 +0900569 }
570
daniel parkb5817102018-02-15 00:18:51 +0900571 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900572 public void updateExternalPeerRouter(IpAddress ipAddress,
573 MacAddress macAddress,
574 VlanId vlanId) {
Jian Lie6e609f2019-05-14 17:45:54 +0900575 checkNotNull(ipAddress, ERR_NULL_PEER_ROUTER_IP);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900576
Jian Lie6e609f2019-05-14 17:45:54 +0900577 ExternalPeerRouter existingPeerRouter =
578 osNetworkStore.externalPeerRouter(ipAddress.toString());
579
580 if (existingPeerRouter != null) {
581 ExternalPeerRouter.Builder urBuilder = DefaultExternalPeerRouter.builder()
582 .ipAddress(ipAddress);
583
584 if (macAddress == null) {
585 urBuilder.macAddress(existingPeerRouter.macAddress());
586 } else {
587 urBuilder.macAddress(macAddress);
588 }
589
590 if (vlanId == null) {
591 urBuilder.vlanId(existingPeerRouter.vlanId());
592 } else {
593 urBuilder.vlanId(vlanId);
594 }
595 osNetworkStore.updateExternalPeerRouter(urBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900596 }
597 }
598
599 @Override
600 public MacAddress externalPeerRouterMac(ExternalGateway externalGateway) {
601 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
602
603 if (ipAddress == null) {
604 return null;
605 }
Jian Lie6e609f2019-05-14 17:45:54 +0900606
607 ExternalPeerRouter peerRouter =
608 osNetworkStore.externalPeerRouter(ipAddress.toString());
609
610 if (peerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900611 throw new NoSuchElementException();
Jian Lie6e609f2019-05-14 17:45:54 +0900612 } else {
613 return peerRouter.macAddress();
daniel parkb5817102018-02-15 00:18:51 +0900614 }
615 }
616
617 @Override
618 public void updateExternalPeerRouterVlan(IpAddress ipAddress, VlanId vlanId) {
Jian Lie6e609f2019-05-14 17:45:54 +0900619 updateExternalPeerRouter(ipAddress, null, vlanId);
daniel parkb5817102018-02-15 00:18:51 +0900620 }
621
622 @Override
623 public Set<ExternalPeerRouter> externalPeerRouters() {
Jian Lie6e609f2019-05-14 17:45:54 +0900624 return ImmutableSet.copyOf(osNetworkStore.externalPeerRouters());
daniel parkb5817102018-02-15 00:18:51 +0900625 }
Daniel Park577b69c2018-07-16 17:29:34 +0900626
627 @Override
628 public IpPrefix ipPrefix(String portId) {
629 checkNotNull(portId);
630
631 Port port = port(portId);
632
633 checkNotNull(port);
634
635 IpAddress ipAddress = port.getFixedIps().stream()
636 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
637 .findAny().orElse(null);
638
639 checkNotNull(ipAddress);
640
641 Network network = network(port.getNetworkId());
642
643 checkNotNull(network);
644
645 return subnets(network.getId()).stream()
646 .map(s -> IpPrefix.valueOf(s.getCidr()))
647 .filter(prefix -> prefix.contains(ipAddress))
648 .findAny().orElse(null);
649 }
650
651 @Override
SONA Project6bc5c4a2018-12-14 23:49:52 +0900652 public Type networkType(String netId) {
653 OpenstackNetwork network = augmentedNetworkMap.asJavaMap().get(netId);
Daniel Park577b69c2018-07-16 17:29:34 +0900654
655 checkNotNull(network);
656
SONA Project6bc5c4a2018-12-14 23:49:52 +0900657 return network.type();
Daniel Park577b69c2018-07-16 17:29:34 +0900658 }
659
660 @Override
661 public String gatewayIp(String portId) {
662 checkNotNull(portId);
663
664 Port port = port(portId);
665
666 checkNotNull(port);
667
668 IpAddress ipAddress = port.getFixedIps().stream()
669 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
670 .findAny().orElse(null);
671
672 checkNotNull(ipAddress);
673
674 Network network = network(port.getNetworkId());
675
676 checkNotNull(network);
677
678 return subnets(network.getId()).stream()
679 .filter(s -> IpPrefix.valueOf(s.getCidr()).contains(ipAddress))
Jian Lib7873422018-08-18 22:34:39 +0900680 .map(Subnet::getGateway)
Daniel Park577b69c2018-07-16 17:29:34 +0900681 .findAny().orElse(null);
682 }
683
Jian Li0b93b002018-07-31 13:41:08 +0900684 @Override
685 public String segmentId(String netId) {
686 Network network = network(netId);
687
688 checkNotNull(network);
689
690 return network.getProviderSegID();
691 }
692
SONA Project6bc5c4a2018-12-14 23:49:52 +0900693 private OpenstackNetwork buildAugmentedNetworkFromType(Network osNet) {
694 OpenstackNetwork augmentedNetwork = null;
695 if (osNet.getNetworkType() == null) {
696 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), GENEVE);
697 } else {
698 switch (osNet.getNetworkType()) {
699 case FLAT:
700 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), FLAT);
701 break;
702 case VLAN:
703 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), VLAN);
704 break;
705 case VXLAN:
706 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), VXLAN);
707 break;
708 case GRE:
709 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), GRE);
710 break;
711 case LOCAL:
712 augmentedNetwork = new DefaultOpenstackNetwork(osNet.getId(), LOCAL);
713 break;
714 default:
715 break;
716 }
717 }
718
719 return augmentedNetwork;
720 }
721
Hyunsun Moon44aac662017-02-18 02:07:01 +0900722 private boolean isNetworkInUse(String netId) {
723 return !subnets(netId).isEmpty() && !ports(netId).isEmpty();
724 }
725
726 private boolean isSubnetInUse(String subnetId) {
727 // TODO add something if needed
728 return false;
729 }
730
731 private boolean isPortInUse(String portId) {
732 // TODO add something if needed
733 return false;
734 }
735
736 private class InternalNetworkStoreDelegate implements OpenstackNetworkStoreDelegate {
737
738 @Override
739 public void notify(OpenstackNetworkEvent event) {
740 if (event != null) {
Jian Li78885a22018-03-02 11:33:02 +0900741 log.trace("send openstack switching event {}", event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900742 process(event);
743 }
744 }
745 }
daniel park576969a2018-03-09 07:07:41 +0900746
Jian Li5ecfd1a2018-12-10 11:41:03 +0900747 private IpAddress getExternalGatewaySourceIp(ExternalGateway externalGateway,
748 Router router) {
daniel park576969a2018-03-09 07:07:41 +0900749 Port exGatewayPort = ports(externalGateway.getNetworkId())
750 .stream()
751 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
752 .findAny().orElse(null);
753 if (exGatewayPort == null) {
754 log.warn("no external gateway port for router({})", router.getName());
755 return null;
756 }
757
758 IP ipAddress = exGatewayPort.getFixedIps().stream().findFirst().orElse(null);
759
760 return ipAddress == null ? null : IpAddress.valueOf(ipAddress.getIpAddress());
761 }
762
763 private IpAddress getExternalPeerRouterIp(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900764 if (externalGateway == null) {
765 return null;
766 }
daniel park576969a2018-03-09 07:07:41 +0900767 Optional<Subnet> externalSubnet = subnets(externalGateway.getNetworkId())
768 .stream()
769 .findFirst();
770
Jian Li5ecfd1a2018-12-10 11:41:03 +0900771 return externalSubnet.map(subnet ->
772 IpAddress.valueOf(subnet.getGateway())).orElse(null);
daniel park576969a2018-03-09 07:07:41 +0900773 }
Jian Lib7873422018-08-18 22:34:39 +0900774}