blob: e7cda54fe6489e1a82ba6d65d4a63571cb837231 [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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
39import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
40import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
41import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
42import org.onosproject.openstacknetworking.api.OpenstackNetworkStore;
43import org.onosproject.openstacknetworking.api.OpenstackNetworkStoreDelegate;
daniel parkb5817102018-02-15 00:18:51 +090044import org.onosproject.openstacknode.api.OpenstackNode;
45import org.onosproject.openstacknode.api.OpenstackNodeService;
46import org.onosproject.store.serializers.KryoNamespaces;
47import org.onosproject.store.service.ConsistentMap;
48import org.onosproject.store.service.Serializer;
49import org.onosproject.store.service.StorageService;
Jian Lie6110b72018-07-06 19:06:36 +090050import org.openstack4j.model.common.IdEntity;
daniel parkb5817102018-02-15 00:18:51 +090051import org.openstack4j.model.network.ExternalGateway;
52import org.openstack4j.model.network.IP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.openstack4j.model.network.Network;
Jian Lie6110b72018-07-06 19:06:36 +090054import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.Port;
daniel parkb5817102018-02-15 00:18:51 +090056import org.openstack4j.model.network.Router;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import org.openstack4j.model.network.Subnet;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070058import org.osgi.service.component.annotations.Activate;
59import org.osgi.service.component.annotations.Component;
60import org.osgi.service.component.annotations.Deactivate;
61import org.osgi.service.component.annotations.Reference;
62import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import org.slf4j.Logger;
64
daniel parkb5817102018-02-15 00:18:51 +090065import java.nio.ByteBuffer;
66import java.util.NoSuchElementException;
Hyunsun Moon44aac662017-02-18 02:07:01 +090067import java.util.Objects;
68import java.util.Optional;
69import java.util.Set;
70import java.util.stream.Collectors;
71
72import static com.google.common.base.Preconditions.checkArgument;
73import static com.google.common.base.Preconditions.checkNotNull;
Jian Li5ecfd1a2018-12-10 11:41:03 +090074import static java.util.Objects.requireNonNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parkc4d06402018-05-28 15:57:37 +090076import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
77import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
Daniel Parkc4d06402018-05-28 15:57:37 +090078import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getIntfNameFromPciAddress;
Daniel Park7e8c4d82018-08-13 23:47:49 +090079import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
Jian Li5ecfd1a2018-12-10 11:41:03 +090080import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import static org.slf4j.LoggerFactory.getLogger;
82
83/**
84 * Provides implementation of administering and interfacing OpenStack network,
85 * subnet, and port.
86 */
daniel parkb5817102018-02-15 00:18:51 +090087
Jian Li5ecfd1a2018-12-10 11:41:03 +090088@Component(
89 immediate = true,
90 service = { OpenstackNetworkAdminService.class, OpenstackNetworkService.class }
91)
Hyunsun Moon44aac662017-02-18 02:07:01 +090092public class OpenstackNetworkManager
93 extends ListenerRegistry<OpenstackNetworkEvent, OpenstackNetworkListener>
94 implements OpenstackNetworkAdminService, OpenstackNetworkService {
95
96 protected final Logger log = getLogger(getClass());
97
98 private static final String MSG_NETWORK = "OpenStack network %s %s";
99 private static final String MSG_SUBNET = "OpenStack subnet %s %s";
100 private static final String MSG_PORT = "OpenStack port %s %s";
101 private static final String MSG_CREATED = "created";
102 private static final String MSG_UPDATED = "updated";
103 private static final String MSG_REMOVED = "removed";
104
Jian Li5ecfd1a2018-12-10 11:41:03 +0900105 private static final String ERR_NULL_NETWORK =
106 "OpenStack network cannot be null";
107 private static final String ERR_NULL_NETWORK_ID =
108 "OpenStack network ID cannot be null";
109 private static final String ERR_NULL_SUBNET =
110 "OpenStack subnet cannot be null";
111 private static final String ERR_NULL_SUBNET_ID =
112 "OpenStack subnet ID cannot be null";
113 private static final String ERR_NULL_SUBNET_NET_ID =
114 "OpenStack subnet network ID cannot be null";
115 private static final String ERR_NULL_SUBNET_CIDR =
116 "OpenStack subnet CIDR cannot be null";
117 private static final String ERR_NULL_PORT =
118 "OpenStack port cannot be null";
119 private static final String ERR_NULL_PORT_ID =
120 "OpenStack port ID cannot be null";
121 private static final String ERR_NULL_PORT_NET_ID =
122 "OpenStack port network ID cannot be null";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
124 private static final String ERR_IN_USE = " still in use";
Daniel Parkc4d06402018-05-28 15:57:37 +0900125
Jian Lie6110b72018-07-06 19:06:36 +0900126 private static final int PREFIX_LENGTH = 32;
127
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130 protected CoreService coreService;
131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900133 protected PacketService packetService;
134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900136 protected DeviceService deviceService;
137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 protected OpenstackNetworkStore osNetworkStore;
140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900142 protected StorageService storageService;
143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900145 protected OpenstackNodeService osNodeService;
146
Jian Li5ecfd1a2018-12-10 11:41:03 +0900147 private final OpenstackNetworkStoreDelegate
148 delegate = new InternalNetworkStoreDelegate();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149
daniel parkb5817102018-02-15 00:18:51 +0900150 private ConsistentMap<String, ExternalPeerRouter> externalPeerRouterMap;
151
Jian Li5ecfd1a2018-12-10 11:41:03 +0900152 private static final KryoNamespace
153 SERIALIZER_EXTERNAL_PEER_ROUTER_MAP = KryoNamespace.newBuilder()
daniel parkb5817102018-02-15 00:18:51 +0900154 .register(KryoNamespaces.API)
155 .register(ExternalPeerRouter.class)
156 .register(DefaultExternalPeerRouter.class)
157 .register(MacAddress.class)
158 .register(IpAddress.class)
159 .register(VlanId.class)
160 .build();
161
162 private ApplicationId appId;
163
164
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 @Activate
166 protected void activate() {
daniel parkb5817102018-02-15 00:18:51 +0900167 appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
168
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 osNetworkStore.setDelegate(delegate);
170 log.info("Started");
daniel parkb5817102018-02-15 00:18:51 +0900171
172 externalPeerRouterMap = storageService.<String, ExternalPeerRouter>consistentMapBuilder()
173 .withSerializer(Serializer.using(SERIALIZER_EXTERNAL_PEER_ROUTER_MAP))
174 .withName("external-routermap")
175 .withApplicationId(appId)
176 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 }
178
179 @Deactivate
180 protected void deactivate() {
181 osNetworkStore.unsetDelegate(delegate);
182 log.info("Stopped");
183 }
184
185 @Override
186 public void createNetwork(Network osNet) {
187 checkNotNull(osNet, ERR_NULL_NETWORK);
188 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189
190 osNetworkStore.createNetwork(osNet);
191 log.info(String.format(MSG_NETWORK, osNet.getName(), MSG_CREATED));
192 }
193
194 @Override
195 public void updateNetwork(Network osNet) {
196 checkNotNull(osNet, ERR_NULL_NETWORK);
197 checkArgument(!Strings.isNullOrEmpty(osNet.getId()), ERR_NULL_NETWORK_ID);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900198
199 osNetworkStore.updateNetwork(osNet);
200 log.info(String.format(MSG_NETWORK, osNet.getId(), MSG_UPDATED));
201 }
202
203 @Override
204 public void removeNetwork(String netId) {
205 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
206 synchronized (this) {
207 if (isNetworkInUse(netId)) {
208 final String error = String.format(MSG_NETWORK, netId, ERR_IN_USE);
209 throw new IllegalStateException(error);
210 }
211 Network osNet = osNetworkStore.removeNetwork(netId);
212 if (osNet != null) {
213 log.info(String.format(MSG_NETWORK, osNet.getName(), MSG_REMOVED));
214 }
215 }
216 }
217
218 @Override
219 public void createSubnet(Subnet osSubnet) {
220 checkNotNull(osSubnet, ERR_NULL_SUBNET);
221 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
222 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
223 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
224
225 osNetworkStore.createSubnet(osSubnet);
226 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_CREATED));
227 }
228
229 @Override
230 public void updateSubnet(Subnet osSubnet) {
231 checkNotNull(osSubnet, ERR_NULL_SUBNET);
232 checkArgument(!Strings.isNullOrEmpty(osSubnet.getId()), ERR_NULL_SUBNET_ID);
233 checkArgument(!Strings.isNullOrEmpty(osSubnet.getNetworkId()), ERR_NULL_SUBNET_NET_ID);
234 checkArgument(!Strings.isNullOrEmpty(osSubnet.getCidr()), ERR_NULL_SUBNET_CIDR);
235
236 osNetworkStore.updateSubnet(osSubnet);
237 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_UPDATED));
238 }
239
240 @Override
241 public void removeSubnet(String subnetId) {
242 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
243 synchronized (this) {
244 if (isSubnetInUse(subnetId)) {
245 final String error = String.format(MSG_SUBNET, subnetId, ERR_IN_USE);
246 throw new IllegalStateException(error);
247 }
248 Subnet osSubnet = osNetworkStore.removeSubnet(subnetId);
249 if (osSubnet != null) {
250 log.info(String.format(MSG_SUBNET, osSubnet.getCidr(), MSG_REMOVED));
251 }
252 }
253 }
254
255 @Override
256 public void createPort(Port osPort) {
257 checkNotNull(osPort, ERR_NULL_PORT);
258 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
259 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
260
261 osNetworkStore.createPort(osPort);
262 log.info(String.format(MSG_PORT, osPort.getId(), MSG_CREATED));
263 }
264
265 @Override
266 public void updatePort(Port osPort) {
267 checkNotNull(osPort, ERR_NULL_PORT);
268 checkArgument(!Strings.isNullOrEmpty(osPort.getId()), ERR_NULL_PORT_ID);
269 checkArgument(!Strings.isNullOrEmpty(osPort.getNetworkId()), ERR_NULL_PORT_NET_ID);
270
271 osNetworkStore.updatePort(osPort);
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900272 log.info(String.format(MSG_PORT, osPort.getId(), MSG_UPDATED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900273 }
274
275 @Override
276 public void removePort(String portId) {
277 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
278 synchronized (this) {
279 if (isPortInUse(portId)) {
280 final String error = String.format(MSG_PORT, portId, ERR_IN_USE);
281 throw new IllegalStateException(error);
282 }
283 Port osPort = osNetworkStore.removePort(portId);
284 if (osPort != null) {
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900285 log.info(String.format(MSG_PORT, osPort.getId(), MSG_REMOVED));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900286 }
287 }
288 }
289
290 @Override
Hyunsun Moonc7219222017-03-27 11:05:59 +0900291 public void clear() {
292 osNetworkStore.clear();
293 }
294
295 @Override
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 public Network network(String netId) {
297 checkArgument(!Strings.isNullOrEmpty(netId), ERR_NULL_NETWORK_ID);
298 return osNetworkStore.network(netId);
299 }
300
301 @Override
302 public Set<Network> networks() {
303 return osNetworkStore.networks();
304 }
305
306 @Override
307 public Subnet subnet(String subnetId) {
308 checkArgument(!Strings.isNullOrEmpty(subnetId), ERR_NULL_SUBNET_ID);
309 return osNetworkStore.subnet(subnetId);
310 }
311
312 @Override
313 public Set<Subnet> subnets() {
314 return osNetworkStore.subnets();
315 }
316
317 @Override
318 public Set<Subnet> subnets(String netId) {
319 Set<Subnet> osSubnets = osNetworkStore.subnets().stream()
320 .filter(subnet -> Objects.equals(subnet.getNetworkId(), netId))
321 .collect(Collectors.toSet());
322 return ImmutableSet.copyOf(osSubnets);
323 }
324
325 @Override
326 public Port port(String portId) {
327 checkArgument(!Strings.isNullOrEmpty(portId), ERR_NULL_PORT_ID);
328 return osNetworkStore.port(portId);
329 }
330
331 @Override
332 public Port port(org.onosproject.net.Port port) {
333 String portName = port.annotations().value(PORT_NAME);
334 if (Strings.isNullOrEmpty(portName)) {
335 return null;
336 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900337
Daniel Park7e8c4d82018-08-13 23:47:49 +0900338 try {
339 Optional<Port> osPort;
340 switch (vnicType(portName)) {
341 case NORMAL:
342 osPort = osNetworkStore.ports()
343 .stream()
344 .filter(p -> p.getId().contains(portName.substring(3)))
345 .findFirst();
346 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900347 case DIRECT:
348 //Additional prefixes will be added
349 osPort = osNetworkStore.ports()
350 .stream()
Jian Li5ecfd1a2018-12-10 11:41:03 +0900351 .filter(p -> p.getvNicType().equals(DIRECT) &&
352 p.getProfile().get(PCISLOT) != null)
353 .filter(p -> requireNonNull(
354 getIntfNameFromPciAddress(p)).equals(portName))
Daniel Park7e8c4d82018-08-13 23:47:49 +0900355 .findFirst();
356 return osPort.orElse(null);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900357 default:
358 return null;
359 }
360 } catch (IllegalArgumentException e) {
361 log.error("IllegalArgumentException occurred because of {}", e);
Daniel Parkc4d06402018-05-28 15:57:37 +0900362 return null;
363 }
364 }
365
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366 @Override
367 public Set<Port> ports() {
daniel parkb5817102018-02-15 00:18:51 +0900368 return ImmutableSet.copyOf(osNetworkStore.ports());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900369 }
370
371 @Override
372 public Set<Port> ports(String netId) {
373 Set<Port> osPorts = osNetworkStore.ports().stream()
374 .filter(port -> Objects.equals(port.getNetworkId(), netId))
375 .collect(Collectors.toSet());
376 return ImmutableSet.copyOf(osPorts);
377 }
378
daniel parkb5817102018-02-15 00:18:51 +0900379 @Override
Jian Lie6110b72018-07-06 19:06:36 +0900380 public Set<IpPrefix> getFixedIpsByNetworkType(String type) {
381 if (type == null) {
382 return Sets.newHashSet();
383 }
384
385 Set<Network> networks = osNetworkStore.networks();
386 Set<String> networkIds = Sets.newConcurrentHashSet();
387
388 switch (type.toUpperCase()) {
389 case "FLAT" :
390 networkIds = networks.stream()
391 .filter(n -> n.getNetworkType() == NetworkType.FLAT)
392 .map(IdEntity::getId).collect(Collectors.toSet());
393 break;
394 case "VXLAN" :
395 networkIds = networks.stream()
396 .filter(n -> n.getNetworkType() == NetworkType.VXLAN)
397 .map(IdEntity::getId).collect(Collectors.toSet());
398 break;
Jian Li2d68c192018-12-13 15:52:59 +0900399 case "GRE" :
400 networkIds = networks.stream()
401 .filter(n -> n.getNetworkType() == NetworkType.GRE)
402 .map(IdEntity::getId).collect(Collectors.toSet());
403 break;
Jian Lie6110b72018-07-06 19:06:36 +0900404 case "VLAN" :
405 networkIds = networks.stream()
406 .filter(n -> n.getNetworkType() == NetworkType.VLAN)
407 .map(IdEntity::getId).collect(Collectors.toSet());
408 break;
409 default:
410 break;
411 }
412
413 Set<IP> ips = Sets.newConcurrentHashSet();
414 for (String networkId : networkIds) {
415 osNetworkStore.ports()
416 .stream()
417 .filter(p -> p.getNetworkId().equals(networkId))
418 .filter(p -> p.getFixedIps() != null)
419 .forEach(p -> ips.addAll(p.getFixedIps()));
420 }
421
422 return ips.stream().map(ip -> IpPrefix.valueOf(
423 IpAddress.valueOf(ip.getIpAddress()), PREFIX_LENGTH))
424 .collect(Collectors.toSet());
425 }
426
427 @Override
daniel parkb5817102018-02-15 00:18:51 +0900428 public ExternalPeerRouter externalPeerRouter(IpAddress ipAddress) {
429 if (externalPeerRouterMap.containsKey(ipAddress.toString())) {
430 return externalPeerRouterMap.get(ipAddress.toString()).value();
431 }
432 return null;
433 }
434
435 @Override
daniel park576969a2018-03-09 07:07:41 +0900436 public ExternalPeerRouter externalPeerRouter(ExternalGateway externalGateway) {
437 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
438
439 if (ipAddress == null) {
440 return null;
441 }
442
443 if (externalPeerRouterMap.containsKey(ipAddress.toString())) {
444 return externalPeerRouterMap.get(ipAddress.toString()).value();
445 } else {
446 return null;
447 }
448 }
449
450 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900451 public void deriveExternalPeerRouterMac(ExternalGateway externalGateway,
452 Router router, VlanId vlanId) {
daniel parkb5817102018-02-15 00:18:51 +0900453 log.info("deriveExternalPeerRouterMac called");
454
455 IpAddress sourceIp = getExternalGatewaySourceIp(externalGateway, router);
456 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
457
458 if (sourceIp == null || targetIp == null) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900459 log.warn("Failed to derive external router mac address because " +
460 "source IP {} or target IP {} is null", sourceIp, targetIp);
daniel parkb5817102018-02-15 00:18:51 +0900461 return;
462 }
463
464 if (externalPeerRouterMap.containsKey(targetIp.toString()) &&
465 !externalPeerRouterMap.get(
Jian Li5e2ad4a2018-07-16 13:40:53 +0900466 targetIp.toString()).value().macAddress().equals(MacAddress.NONE)) {
daniel parkb5817102018-02-15 00:18:51 +0900467 return;
468 }
469
470 MacAddress sourceMac = Constants.DEFAULT_GATEWAY_MAC;
471 Ethernet ethRequest = ARP.buildArpRequest(sourceMac.toBytes(),
472 sourceIp.toOctets(),
473 targetIp.toOctets(),
daniel park576969a2018-03-09 07:07:41 +0900474 vlanId.id());
daniel parkb5817102018-02-15 00:18:51 +0900475
Jian Li5ecfd1a2018-12-10 11:41:03 +0900476 if (osNodeService.completeNodes(GATEWAY).isEmpty()) {
daniel parkb5817102018-02-15 00:18:51 +0900477 log.warn("There's no complete gateway");
478 return;
479 }
Jian Li5ecfd1a2018-12-10 11:41:03 +0900480 OpenstackNode gatewayNode = osNodeService.completeNodes(GATEWAY)
daniel parkb5817102018-02-15 00:18:51 +0900481 .stream()
482 .findFirst()
483 .orElse(null);
484
485 if (gatewayNode == null) {
486 return;
487 }
488
Daniel Park75e3d7f2018-05-29 14:43:53 +0900489 if (gatewayNode.uplinkPortNum() == null) {
daniel parkb5817102018-02-15 00:18:51 +0900490 log.warn("There's no uplink port for gateway node {}", gatewayNode.toString());
491 return;
492 }
493
494 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Daniel Park75e3d7f2018-05-29 14:43:53 +0900495 .setOutput(gatewayNode.uplinkPortNum())
daniel parkb5817102018-02-15 00:18:51 +0900496 .build();
497
498 packetService.emit(new DefaultOutboundPacket(
499 gatewayNode.intgBridge(),
500 treatment,
501 ByteBuffer.wrap(ethRequest.serialize())));
502
Jian Li5e2ad4a2018-07-16 13:40:53 +0900503 externalPeerRouterMap.put(targetIp.toString(),
Jian Lib7873422018-08-18 22:34:39 +0900504 DefaultExternalPeerRouter.builder()
505 .ipAddress(targetIp)
506 .macAddress(MacAddress.NONE)
507 .vlanId(vlanId)
508 .build());
daniel parkb5817102018-02-15 00:18:51 +0900509
Jian Li5ecfd1a2018-12-10 11:41:03 +0900510 log.info("Initializes external peer router map with peer router IP {}",
511 targetIp.toString());
daniel parkb5817102018-02-15 00:18:51 +0900512 }
513
514 @Override
515 public void deleteExternalPeerRouter(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900516 if (externalGateway == null) {
517 return;
518 }
519
daniel parkb5817102018-02-15 00:18:51 +0900520 IpAddress targetIp = getExternalPeerRouterIp(externalGateway);
521 if (targetIp == null) {
522 return;
523 }
524
525 if (externalPeerRouterMap.containsKey(targetIp.toString())) {
526 externalPeerRouterMap.remove(targetIp.toString());
527 }
528 }
529
daniel parkeeb8e042018-02-21 14:06:58 +0900530 @Override
531 public void deleteExternalPeerRouter(String ipAddress) {
532 if (ipAddress == null) {
533 return;
534 }
535
536 if (externalPeerRouterMap.containsKey(ipAddress)) {
537 externalPeerRouterMap.remove(ipAddress);
538 }
539
540 }
daniel parkb5817102018-02-15 00:18:51 +0900541
542 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900543 public void updateExternalPeerRouterMac(IpAddress ipAddress,
544 MacAddress macAddress) {
daniel parkb5817102018-02-15 00:18:51 +0900545 try {
546 externalPeerRouterMap.computeIfPresent(ipAddress.toString(), (id, existing) ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900547 DefaultExternalPeerRouter.builder()
548 .ipAddress(ipAddress)
549 .macAddress(macAddress)
550 .vlanId(existing.vlanId())
551 .build());
Jian Lid4066ea2018-06-07 01:44:45 +0900552
553 log.info("Updated external peer router map {}",
554 externalPeerRouterMap.get(ipAddress.toString()).value().toString());
daniel parkb5817102018-02-15 00:18:51 +0900555 } catch (Exception e) {
Jian Li6a47fd02018-11-27 21:51:03 +0900556 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900557 }
daniel parkb5817102018-02-15 00:18:51 +0900558 }
559
daniel parkb5817102018-02-15 00:18:51 +0900560 @Override
Jian Li5ecfd1a2018-12-10 11:41:03 +0900561 public void updateExternalPeerRouter(IpAddress ipAddress,
562 MacAddress macAddress,
563 VlanId vlanId) {
daniel parkb5817102018-02-15 00:18:51 +0900564 try {
565 externalPeerRouterMap.computeIfPresent(ipAddress.toString(), (id, existing) ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900566 DefaultExternalPeerRouter.builder()
567 .ipAddress(ipAddress)
568 .macAddress(macAddress)
569 .vlanId(vlanId)
570 .build());
571
daniel parkb5817102018-02-15 00:18:51 +0900572 } catch (Exception e) {
Jian Li6a47fd02018-11-27 21:51:03 +0900573 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900574 }
575 }
576
577 @Override
578 public MacAddress externalPeerRouterMac(ExternalGateway externalGateway) {
579 IpAddress ipAddress = getExternalPeerRouterIp(externalGateway);
580
581 if (ipAddress == null) {
582 return null;
583 }
584 if (externalPeerRouterMap.containsKey(ipAddress.toString())) {
Jian Li5e2ad4a2018-07-16 13:40:53 +0900585 return externalPeerRouterMap.get(ipAddress.toString()).value().macAddress();
daniel parkb5817102018-02-15 00:18:51 +0900586 } else {
587 throw new NoSuchElementException();
588 }
589 }
590
591 @Override
592 public void updateExternalPeerRouterVlan(IpAddress ipAddress, VlanId vlanId) {
593
594 try {
daniel park576969a2018-03-09 07:07:41 +0900595 externalPeerRouterMap.computeIfPresent(ipAddress.toString(), (id, existing) ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900596 DefaultExternalPeerRouter.builder()
597 .ipAddress(ipAddress)
598 .macAddress(existing.macAddress())
599 .vlanId(vlanId).build());
daniel park576969a2018-03-09 07:07:41 +0900600
daniel parkb5817102018-02-15 00:18:51 +0900601 } catch (Exception e) {
Jian Li6a47fd02018-11-27 21:51:03 +0900602 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900603 }
604 }
605
606 @Override
607 public Set<ExternalPeerRouter> externalPeerRouters() {
Jian Li78885a22018-03-02 11:33:02 +0900608 return ImmutableSet.copyOf(externalPeerRouterMap.asJavaMap().values());
daniel parkb5817102018-02-15 00:18:51 +0900609 }
Daniel Park577b69c2018-07-16 17:29:34 +0900610
611 @Override
612 public IpPrefix ipPrefix(String portId) {
613 checkNotNull(portId);
614
615 Port port = port(portId);
616
617 checkNotNull(port);
618
619 IpAddress ipAddress = port.getFixedIps().stream()
620 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
621 .findAny().orElse(null);
622
623 checkNotNull(ipAddress);
624
625 Network network = network(port.getNetworkId());
626
627 checkNotNull(network);
628
629 return subnets(network.getId()).stream()
630 .map(s -> IpPrefix.valueOf(s.getCidr()))
631 .filter(prefix -> prefix.contains(ipAddress))
632 .findAny().orElse(null);
633 }
634
635 @Override
636 public String networkType(String netId) {
637 Network network = network(netId);
638
639 checkNotNull(network);
640
641 return network.getNetworkType().toString();
642 }
643
644 @Override
645 public String gatewayIp(String portId) {
646 checkNotNull(portId);
647
648 Port port = port(portId);
649
650 checkNotNull(port);
651
652 IpAddress ipAddress = port.getFixedIps().stream()
653 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
654 .findAny().orElse(null);
655
656 checkNotNull(ipAddress);
657
658 Network network = network(port.getNetworkId());
659
660 checkNotNull(network);
661
662 return subnets(network.getId()).stream()
663 .filter(s -> IpPrefix.valueOf(s.getCidr()).contains(ipAddress))
Jian Lib7873422018-08-18 22:34:39 +0900664 .map(Subnet::getGateway)
Daniel Park577b69c2018-07-16 17:29:34 +0900665 .findAny().orElse(null);
666 }
667
Jian Li0b93b002018-07-31 13:41:08 +0900668 @Override
669 public String segmentId(String netId) {
670 Network network = network(netId);
671
672 checkNotNull(network);
673
674 return network.getProviderSegID();
675 }
676
Hyunsun Moon44aac662017-02-18 02:07:01 +0900677 private boolean isNetworkInUse(String netId) {
678 return !subnets(netId).isEmpty() && !ports(netId).isEmpty();
679 }
680
681 private boolean isSubnetInUse(String subnetId) {
682 // TODO add something if needed
683 return false;
684 }
685
686 private boolean isPortInUse(String portId) {
687 // TODO add something if needed
688 return false;
689 }
690
691 private class InternalNetworkStoreDelegate implements OpenstackNetworkStoreDelegate {
692
693 @Override
694 public void notify(OpenstackNetworkEvent event) {
695 if (event != null) {
Jian Li78885a22018-03-02 11:33:02 +0900696 log.trace("send openstack switching event {}", event);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900697 process(event);
698 }
699 }
700 }
daniel park576969a2018-03-09 07:07:41 +0900701
Jian Li5ecfd1a2018-12-10 11:41:03 +0900702 private IpAddress getExternalGatewaySourceIp(ExternalGateway externalGateway,
703 Router router) {
daniel park576969a2018-03-09 07:07:41 +0900704 Port exGatewayPort = ports(externalGateway.getNetworkId())
705 .stream()
706 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
707 .findAny().orElse(null);
708 if (exGatewayPort == null) {
709 log.warn("no external gateway port for router({})", router.getName());
710 return null;
711 }
712
713 IP ipAddress = exGatewayPort.getFixedIps().stream().findFirst().orElse(null);
714
715 return ipAddress == null ? null : IpAddress.valueOf(ipAddress.getIpAddress());
716 }
717
718 private IpAddress getExternalPeerRouterIp(ExternalGateway externalGateway) {
Daniel Park613ac372018-06-28 14:30:11 +0900719 if (externalGateway == null) {
720 return null;
721 }
daniel park576969a2018-03-09 07:07:41 +0900722 Optional<Subnet> externalSubnet = subnets(externalGateway.getNetworkId())
723 .stream()
724 .findFirst();
725
Jian Li5ecfd1a2018-12-10 11:41:03 +0900726 return externalSubnet.map(subnet ->
727 IpAddress.valueOf(subnet.getGateway())).orElse(null);
daniel park576969a2018-03-09 07:07:41 +0900728 }
Jian Lib7873422018-08-18 22:34:39 +0900729}