Log enhancements and fixes for VPP renderer
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / routing / RoutingManager.java
1 /*
2  * Copyright (c) 2016 Cisco Systems. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.routing;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15
16 import javax.annotation.Nonnull;
17
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;
42
43 import com.google.common.base.Optional;
44 import com.google.common.base.Strings;
45
46 public class RoutingManager {
47     private static final Logger LOG = LoggerFactory.getLogger(RoutingManager.class);
48
49     private static final long DEFAULT_TABLE = 0L;
50
51     private final DataBroker dataBroker;
52     private final MountedDataBrokerProvider mountDataProvider;
53
54     public RoutingManager(DataBroker dataBroker, MountedDataBrokerProvider mountDataProvider) {
55         this.dataBroker = dataBroker;
56         this.mountDataProvider = mountDataProvider;
57     }
58
59     public Map<InstanceIdentifier<Node>, RoutingCommand> createRouting(
60         @Nonnull RendererForwardingByTenant forwardingByTenant, List<InstanceIdentifier<PhysicalInterface>> physIntIids,
61         General.Operations operation) {
62
63         Map<InstanceIdentifier<Node>, RoutingCommand> routingCommands = new HashMap<>();
64
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);
71
72             String outboundIntName = outboundInterface != null ? outboundInterface.getInterfaceName() : null;
73
74             if (Strings.isNullOrEmpty(outboundIntName)) {
75                 LOG.trace("Route skipped, no physical interface for gateway found {} in interfaces {}", gateways,
76                     physIntIids);
77             } else {
78                 Long routeIndex = 0L;
79                 IpAddress externalGwIp = gateways.getGateway();
80                 for (Prefixes prefixes : gateways.getPrefixes()) {
81                     routeIndex++;
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);
86                 }
87             }
88
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)
96                     .build());
97                 LOG.trace("Creating of routing successful, routing command: {}.", command);
98             }
99         });
100
101         return routingCommands;
102     }
103
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)
109                 .build())
110             .build();
111     }
112
113     /**
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.
117      */
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){
124                 continue;
125             }
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);
131                 }
132             }
133         }
134         return gateways;
135     }
136
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()) {
144                 continue;
145             }
146             if (physicalInterfaceOptional.get().isExternal()) {
147                 return physicalInterfaceOptional.get();
148             }
149             if (physicalInterfaceOptional.get().getAddress().contains(extIfaceIp)){
150                 return physicalInterfaceOptional.get();
151             }
152         }
153         return null;
154     }
155
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()){
162                 continue;
163             }
164             if (physicalInterfaceOptional.get().isExternal()) {
165                 return (InstanceIdentifier<Node>) identifier.firstKeyOf(RendererNode.class).getNodePath();
166             }
167             if (physicalInterfaceOptional.get().getAddress().contains(extIfaceIp)){
168                 return (InstanceIdentifier<Node>) identifier.firstKeyOf(RendererNode.class).getNodePath();
169             }
170         }
171         return null;
172     }
173
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);
177             return false;
178         }
179         LOG.trace("Submitting routing for routing command: {}, nodeId: {}", routing, nodeIid);
180
181         Optional<DataBroker> mountPointDataBroker = mountDataProvider.resolveDataBrokerForMountPoint(nodeIid);
182         if (!mountPointDataBroker.isPresent()) {
183             throw new IllegalStateException("Cannot find data broker for mount point " + nodeIid);
184         }
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);
192         }
193         return false;
194     }
195 }