2 * Copyright (c) 2017 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.lisp.flat.overlay;
11 import java.util.HashMap;
12 import java.util.List;
15 import javax.annotation.Nonnull;
17 import org.apache.commons.net.util.SubnetUtils;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.StaticArpCommand;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.EndpointHost;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.HostRelatedInfoContainer;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PhysicalInterfaces;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PortInterfaces;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.Constants;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.IpAddressUtil;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppEndpointListener;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.routing.RoutingManager;
33 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
34 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.LispUtil;
36 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
37 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
38 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev170917.VniReference;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.Routing;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.RoutingBuilder;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 import com.google.common.base.Optional;
63 import com.google.common.base.Preconditions;
65 public class FlatOverlayManager {
66 private static final Logger LOG = LoggerFactory.getLogger(FlatOverlayManager.class);
68 private ConfigManagerHelper overlayHelper;
69 private DataBroker dataBroker;
71 private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
72 private HostRelatedInfoContainer hostRelatedInfoContainer = HostRelatedInfoContainer.getInstance();
73 // Node ID, VRF ID, route count
74 private Map<String, Map<Long, Long>> vrfsByHostname = new HashMap<>();
76 private StaticRoutingHelper staticRoutingHelper;
77 private VppEndpointListener vppEndpointListener;
79 public FlatOverlayManager(@Nonnull DataBroker dataBroker,
80 @Nonnull MountedDataBrokerProvider mountedDataBrokerProvider,
81 @Nonnull VppEndpointListener vppEndpointListener) {
82 this.overlayHelper = new ConfigManagerHelper(mountedDataBrokerProvider);
83 staticRoutingHelper = new StaticRoutingHelper();
84 this.dataBroker = dataBroker;
85 this.vppEndpointListener = vppEndpointListener;
88 public void configureEndpointForFlatOverlay(AddressEndpointWithLocation addressEp) {
89 addStaticRoute(addressEp);
90 addStaticArpAndInfcsToVrf(addressEp);
93 private void addInterfaceInVrf(String hostName, String interfaceName, long vrf) {
94 if (hostRelatedInfoContainer.getPortInterfaceStateOfHost(hostName)
95 .isVrfConfiguredForInterface(interfaceName)) {
99 if (!putVrfInInterface(hostName, interfaceName, vrf)) {
100 LOG.warn("Failed to put interface {} to vrf {}", interfaceName, vrf);
102 hostRelatedInfoContainer
103 .getPortInterfaceStateOfHost(hostName)
104 .initializeRoutingContextForInterface(interfaceName, vrf);
105 LOG.debug("Added interface {} to vrf {}", interfaceName, vrf);
109 private boolean putVrfInInterface(String hostName, String interfaceName, Long vrf) {
110 InstanceIdentifier<Routing> iid = VppIidFactory.getRoutingIid(new InterfaceKey(interfaceName));
111 RoutingBuilder builder = new RoutingBuilder();
112 builder.setIpv4VrfId(vrf);
113 return GbpNetconfTransaction.netconfSyncedWrite(LispUtil.HOSTNAME_TO_IID.apply(hostName), iid,
114 builder.build(), GbpNetconfTransaction.RETRY_COUNT);
117 private void addStaticArpAndInfcsToVrf(AddressEndpointWithLocation addressEp) {
118 if (!addressEp.getAddressType().equals(IpPrefixType.class)) {
121 Map<String, String> intfcsByHostname = resolveIntfcsByHosts(addressEp);
122 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
123 Optional<Config> cfg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
124 VppIidFactory.getVppRendererConfig(), readTx);
126 intfcsByHostname.entrySet().forEach(intfcByHost -> {
127 if (cfg.isPresent() && !cfg.get().getVppEndpoint().isEmpty()) {
128 java.util.Optional<VppEndpoint> foundVpp = cfg.get()
131 .filter(vpp -> vpp.getVppInterfaceName().equals(intfcByHost.getValue()))
133 if (!foundVpp.isPresent()) {
136 Ipv4Address ipv4 = ConfigManagerHelper.getInterfaceIp(addressEp);
137 putStaticArp(intfcByHost.getKey(), new InterfaceKey(intfcByHost.getValue()),
138 new PhysAddress(foundVpp.get().getAddress()), new Ipv4AddressNoZone(ipv4));
139 addInterfaceInVrf(intfcByHost.getKey(), intfcByHost.getValue(),
140 getVni(addressEp.getTenant().getValue()));
145 private boolean putStaticArp(String hostName, InterfaceKey interfaceKey, PhysAddress physAddress,
146 Ipv4AddressNoZone ip) {
147 StaticArpCommand.StaticArpCommandBuilder staticArpCommandBuilder =
148 new StaticArpCommand.StaticArpCommandBuilder();
150 staticArpCommandBuilder.setOperation(General.Operations.PUT);
151 staticArpCommandBuilder.setInterfaceKey(interfaceKey);
152 staticArpCommandBuilder.setIp(ip);
153 staticArpCommandBuilder.setLinkLayerAddress(physAddress);
155 return GbpNetconfTransaction.netconfSyncedWrite(LispUtil.HOSTNAME_TO_IID.apply(hostName),
156 staticArpCommandBuilder.build(), GbpNetconfTransaction.RETRY_COUNT);
159 private void addStaticRoute(AddressEndpointWithLocation addressEp) {
161 Optional<Long> routeId = routeId(addressEp);
162 if(!routeId.isPresent()) {
166 //TODO workaround for interfaces that do not exist anymore
167 List<ChildEndpoint> childs = addressEp.getChildEndpoint();
168 if (childs != null) {
169 for (ChildEndpoint child : childs) {
171 child.getContextId();
172 VppEndpointKey vppEndpointKey = new VppEndpointKey(child.getAddress(), child.getAddressType(),
173 child.getContextId(), child.getContextType());
174 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
175 Optional<VppEndpoint> vppEp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
176 VppIidFactory.getVppRendererConfig().child(VppEndpoint.class, vppEndpointKey), rTx);
178 if (!vppEp.isPresent()) {
179 LOG.error("Failed to add route for endpoint {}. Interface not created yet.", addressEp);
185 Map<String, String> hostnamesAndIntfcs = resolveIntfcsByHosts(addressEp);
186 long vni = getVni(addressEp.getTenant().getValue());
189 hostnamesAndIntfcs.forEach((hostname, outgoingInterfaceName) -> {
191 Ipv4Address ipWithoutPrefix = ConfigManagerHelper.getInterfaceIp(addressEp);
193 Ipv4Prefix ipv4Prefix = overlayHelper.getInterfaceIpAsPrefix(addressEp);
194 LOG.trace("Adding static route for addressEp: {}", addressEp);
195 addStaticRoute(routeId.get(), hostname, vrf, ipWithoutPrefix, ipv4Prefix, outgoingInterfaceName);
199 public static Map<String,String> resolveIntfcsByHosts(AddressEndpointWithLocation addressEp) {
200 Map<String, String> hostnamesAndIntfcs = new HashMap<>();
201 if (addressEp.getRelativeLocations() != null
202 && addressEp.getRelativeLocations().getExternalLocation() != null) {
203 LOG.trace("deleteStaticRoutingEntry -> addresEp locations: {}", addressEp.getRelativeLocations().getExternalLocation());
204 addressEp.getRelativeLocations().getExternalLocation().forEach(externalLocation -> {
205 Optional<String> interfaceOptional =
206 VppPathMapper.interfacePathToInterfaceName(externalLocation.getExternalNodeConnector());
207 if (interfaceOptional.isPresent()) {
208 hostnamesAndIntfcs.put(
209 externalLocation.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId().getValue(),
210 interfaceOptional.get());
212 LOG.warn("Couldn't resolve interface name for addrEP: {}", addressEp);
215 } else if (addressEp.getAbsoluteLocation() != null && addressEp.getAbsoluteLocation().getLocationType() != null
216 && addressEp.getAbsoluteLocation().getLocationType() instanceof ExternalLocationCase) {
217 ExternalLocationCase externalLocationCase =
218 (ExternalLocationCase) addressEp.getAbsoluteLocation().getLocationType();
219 LOG.trace("deleteStaticRoutingEntry -> addresEp location: {}", externalLocationCase);
220 Optional<String> interfaceOptional =
221 VppPathMapper.interfacePathToInterfaceName(externalLocationCase.getExternalNodeConnector());
222 if (interfaceOptional.isPresent()) {
223 hostnamesAndIntfcs.put(
224 externalLocationCase.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId().getValue(),
225 interfaceOptional.get());
227 LOG.warn("Couldn't resolve interface name for addrEP: {}", addressEp);
230 return hostnamesAndIntfcs;
233 private boolean addStaticRoute(Long routeId, String hostName, long vrfId, Ipv4Address ipWithoutPrefix,
234 Ipv4Prefix ipv4Prefix, String outgoingInterfaceName) {
235 if (vrfsByHostname.get(hostName) == null || !vrfsByHostname.get(hostName).keySet().contains(vrfId)) {
236 if (staticRoutingHelper.addRoutingProtocolForVrf(LispUtil.HOSTNAME_TO_IID.apply(hostName), vrfId)) {
237 addStaticRouteToPublicInterface(hostName, vrfId);
238 countPlusPlus(hostName, vrfId);
241 if (staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(routeId, hostName, vrfId, ipWithoutPrefix,
242 ipv4Prefix, outgoingInterfaceName, null)) {
243 countPlusPlus(hostName, vrfId);
249 private void countPlusPlus(String hostName, Long vrfId) {
250 if (vrfsByHostname.get(hostName) == null || vrfsByHostname.get(hostName).get(vrfId) == null) {
251 HashMap<Long, Long> newEntry = new HashMap<>();
252 newEntry.put(vrfId, 1L);
253 vrfsByHostname.put(hostName, newEntry);
255 Long count = vrfsByHostname.get(hostName).get(vrfId);
256 HashMap<Long, Long> newEntry = new HashMap<>();
257 newEntry.put(vrfId, count + 1);
258 vrfsByHostname.put(hostName, newEntry);
262 private void countMinusMinus(String hostName, Long vrfId) {
263 if (vrfsByHostname.get(hostName) != null && vrfsByHostname.get(hostName).get(vrfId) != null) {
264 Long count = vrfsByHostname.get(hostName).get(vrfId);
265 HashMap<Long, Long> newEntry = new HashMap<>();
266 newEntry.put(vrfId, count - 1);
267 vrfsByHostname.put(hostName, newEntry);
271 private Long getRouteCount(String hostName, Long vrfId) {
272 if (vrfsByHostname.get(hostName) != null && vrfsByHostname.get(hostName).get(vrfId) != null) {
273 return vrfsByHostname.get(hostName).get(vrfId);
278 private void addStaticRouteToPublicInterface(String hostName, long vrfId) {
279 LOG.trace("addStaticRouteToPublicInterface, hostname: {}, vrfId: {}", hostName, vrfId);
280 Ipv4Address physicalInterfaceIp = hostRelatedInfoContainer.getPhysicalInterfaceState(hostName)
281 .getIp(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC)
283 String interfaceName = hostRelatedInfoContainer.getPhysicalInterfaceState(hostName)
284 .getName(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC);
285 if (interfaceName != null && !interfaceName.isEmpty()) {
286 LOG.trace("Adding Public interface route. hostname: {}, VrfId: {}, Ip: {}, Gw: {}, InterfaceName: {}.",
287 hostName, vrfId, physicalInterfaceIp, null, interfaceName);
288 if (!staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(0L, hostName, vrfId, physicalInterfaceIp,
289 IpAddressUtil.toIpV4Prefix(physicalInterfaceIp), interfaceName,
290 new VniReference(RoutingManager.DEFAULT_TABLE))) {
291 LOG.warn("Failed to add route for physical interface in vrf {} compute host {}", vrfId, hostName);
293 LOG.debug("addStaticRouteToPublicInterface -> Added route to public intf ({} via {}) in vrf {} in compute host {}",
294 IpAddressUtil.toIpV4Prefix(physicalInterfaceIp), interfaceName, vrfId, hostName);
299 private Optional<Long> routeId(AddressEndpointWithLocation addressEp) {
300 if (!addressEp.getAddressType().equals(IpPrefixType.class) || !addressEp.getAddress().contains("/")) {
301 return Optional.absent();
303 String ipAddress = addressEp.getAddress().split("/")[0];
304 SubnetUtils subnet = new SubnetUtils(addressEp.getAddress());
305 Long routeId = Integer.toUnsignedLong(subnet.getInfo().asInteger(ipAddress));
306 return Optional.of(routeId);
309 public void deleteStaticRoutingEntry(AddressEndpointWithLocation addressEp) {
311 Optional<Long> routeId = routeId(addressEp);
312 if(!routeId.isPresent()) {
315 long vni = getVni(addressEp.getTenant().getValue());
317 Map<String, String> hostnamesAndIntfcs = resolveIntfcsByHosts(addressEp);
318 LOG.trace("deleteStaticRoutingEntry -> addresEp locations: {}", addressEp);
319 hostnamesAndIntfcs.entrySet().forEach(intfcsByHost -> {
320 LOG.trace("deleteStaticRoutingEntry -> Deleting addresEp: {} for interface: {}, on node: {}", addressEp.getKey(), intfcsByHost.getValue(), intfcsByHost.getKey());
321 Ipv4Address ipWithoutPrefix = ConfigManagerHelper.getInterfaceIp(addressEp);
322 if (!staticRoutingHelper.deleteSingleStaticRouteFromRoutingProtocol(intfcsByHost.getKey(), vrfId, routeId.get())) {
323 LOG.warn("Failed to delete route ({} via {}) from vrf {} from host{}", ipWithoutPrefix,
324 intfcsByHost.getValue(), vrfId, intfcsByHost);
326 LOG.trace("deletedStaticRoutingEntry -> Deleted addresEp: {} for interface: {}, on node: {}", addressEp.getKey(), intfcsByHost.getValue(), intfcsByHost.getKey());
327 countMinusMinus(intfcsByHost.getKey(), vrfId);
328 if (getRouteCount(intfcsByHost.getKey(), vrfId) <= 1) {
329 LOG.info("deletedStaticRoutingEntry -> Removing route to public int from VRF {}", vrfId);
330 staticRoutingHelper.deleteSingleStaticRouteFromRoutingProtocol(intfcsByHost.getKey(), vrfId, 0L);
331 InstanceIdentifier<RoutingProtocol> protocol =
332 VppIidFactory.getRoutingInstanceIid(StaticRoutingHelper.getRoutingProtocolName(vrfId));
333 if(GbpNetconfTransaction.netconfSyncedDelete(
334 VppIidFactory.getNetconfNodeIid(new NodeId(intfcsByHost.getKey())), protocol,
335 GbpNetconfTransaction.RETRY_COUNT)) {
336 vrfsByHostname.get(intfcsByHost.getKey()).remove(vrfId);
339 LOG.trace("deleteStaticRoutingEntry -> flushPendingVppEndpoint for addresEp: {}", addressEp);
340 hostRelatedInfoContainer.deleteRouteFromIntfc(intfcsByHost.getKey(), intfcsByHost.getValue(), routeId.get());
341 vppEndpointListener.flushPendingVppEndpoint(intfcsByHost.getKey(), intfcsByHost.getValue());
342 LOG.debug("Delete Static Route ({} via {}) from vrf {} from host {}", ipWithoutPrefix,
343 intfcsByHost.getValue(), vrfId, intfcsByHost);
349 public long getVni(String tenantUuid) {
350 long vni = neutronTenantToVniMapper.getVni(tenantUuid);
351 LOG.debug("Debugging: getVni {} = {}", tenantUuid, vni);