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 com.google.common.base.Optional;
13 import java.util.HashMap;
14 import java.util.List;
17 import javax.annotation.Nonnull;
19 import org.apache.commons.net.util.SubnetUtils;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.StaticArpCommand;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.HostRelatedInfoContainer;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PhysicalInterfaces;
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.IpAddressUtil;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppEndpointListener;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.routing.RoutingManager;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
33 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
34 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.LispUtil;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
36 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
37 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev170917.VniReference;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.Routing;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.RoutingBuilder;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 public class FlatOverlayManager {
61 private static final Logger LOG = LoggerFactory.getLogger(FlatOverlayManager.class);
63 private ConfigManagerHelper overlayHelper;
64 private DataBroker dataBroker;
66 private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
67 private HostRelatedInfoContainer hostRelatedInfoContainer = HostRelatedInfoContainer.getInstance();
68 // Node ID, VRF ID, route count
69 private Map<String, Map<Long, Long>> vrfsByHostname = new HashMap<>();
71 private StaticRoutingHelper staticRoutingHelper;
72 private VppEndpointListener vppEndpointListener;
74 public FlatOverlayManager(@Nonnull DataBroker dataBroker,
75 @Nonnull MountedDataBrokerProvider mountedDataBrokerProvider,
76 @Nonnull VppEndpointListener vppEndpointListener) {
77 this.overlayHelper = new ConfigManagerHelper();
78 staticRoutingHelper = new StaticRoutingHelper();
79 this.dataBroker = dataBroker;
80 this.vppEndpointListener = vppEndpointListener;
83 public void configureEndpointForFlatOverlay(AddressEndpointWithLocation addressEp) {
84 addStaticRoute(addressEp);
85 addStaticArpAndInfcsToVrf(addressEp);
88 private void addInterfaceInVrf(String hostName, String interfaceName, long vrf) {
89 if (!putVrfInInterface(hostName, interfaceName, vrf)) {
90 LOG.warn("Failed to put interface {} to vrf {}", interfaceName, vrf);
92 LOG.trace("Added interface {} to vrf {}", interfaceName, vrf);
96 private boolean putVrfInInterface(String hostName, String interfaceName, Long vrf) {
97 InstanceIdentifier<Routing> iid = VppIidFactory.getRoutingIid(new InterfaceKey(interfaceName));
98 RoutingBuilder builder = new RoutingBuilder();
99 builder.setIpv4VrfId(vrf);
100 return GbpNetconfTransaction.netconfSyncedWrite(LispUtil.hostnameToIid(hostName), iid,
101 builder.build(), GbpNetconfTransaction.RETRY_COUNT);
104 private void addStaticArpAndInfcsToVrf(AddressEndpointWithLocation addressEp) {
105 if (!addressEp.getAddressType().equals(IpPrefixType.class)) {
108 Map<String, String> intfcsByHostname = resolveIntfcsByHosts(addressEp);
109 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
110 Optional<Config> cfg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
111 VppIidFactory.getVppRendererConfig(), readTx);
113 intfcsByHostname.entrySet().forEach(intfcByHost -> {
114 if (cfg.isPresent() && !cfg.get().getVppEndpoint().isEmpty()) {
115 java.util.Optional<VppEndpoint> foundVpp = cfg.get()
118 .filter(vpp -> vpp.getVppInterfaceName().equals(intfcByHost.getValue()))
120 if (!foundVpp.isPresent()) {
123 Ipv4Address ipv4 = ConfigManagerHelper.getInterfaceIp(addressEp);
124 putStaticArp(intfcByHost.getKey(), new InterfaceKey(intfcByHost.getValue()),
125 new PhysAddress(foundVpp.get().getAddress()), new Ipv4AddressNoZone(ipv4));
126 addInterfaceInVrf(intfcByHost.getKey(), intfcByHost.getValue(),
127 getVni(addressEp.getTenant().getValue()));
132 private boolean putStaticArp(String hostName, InterfaceKey interfaceKey, PhysAddress physAddress,
133 Ipv4AddressNoZone ip) {
134 StaticArpCommand.StaticArpCommandBuilder staticArpCommandBuilder =
135 new StaticArpCommand.StaticArpCommandBuilder();
137 staticArpCommandBuilder.setOperation(General.Operations.PUT);
138 staticArpCommandBuilder.setInterfaceKey(interfaceKey);
139 staticArpCommandBuilder.setIp(ip);
140 staticArpCommandBuilder.setLinkLayerAddress(physAddress);
142 return GbpNetconfTransaction.netconfSyncedWrite(LispUtil.hostnameToIid(hostName),
143 staticArpCommandBuilder.build(), GbpNetconfTransaction.RETRY_COUNT);
146 private void addStaticRoute(AddressEndpointWithLocation addressEp) {
148 Optional<Long> routeId = routeId(addressEp);
149 if(!routeId.isPresent()) {
153 //TODO workaround for interfaces that do not exist anymore
154 List<ChildEndpoint> childs = addressEp.getChildEndpoint();
155 if (childs != null) {
156 for (ChildEndpoint child : childs) {
158 child.getContextId();
159 VppEndpointKey vppEndpointKey = new VppEndpointKey(child.getAddress(), child.getAddressType(),
160 child.getContextId(), child.getContextType());
161 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
162 Optional<VppEndpoint> vppEp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
163 VppIidFactory.getVppRendererConfig().child(VppEndpoint.class, vppEndpointKey), rTx);
165 if (!vppEp.isPresent()) {
166 LOG.warn("Failed to add route for endpoint {}. Interface not created yet.", addressEp);
172 Map<String, String> hostnamesAndIntfcs = resolveIntfcsByHosts(addressEp);
173 long vni = getVni(addressEp.getTenant().getValue());
176 hostnamesAndIntfcs.forEach((hostname, outgoingInterfaceName) -> {
178 Ipv4Address ipWithoutPrefix = ConfigManagerHelper.getInterfaceIp(addressEp);
180 Ipv4Prefix ipv4Prefix = overlayHelper.getInterfaceIpAsPrefix(addressEp);
181 LOG.trace("Adding static route for addressEp: {}", addressEp);
182 addStaticRoute(routeId.get(), hostname, vrf, ipWithoutPrefix, ipv4Prefix, outgoingInterfaceName);
186 public static Map<String,String> resolveIntfcsByHosts(AddressEndpointWithLocation addressEp) {
187 Map<String, String> hostnamesAndIntfcs = new HashMap<>();
188 if (addressEp.getRelativeLocations() != null
189 && addressEp.getRelativeLocations().getExternalLocation() != null) {
190 LOG.trace("deleteStaticRoutingEntry -> addresEp locations: {}",
191 addressEp.getRelativeLocations().getExternalLocation());
192 addressEp.getRelativeLocations().getExternalLocation().forEach(externalLocation -> {
193 Optional<String> interfaceOptional =
194 VppPathMapper.interfacePathToInterfaceName(externalLocation.getExternalNodeConnector());
195 if (interfaceOptional.isPresent()) {
196 hostnamesAndIntfcs.put(
197 externalLocation.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId().getValue(),
198 interfaceOptional.get());
200 LOG.warn("Couldn't resolve interface name for addrEP: {}", addressEp);
203 } else if (addressEp.getAbsoluteLocation() != null && addressEp.getAbsoluteLocation().getLocationType() != null
204 && addressEp.getAbsoluteLocation().getLocationType() instanceof ExternalLocationCase) {
205 ExternalLocationCase externalLocationCase =
206 (ExternalLocationCase) addressEp.getAbsoluteLocation().getLocationType();
207 LOG.trace("deleteStaticRoutingEntry -> addresEp location: {}", externalLocationCase);
208 Optional<String> interfaceOptional =
209 VppPathMapper.interfacePathToInterfaceName(externalLocationCase.getExternalNodeConnector());
210 if (interfaceOptional.isPresent()) {
211 hostnamesAndIntfcs.put(
212 externalLocationCase.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId().getValue(),
213 interfaceOptional.get());
215 LOG.warn("Couldn't resolve interface name for addrEP: {}", addressEp);
218 return hostnamesAndIntfcs;
221 private boolean addStaticRoute(Long routeId, String hostName, long vrfId, Ipv4Address ipWithoutPrefix,
222 Ipv4Prefix ipv4Prefix, String outgoingInterfaceName) {
223 if (vrfsByHostname.get(hostName) == null || !vrfsByHostname.get(hostName).keySet().contains(vrfId)) {
224 if (staticRoutingHelper.addRoutingProtocolForVrf(LispUtil.hostnameToIid(hostName), vrfId)) {
225 addStaticRouteToPublicInterface(hostName, vrfId);
226 countPlusPlus(hostName, vrfId);
229 if (staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(routeId, hostName, vrfId, ipWithoutPrefix,
230 ipv4Prefix, outgoingInterfaceName, null)) {
231 countPlusPlus(hostName, vrfId);
237 private void countPlusPlus(String hostName, Long vrfId) {
238 if (vrfsByHostname.get(hostName) == null || vrfsByHostname.get(hostName).get(vrfId) == null) {
239 HashMap<Long, Long> newEntry = new HashMap<>();
240 newEntry.put(vrfId, 1L);
241 vrfsByHostname.put(hostName, newEntry);
243 Long count = vrfsByHostname.get(hostName).get(vrfId);
244 HashMap<Long, Long> newEntry = new HashMap<>();
245 newEntry.put(vrfId, count + 1);
246 vrfsByHostname.put(hostName, newEntry);
250 private void countMinusMinus(String hostName, Long vrfId) {
251 if (vrfsByHostname.get(hostName) != null && vrfsByHostname.get(hostName).get(vrfId) != null) {
252 Long count = vrfsByHostname.get(hostName).get(vrfId);
253 HashMap<Long, Long> newEntry = new HashMap<>();
254 newEntry.put(vrfId, count - 1);
255 vrfsByHostname.put(hostName, newEntry);
259 private Long getRouteCount(String hostName, Long vrfId) {
260 if (vrfsByHostname.get(hostName) != null && vrfsByHostname.get(hostName).get(vrfId) != null) {
261 return vrfsByHostname.get(hostName).get(vrfId);
266 private void addStaticRouteToPublicInterface(String hostName, long vrfId) {
267 LOG.trace("addStaticRouteToPublicInterface, hostname: {}, vrfId: {}", hostName, vrfId);
268 Ipv4Address physicalInterfaceIp = hostRelatedInfoContainer.getPhysicalInterfaceState(hostName)
269 .getIp(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC)
271 String interfaceName = hostRelatedInfoContainer.getPhysicalInterfaceState(hostName)
272 .getName(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC);
273 if (interfaceName != null && !interfaceName.isEmpty()) {
274 LOG.trace("Adding Public interface route. hostname: {}, VrfId: {}, Ip: {}, Gw: {}, InterfaceName: {}.",
275 hostName, vrfId, physicalInterfaceIp, null, interfaceName);
276 if (!staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(0L, hostName, vrfId, physicalInterfaceIp,
277 IpAddressUtil.toIpV4Prefix(physicalInterfaceIp), interfaceName,
278 new VniReference(RoutingManager.DEFAULT_TABLE))) {
279 LOG.warn("Failed to add route for physical interface in vrf {} compute host {}", vrfId, hostName);
281 LOG.debug("addStaticRouteToPublicInterface -> Added route to public intf ({} via {}) in vrf {} in compute host {}",
282 IpAddressUtil.toIpV4Prefix(physicalInterfaceIp), interfaceName, vrfId, hostName);
287 private Optional<Long> routeId(AddressEndpointWithLocation addressEp) {
288 if (!addressEp.getAddressType().equals(IpPrefixType.class) || !addressEp.getAddress().contains("/")) {
289 return Optional.absent();
291 String ipAddress = addressEp.getAddress().split("/")[0];
292 SubnetUtils subnet = new SubnetUtils(addressEp.getAddress());
293 Long routeId = Integer.toUnsignedLong(subnet.getInfo().asInteger(ipAddress));
294 return Optional.of(routeId);
297 public void deleteStaticRoutingEntry(AddressEndpointWithLocation addressEp) {
299 Optional<Long> routeId = routeId(addressEp);
300 if(!routeId.isPresent()) {
303 long vni = getVni(addressEp.getTenant().getValue());
305 Map<String, String> hostnamesAndIntfcs = resolveIntfcsByHosts(addressEp);
306 LOG.trace("deleteStaticRoutingEntry -> addresEp locations: {}", addressEp);
307 hostnamesAndIntfcs.entrySet().forEach(intfcsByHost -> {
308 LOG.trace("deleteStaticRoutingEntry -> Deleting addresEp: {} for interface: {}, on node: {}",
309 addressEp.getKey(), intfcsByHost.getValue(), intfcsByHost.getKey());
310 Ipv4Address ipWithoutPrefix = ConfigManagerHelper.getInterfaceIp(addressEp);
311 if (!staticRoutingHelper.deleteSingleStaticRouteFromRoutingProtocol(intfcsByHost.getKey(), vrfId,
313 LOG.warn("Failed to delete route ({} via {}) from vrf {} from host{}", ipWithoutPrefix,
314 intfcsByHost.getValue(), vrfId, intfcsByHost);
316 LOG.trace("deletedStaticRoutingEntry -> Deleted addresEp: {} for interface: {}, on node: {}",
317 addressEp.getKey(), intfcsByHost.getValue(), intfcsByHost.getKey());
318 countMinusMinus(intfcsByHost.getKey(), vrfId);
319 if (getRouteCount(intfcsByHost.getKey(), vrfId) <= 1) {
320 LOG.info("deletedStaticRoutingEntry -> Removing route to public int from VRF {}", vrfId);
321 staticRoutingHelper.deleteSingleStaticRouteFromRoutingProtocol(intfcsByHost.getKey(), vrfId, 0L);
322 InstanceIdentifier<RoutingProtocol> protocol =
323 VppIidFactory.getRoutingInstanceIid(StaticRoutingHelper.getRoutingProtocolName(vrfId));
324 if(GbpNetconfTransaction.netconfSyncedDelete(
325 VppIidFactory.getNetconfNodeIid(new NodeId(intfcsByHost.getKey())), protocol,
326 GbpNetconfTransaction.RETRY_COUNT)) {
327 vrfsByHostname.get(intfcsByHost.getKey()).remove(vrfId);
330 LOG.trace("deleteStaticRoutingEntry -> flushPendingVppEndpoint for addresEp: {}", addressEp);
331 hostRelatedInfoContainer.deleteRouteFromIntfc(intfcsByHost.getKey(), intfcsByHost.getValue(),
333 vppEndpointListener.flushPendingVppEndpoint(intfcsByHost.getKey(), intfcsByHost.getValue());
334 LOG.debug("Delete Static Route ({} via {}) from vrf {} from host {}", ipWithoutPrefix,
335 intfcsByHost.getValue(), vrfId, intfcsByHost);
341 public long getVni(String tenantUuid) {
342 long vni = neutronTenantToVniMapper.getVni(tenantUuid);
343 LOG.debug("Debugging: getVni {} = {}", tenantUuid, vni);