2 * Copyright (c) 2016 Cisco Systems. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.routing;
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
16 import javax.annotation.Nonnull;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.RoutingCommand;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
24 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHopBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.SubnetAugmentRenderer;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.has.subnet.subnet.Gateways;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.has.subnet.subnet.gateways.Prefixes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.RendererForwardingByTenant;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.forwarding.renderer.forwarding.by.tenant.RendererNetworkDomain;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.renderers.renderer.renderer.nodes.renderer.node.PhysicalInterface;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 import com.google.common.base.Optional;
44 import com.google.common.base.Strings;
46 public class RoutingManager {
47 private static final Logger LOG = LoggerFactory.getLogger(RoutingManager.class);
49 private static final long DEFAULT_TABLE = 0L;
51 private final DataBroker dataBroker;
52 private final MountedDataBrokerProvider mountDataProvider;
54 public RoutingManager(DataBroker dataBroker, MountedDataBrokerProvider mountDataProvider) {
55 this.dataBroker = dataBroker;
56 this.mountDataProvider = mountDataProvider;
59 public Map<InstanceIdentifier<Node>, RoutingCommand> createRouting(
60 @Nonnull RendererForwardingByTenant forwardingByTenant, List<InstanceIdentifier<PhysicalInterface>> physIntIids,
61 General.Operations operation) {
63 Map<InstanceIdentifier<Node>, RoutingCommand> routingCommands = new HashMap<>();
65 getExternalGateways(forwardingByTenant.getRendererNetworkDomain()).forEach((gateways, virtualRouterIp) -> {
66 LOG.trace("Creating routing for Tenant {}, gateway {}, virtualRouterIp {}.",
67 forwardingByTenant.getTenantId(), gateways, virtualRouterIp);
68 List<Route> ipv4Routes = new ArrayList<>();
69 PhysicalInterface outboundInterface = resolveOutboundInterface(virtualRouterIp, physIntIids);
70 InstanceIdentifier<Node> node = resolveOutboundNode(virtualRouterIp, physIntIids);
72 String outboundIntName = outboundInterface != null ? outboundInterface.getInterfaceName() : null;
74 if (Strings.isNullOrEmpty(outboundIntName)) {
75 LOG.trace("Route skipped, no physical interface for gateway found {} in interfaces {}", gateways,
79 IpAddress externalGwIp = gateways.getGateway();
80 for (Prefixes prefixes : gateways.getPrefixes()) {
82 Route ipv4Route = buildIpv4Route(outboundIntName, routeIndex, externalGwIp, prefixes);
83 //todo add support for ipv6
84 LOG.trace("Adding new route {}.", ipv4Route);
85 ipv4Routes.add(ipv4Route);
89 if (!ipv4Routes.isEmpty()) {
90 RoutingCommand command = routingCommands.put(node, new RoutingCommand.RoutingCommandBuilder()
91 .setOperation(operation)
92 .setRouterProtocol(RoutingCommand.DEFAULT_ROUTING_PROTOCOL)
93 .setRoutes(ipv4Routes)
94 //todo in multi-tenant environment we need to use different vrfID for each tenant
95 .setVrfId(DEFAULT_TABLE)
97 LOG.trace("Creating of routing successful, routing command: {}.", command);
101 return routingCommands;
104 private Route buildIpv4Route(String outboundIntName, Long routeIndex, IpAddress externalGwIp, Prefixes prefixes) {
105 return new RouteBuilder().setId(routeIndex)
106 .setDestinationPrefix(new Ipv4Prefix(prefixes.getPrefix().getIpv4Prefix()))
107 .setNextHopOptions(new SimpleNextHopBuilder().setNextHop(new Ipv4Address(externalGwIp.getIpv4Address()))
108 .setOutgoingInterface(outboundIntName)
114 * Used to extract external gateways from network domains if they contain any gateways
115 * @param rendererNetworkDomain list of network domains from which we extract external gateways
116 * @return map of extracted gateways by virtual router IP from network domain list.
118 private Map<Gateways, IpAddress> getExternalGateways(List<RendererNetworkDomain> rendererNetworkDomain){
119 Map<Gateways, IpAddress> gateways = new HashMap<>();
120 for (RendererNetworkDomain domain : rendererNetworkDomain) {
121 SubnetAugmentRenderer subnet = domain.getAugmentation(SubnetAugmentRenderer.class);
122 IpAddress virtualRouterIp = subnet.getSubnet().getVirtualRouterIp();
123 if (virtualRouterIp == null){
126 List<Gateways> gatewaysList = subnet.getSubnet().getGateways();
127 if (gatewaysList != null) {
128 for (Gateways gateway : gatewaysList) {
129 gateways.put(gateway, virtualRouterIp);
130 LOG.trace("Found external Gateway {}", gateway);
137 private PhysicalInterface resolveOutboundInterface(@Nonnull IpAddress extIfaceIp,
138 List<InstanceIdentifier<PhysicalInterface>> physIntIids) {
139 LOG.trace("Resolving External interface {} from interfaces {}.", extIfaceIp, physIntIids);
140 for (InstanceIdentifier<PhysicalInterface> identifier : physIntIids) {
141 Optional<PhysicalInterface> physicalInterfaceOptional = DataStoreHelper.readFromDs(
142 LogicalDatastoreType.OPERATIONAL, identifier, dataBroker.newReadOnlyTransaction());
143 if (!physicalInterfaceOptional.isPresent()) {
146 if (physicalInterfaceOptional.get().isExternal()) {
147 return physicalInterfaceOptional.get();
149 if (physicalInterfaceOptional.get().getAddress().contains(extIfaceIp)){
150 return physicalInterfaceOptional.get();
156 private InstanceIdentifier<Node> resolveOutboundNode(@Nonnull IpAddress extIfaceIp,
157 List<InstanceIdentifier<PhysicalInterface>> physIntIids) {
158 for (InstanceIdentifier<PhysicalInterface> identifier : physIntIids) {
159 Optional<PhysicalInterface> physicalInterfaceOptional = DataStoreHelper.readFromDs(
160 LogicalDatastoreType.OPERATIONAL, identifier, dataBroker.newReadOnlyTransaction());
161 if (!physicalInterfaceOptional.isPresent()){
164 if (physicalInterfaceOptional.get().isExternal()) {
165 return (InstanceIdentifier<Node>) identifier.firstKeyOf(RendererNode.class).getNodePath();
167 if (physicalInterfaceOptional.get().getAddress().contains(extIfaceIp)){
168 return (InstanceIdentifier<Node>) identifier.firstKeyOf(RendererNode.class).getNodePath();
174 public boolean submitRouting(@Nonnull RoutingCommand routing, InstanceIdentifier<Node> nodeIid) {
175 if (nodeIid == null) {
176 LOG.info("NodeId is null Cannot create routing. RoutingCommand: {}", routing);
179 LOG.trace("Submitting routing for routing command: {}, nodeId: {}", routing, nodeIid);
181 Optional<DataBroker> mountPointDataBroker = mountDataProvider.resolveDataBrokerForMountPoint(nodeIid);
182 if (mountPointDataBroker.isPresent()) {
183 throw new IllegalStateException("Cannot find data broker for mount point " + nodeIid);
185 LOG.info("Routing was created for forwarding. Routing: {}, for node: {}", routing, nodeIid);
186 if (routing.getOperation() == General.Operations.PUT){
187 return GbpNetconfTransaction.netconfSyncedWrite(nodeIid, routing,
188 GbpNetconfTransaction.RETRY_COUNT);
189 } else if (routing.getOperation() == General.Operations.DELETE){
190 return GbpNetconfTransaction.netconfSyncedDelete(nodeIid, routing,
191 GbpNetconfTransaction.RETRY_COUNT);