From d7b2e8e4b5a7f8daadcd3e8fdaa40967efabd4ae Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Wed, 23 Nov 2016 16:34:33 +0100 Subject: [PATCH] introducing loopback port for VPP adding support for loopback interface in vpp-renderer adding support for loopback VPP router interface in neutron-vpp-mapper Change-Id: Ibd91f8b109468abc16018f3a09d6bb76cd7ce018 Signed-off-by: Michal Cmarada --- .../mapper/mapping/NeutronPortAware.java | 6 +- .../neutron/mapper/util/PortUtils.java | 5 +- .../vpp/mapper/processors/PortHandler.java | 67 ++++- .../vpp/commands/LoopbackCommand.java | 227 ++++++++++++++++ .../renderer/vpp/iface/InterfaceManager.java | 42 ++- .../vpp/policy/ForwardingManager.java | 32 ++- renderers/vpp/src/main/yang/vpp-renderer.yang | 19 ++ .../vpp/commands/LoopbackCommandTest.java | 252 ++++++++++++++++++ .../vpp/policy/ForwardingManagerTest.java | 5 +- 9 files changed, 633 insertions(+), 22 deletions(-) create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommand.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommandTest.java diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java index 4e8886357..454b4dea3 100644 --- a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java +++ b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java @@ -121,7 +121,7 @@ public class NeutronPortAware implements NeutronAware { UniqueId portId = new UniqueId(port.getUuid().getValue()); addBaseEndpointMappings(addrEpKey, portId, rwTx); - // Add Qrouter port as Endpoint + // Add Qrouter and VPProuter port as Endpoint if (port.getAugmentation(PortBindingExtension.class) != null && PortUtils.DEVICE_VIF_TYPE.equals(port.getAugmentation(PortBindingExtension.class).getVifType())) { LOG.trace("Port is QRouter port: {}", port.getUuid().getValue()); @@ -291,14 +291,14 @@ public class NeutronPortAware implements NeutronAware { Set portsInSameSubnet = PortUtils.findPortsBySubnet(subnetUuid, neutron.getPorts()); for (Port portInSameSubnet : portsInSameSubnet) { if (PortUtils.isNormalPort(portInSameSubnet) || PortUtils.isDhcpPort(portInSameSubnet) - || PortUtils.isQrouterPort(portInSameSubnet)) { + || PortUtils.isQrouterOrVppRouterPort(portInSameSubnet)) { // endpoints are created only from neutron normal port or DHCP port Optional firstFixedIps = PortUtils.resolveFirstFixedIps(portInSameSubnet); if (firstFixedIps.isPresent()) { // endpoint has only one network containment therefore only first IP is used FixedIps ipWithSubnet = firstFixedIps.get(); List endpointGroupIds = new ArrayList<>(); - if (PortUtils.isDhcpPort(portInSameSubnet) || PortUtils.isQrouterPort(portInSameSubnet)) { + if (PortUtils.isDhcpPort(portInSameSubnet) || PortUtils.isQrouterOrVppRouterPort(portInSameSubnet)) { endpointGroupIds.add(NetworkService.EPG_ID); } else if (PortUtils.isNormalPort(portInSameSubnet)) { endpointGroupIds.add(NetworkClient.EPG_ID); diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/PortUtils.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/PortUtils.java index 354d7b36e..2e2258767 100644 --- a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/PortUtils.java +++ b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/PortUtils.java @@ -93,10 +93,9 @@ public class PortUtils { return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner()); } - public static boolean isQrouterPort(Port port) { + public static boolean isQrouterOrVppRouterPort(Port port) { return DEVICE_OWNER_ROUTER_IFACE.equals(port.getDeviceOwner()) - && port.getAugmentation(PortBindingExtension.class) != null - && DEVICE_VIF_TYPE.equals(port.getAugmentation(PortBindingExtension.class).getVifType()); + && port.getAugmentation(PortBindingExtension.class) != null; } public static boolean isRouterInterfacePort(Port port) { diff --git a/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java b/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java index decd0567f..560d15566 100644 --- a/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java +++ b/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java @@ -18,6 +18,8 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.SocketInfo; import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId; @@ -30,6 +32,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_render import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCaseBuilder; @@ -37,10 +41,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.P import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; @@ -56,6 +64,8 @@ import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; +import java.util.List; + public class PortHandler implements TransactionChainListener { private static final Logger LOG = LoggerFactory.getLogger(MappingProvider.class); @@ -189,15 +199,59 @@ public class PortHandler implements TransactionChainListener { .setName(createQRouterPortName(port.getUuid())) .build(); vppEpBuilder.setInterfaceTypeChoice(tapCase); + } else if (isValidVppRouterPort(port)) { + vppEpBuilder.setInterfaceTypeChoice(getLoopbackCase(port)); } return vppEpBuilder.build(); } + private LoopbackCase getLoopbackCase(Port port) { + LoopbackCaseBuilder loopbackCase = new LoopbackCaseBuilder() + .setPhysAddress(new PhysAddress(port.getMacAddress().getValue())); + Optional fixedIpsOptional = resolveFirstFixedIps(port); + if(fixedIpsOptional.isPresent() && fixedIpsOptional.get().getIpAddress() != null){ + loopbackCase.setIpAddress(fixedIpsOptional.get().getIpAddress()); + ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction(); + Optional subnetOptional = + DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + InstanceIdentifier.builder(Neutron.class) + .child(Subnets.class) + .child(Subnet.class, new SubnetKey(fixedIpsOptional.get().getSubnetId())) + .build(), rTx); + if (subnetOptional.isPresent()) { + Ipv4Prefix ipv4Prefix = subnetOptional.get().getCidr().getIpv4Prefix(); + loopbackCase.setIpPrefix(new IpPrefix(ipv4Prefix)); + } else { + LOG.warn("IpPrefix for loopback port: {} was not set.", port); + } + if (loopbackCase.getIpAddress() != null && loopbackCase.getIpPrefix() != null) { + loopbackCase.setBvi(true); + LOG.trace("Creating loopback BVI interface: {} for VPP router port: {}.", loopbackCase, port); + } + + } else { + LOG.warn("IpAddress for loopback port: {} was not set.", port); + } + return loopbackCase.build(); + } + /** * If Qrouter (L3 Agent) is in use, any of Openstack neutron routers is not going be mapped * to ODL neutron. */ private boolean isValidQRouterPort(Port port) { + Optional optRouter = getRouterOptional(port); + return !optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) + && port.getMacAddress() != null; + } + + private boolean isValidVppRouterPort(Port port) { + Optional optRouter = getRouterOptional(port); + return optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) + && port.getMacAddress() != null; + } + + private Optional getRouterOptional(Port port) { ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction(); InstanceIdentifier routerIid = InstanceIdentifier.builder(Neutron.class) .child(Routers.class) @@ -205,8 +259,15 @@ public class PortHandler implements TransactionChainListener { .build(); Optional optRouter = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, routerIid, rTx); rTx.close(); - return !optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) - && port.getMacAddress() != null; + return optRouter; + } + + public static Optional resolveFirstFixedIps(Port port) { + List fixedIps = port.getFixedIps(); + if (fixedIps != null && !fixedIps.isEmpty()) { + return Optional.of(fixedIps.get(0)); + } + return Optional.absent(); } private String createPortName(Uuid portUuid) { @@ -277,6 +338,6 @@ public class PortHandler implements TransactionChainListener { @Override public void onTransactionChainSuccessful(TransactionChain chain) { - LOG.trace("Transaction chain was successfull. {}", chain); + LOG.trace("Transaction chain was successful. {}", chain); } } diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommand.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommand.java new file mode 100644 index 000000000..2d8a6a459 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommand.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2016 Cisco Systems. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.commands; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations; +import org.opendaylight.groupbasedpolicy.util.NetUtils; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Loopback; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.LoopbackBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.BridgeBasedBuilder; + +import java.util.Collections; + +public class LoopbackCommand extends AbstractInterfaceCommand { + + private PhysAddress physAddress; + private String bridgeDomain; + private boolean bvi; + private IpAddress ipAddress; + private IpPrefix ipPrefix; + + private LoopbackCommand(LoopbackCommandBuilder builder) { + this.name = builder.getInterfaceName(); + this.operation = builder.getOperation(); + this.physAddress = builder.getPhysAddress(); + this.enabled = builder.isEnabled(); + this.description = builder.getDescription(); + this.bridgeDomain = builder.getBridgeDomain(); + this.bvi = builder.isBvi(); + this.ipAddress = builder.getIpAddress(); + this.ipPrefix = builder.getIpPrefix(); + } + + public static LoopbackCommandBuilder builder() { + return new LoopbackCommandBuilder(); + } + + public PhysAddress getPhysAddress() { + return physAddress; + } + + public String getBridgeDomain() { + return bridgeDomain; + } + + public boolean getBvi() { + return bvi; + } + + public IpAddress getIpAddress() { + return ipAddress; + } + + public IpPrefix getIpPrefix() { + return ipPrefix; + } + + public short getPrefixLength() { + return (short) NetUtils.getMaskFromPrefix(this.ipPrefix.getIpv4Prefix().getValue()); + } + + @Override public InterfaceBuilder getInterfaceBuilder() { + InterfaceBuilder + interfaceBuilder = + new InterfaceBuilder().setKey(new InterfaceKey(name)) + .setEnabled(enabled) + .setDescription(description) + .setType(Loopback.class) + .setName(name) + .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled); + + // Create the Loopback augmentation + VppInterfaceAugmentationBuilder + vppAugmentationBuilder = + new VppInterfaceAugmentationBuilder().setLoopback(new LoopbackBuilder().setMac(this.physAddress).build()); + + if (!Strings.isNullOrEmpty(bridgeDomain)) { + vppAugmentationBuilder.setL2(new L2Builder().setInterconnection( + new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).setBridgedVirtualInterface(bvi).build()) + .build()); + } + Interface1Builder + interface1Builder = + new Interface1Builder().setIpv4(new Ipv4Builder().setAddress(Collections.singletonList( + new AddressBuilder().setIp(new Ipv4AddressNoZone(this.ipAddress.getIpv4Address())) + .setSubnet(new PrefixLengthBuilder().setPrefixLength(this.getPrefixLength()).build()) + .build())).build()); + interfaceBuilder.addAugmentation(Interface1.class, interface1Builder.build()); + interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentationBuilder.build()); + return interfaceBuilder; + } + + @Override public String toString() { + return "LoopPortUserCommand [physAddress=" + physAddress + ", IpAddress=" + ipAddress + ", IpPrefix=" + ipPrefix + + ", bridgeDomain=" + bridgeDomain + ", operations=" + operation + ", name=" + name + ", description=" + + description + ", enabled=" + enabled + ", bvi=" + bvi + "]"; + } + + public static class LoopbackCommandBuilder { + + private String interfaceName; + private Operations operation; + private PhysAddress physAddress; + private String bridgeDomain; + private String description; + private boolean bvi = false; + private boolean enabled = true; + private IpAddress ipAddress; + private IpPrefix ipPrefix; + + public String getInterfaceName() { + return interfaceName; + } + + public LoopbackCommandBuilder setInterfaceName(String interfaceName) { + this.interfaceName = interfaceName; + return this; + } + + public Operations getOperation() { + return operation; + } + + public LoopbackCommandBuilder setOperation(Operations operation) { + this.operation = operation; + return this; + } + + public PhysAddress getPhysAddress() { + return physAddress; + } + + public LoopbackCommandBuilder setPhysAddress(PhysAddress physAddress) { + this.physAddress = physAddress; + return this; + } + + public String getBridgeDomain() { + return bridgeDomain; + } + + public LoopbackCommandBuilder setBridgeDomain(String bridgeDomain) { + this.bridgeDomain = bridgeDomain; + return this; + } + + public String getDescription() { + return description; + } + + public LoopbackCommandBuilder setDescription(String description) { + this.description = description; + return this; + } + + public boolean isEnabled() { + return enabled; + } + + public LoopbackCommandBuilder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + public IpAddress getIpAddress() { + return ipAddress; + } + + public LoopbackCommandBuilder setIpAddress(IpAddress ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + public IpPrefix getIpPrefix() { + return ipPrefix; + } + + public LoopbackCommandBuilder setIpPrefix(IpPrefix ipPrefix) { + this.ipPrefix = ipPrefix; + return this; + } + + public boolean isBvi() { + return bvi; + } + + public LoopbackCommandBuilder setBvi(boolean bvi) { + this.bvi = bvi; + return this; + } + + /** + * LoopPortCommand build method. + * + * @return LoopPortCommand + * @throws IllegalArgumentException if interfaceName or operation is null. + */ + public LoopbackCommand build() { + Preconditions.checkArgument(this.interfaceName != null); + Preconditions.checkArgument(this.operation != null); + + return new LoopbackCommand(this); + } + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java index a053fabe5..d32222498 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java @@ -25,6 +25,7 @@ import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommand; import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.TapPortCommand; import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand; import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder; @@ -40,6 +41,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpo import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint.InterfaceTypeChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUserRole; @@ -91,11 +93,14 @@ public class InterfaceManager implements AutoCloseable { private ListenableFuture vppEndpointCreated(VppEndpoint vppEndpoint) { InterfaceTypeChoice interfaceTypeChoice = vppEndpoint.getInterfaceTypeChoice(); + LOG.trace("Creating VPP endpoint {}, type of {}", vppEndpoint, interfaceTypeChoice); Optional potentialIfaceCommand = Optional.absent(); if (interfaceTypeChoice instanceof VhostUserCase) { potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.PUT); } else if (interfaceTypeChoice instanceof TapCase) { potentialIfaceCommand = createTapInterfaceWithoutBdCommand(vppEndpoint, Operations.PUT); + } else if (interfaceTypeChoice instanceof LoopbackCase){ + potentialIfaceCommand = createLoopbackWithoutBdCommand(vppEndpoint, Operations.PUT); } if (!potentialIfaceCommand.isPresent()) { @@ -117,6 +122,7 @@ public class InterfaceManager implements AutoCloseable { VppEndpoint vppEndpoint, InstanceIdentifier vppNodeIid) { final ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction(); createIfaceWithoutBdCommand.execute(rwTx); + LOG.trace("Creating Interface on VPP: {}", createIfaceWithoutBdCommand); return Futures.transform(rwTx.submit(), new AsyncFunction() { @Override @@ -146,11 +152,14 @@ public class InterfaceManager implements AutoCloseable { private ListenableFuture vppEndpointDeleted(@Nonnull VppEndpoint vppEndpoint) { InterfaceTypeChoice interfaceTypeChoice = vppEndpoint.getInterfaceTypeChoice(); + LOG.trace("Deleting VPP endpoint {}, type of {}", vppEndpoint, interfaceTypeChoice.toString()); Optional potentialIfaceCommand = Optional.absent(); if (interfaceTypeChoice instanceof VhostUserCase) { potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.DELETE); } else if (interfaceTypeChoice instanceof TapCase) { potentialIfaceCommand = createTapInterfaceWithoutBdCommand(vppEndpoint, Operations.DELETE); + } else if (interfaceTypeChoice instanceof LoopbackCase){ + potentialIfaceCommand = createLoopbackWithoutBdCommand(vppEndpoint, Operations.DELETE); } if (!potentialIfaceCommand.isPresent()) { @@ -172,6 +181,7 @@ public class InterfaceManager implements AutoCloseable { DataBroker vppDataBroker, VppEndpoint vppEndpoint, InstanceIdentifier vppNodeIid) { ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction(); deleteIfaceWithoutBdCommand.execute(rwTx); + LOG.trace("Deleting Interface on VPP: {}", deleteIfaceWithoutBdCommand); return Futures.transform(rwTx.submit(), new AsyncFunction() { @@ -256,6 +266,29 @@ public class InterfaceManager implements AutoCloseable { return Optional.of(tapPortCommand); } + private static Optional createLoopbackWithoutBdCommand(@Nonnull VppEndpoint vppEp, + @Nonnull Operations operation) { + if (!hasNodeAndInterface(vppEp)) { + LOG.debug("Interface command is not created for {}", vppEp); + return Optional.absent(); + } + LoopbackCommand.LoopbackCommandBuilder builder = LoopbackCommand.builder(); + LoopbackCase loopIface = (LoopbackCase) vppEp.getInterfaceTypeChoice(); + + builder.setPhysAddress(loopIface.getPhysAddress()); + builder.setBvi(loopIface.isBvi()); + builder.setIpAddress(loopIface.getIpAddress()); + builder.setIpPrefix(loopIface.getIpPrefix()); + + LoopbackCommand loopbackCommand = builder + .setOperation(operation) + .setDescription(vppEp.getDescription()) + .setInterfaceName(vppEp.getVppInterfaceName()) + .build(); + + return Optional.of(loopbackCommand); + } + /** * Adds bridge domain to an interface if the interface exist.
* It rewrites bridge domain in case it already exist.
@@ -273,7 +306,7 @@ public class InterfaceManager implements AutoCloseable { * @return {@link ListenableFuture} */ public synchronized @Nonnull ListenableFuture addBridgeDomainToInterface(@Nonnull String bridgeDomainName, - @Nonnull AddressEndpointWithLocation addrEpWithLoc) { + @Nonnull AddressEndpointWithLocation addrEpWithLoc, boolean enableBvi) { ExternalLocationCase epLoc = resolveAndValidateLocation(addrEpWithLoc); InstanceIdentifier vppNodeIid = epLoc.getExternalNodeMountPoint(); String interfacePath = epLoc.getExternalNodeConnector(); @@ -299,7 +332,7 @@ public class InterfaceManager implements AutoCloseable { @Override public ListenableFuture apply(Optional optIface) throws Exception { if (!optIface.isPresent()) { - return Futures.immediateFailedFuture(new Exception("Iterface " + return Futures.immediateFailedFuture(new Exception("Interface " + interfaceIid.firstKeyOf(Interface.class) + " does not exist on node " + vppNodeIid)); } @@ -321,7 +354,10 @@ public class InterfaceManager implements AutoCloseable { final ReadWriteTransaction rwTxRead = mountpoint.newReadWriteTransaction(); Optional optL2 = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, l2Iid, rwTxRead); L2Builder l2Builder = (optL2.isPresent()) ? new L2Builder(optL2.get()) : new L2Builder(); - L2 l2 = l2Builder.setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomainName).build()).build(); + L2 l2 = l2Builder.setInterconnection(new BridgeBasedBuilder() + .setBridgeDomain(bridgeDomainName) + .setBridgedVirtualInterface(enableBvi) + .build()).build(); final ReadWriteTransaction rwTxPut = prepareTransactionAndPutData(mountpoint, l2, l2Iid); LOG.debug("Adding bridge domain {} to interface {}", bridgeDomainName, interfacePath); return Futures.transform(rwTxPut.submit(), new AsyncFunction() { diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java index 1abae232c..5823d5bc4 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java @@ -20,7 +20,6 @@ import javax.annotation.Nullable; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager; import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager; @@ -46,14 +45,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_render import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.VlanNetwork; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomain; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpBridgeDomainKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint.InterfaceTypeChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppState; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.status.rev161005.BridgeDomainStatusAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.status.rev161005.BridgeDomainStatusFields; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; @@ -179,7 +176,7 @@ public final class ForwardingManager { } String l2FloodDomain = optL2FloodDomain.get(); try { - ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp).get(); + ifaceManager.addBridgeDomainToInterface(l2FloodDomain, rEp, isBviForEndpoint(rEp)).get(); LOG.debug("Interface added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp); } catch (InterruptedException | ExecutionException e) { // TODO add it to the status for renderer manager @@ -192,6 +189,25 @@ public final class ForwardingManager { } } + private boolean isBviForEndpoint(AddressEndpointWithLocation rEp) { + VppEndpointKey vppEndpointKey = + new VppEndpointKey(rEp.getAddress(), rEp.getAddressType(), rEp.getContextId(), rEp.getContextType()); + ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction(); + Optional vppEndpointOptional = + DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpointKey).build(), rTx); + if (vppEndpointOptional.isPresent()) { + InterfaceTypeChoice interfaceTypeChoice = vppEndpointOptional.get().getInterfaceTypeChoice(); + if (interfaceTypeChoice instanceof LoopbackCase) { + LOG.trace("Vpp renderer endpoint {} IS a BVI interface.", rEp.getKey()); + return ((LoopbackCase) interfaceTypeChoice).isBvi(); + } + } + rTx.close(); + LOG.trace("Vpp renderer endpoint {} IS NOT a BVI interface.", rEp.getKey()); + return false; + } + public void removeForwardingForEndpoint(RendererEndpointKey rEpKey, PolicyContext policyCtx) { AddressEndpointWithLocation rEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey)); ExternalLocationCase rEpLoc = resolveAndValidateLocation(rEp); diff --git a/renderers/vpp/src/main/yang/vpp-renderer.yang b/renderers/vpp/src/main/yang/vpp-renderer.yang index 2c6ae2b5b..25b3f835e 100644 --- a/renderers/vpp/src/main/yang/vpp-renderer.yang +++ b/renderers/vpp/src/main/yang/vpp-renderer.yang @@ -16,6 +16,7 @@ module vpp-renderer { import network-topology { prefix nt; revision-date 2013-10-21; } import opendaylight-l2-types { prefix l2-types; revision-date "2013-08-27"; } import ietf-yang-types { prefix yang-types; revision-date "2013-07-15"; } + import ietf-inet-types { prefix "inet-types"; } description "This module is a baseline for the group-based policy vpp renderer model."; @@ -89,6 +90,24 @@ module vpp-renderer { type yang-types:phys-address; } } + case loopback-case { + leaf phys-address { + description "MAC address of a loopback interface"; + type yang-types:phys-address; + } + leaf ip-address { + description "Ip address of a loopback interface"; + type inet-types:ip-address; + } + leaf ip-prefix { + description "Ip address prefix of a loopback interface"; + type inet-types:ip-prefix; + } + leaf bvi { + description "Enable/disable BVI for loopback interface"; + type boolean; + } + } } } diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommandTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommandTest.java new file mode 100644 index 000000000..1da16e3c5 --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/LoopbackCommandTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2016 Cisco Systems. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.commands; + +import com.google.common.base.Optional; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.renderer.vpp.VppRendererDataBrokerTest; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory; +import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; +import org.opendaylight.groupbasedpolicy.util.NetUtils; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.Loopback; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.LoopbackBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.l2.base.attributes.interconnection.BridgeBasedBuilder; + +import java.util.Collections; +import java.util.concurrent.ExecutionException; + +public class LoopbackCommandTest extends VppRendererDataBrokerTest { + + private final static String DESCRIPTION = "used for testing"; + private final static String INTERFACE_NAME = "testInterface"; + private final static String BRIDGE_DOMAIN = "testBD"; + private final static boolean IS_BVI = true; + private final static PhysAddress MAC_ADDRESS = new PhysAddress("00:11:22:33:44:55"); + private final static IpAddress IP_ADDRESS = new IpAddress(new Ipv4Address("10.0.0.1")); + private final static IpPrefix IP_PREFIX = new IpPrefix(new Ipv4Prefix("10.0.0.1/24")); + + private final static String UPD_DESCRIPTION = "updated description"; + private final static PhysAddress UPD_MAC_ADDRESS = new PhysAddress("55:44:33:22:11:00"); + private final static IpAddress UPD_IP_ADDRESS = new IpAddress(new Ipv4Address("20.0.0.1")); + private final static IpPrefix UPD_IP_PREFIX = new IpPrefix(new Ipv4Prefix("20.0.0.1/24")); + + private final static VppInterfaceAugmentationBuilder vppAugmentationBuilder = new VppInterfaceAugmentationBuilder() + .setLoopback(new LoopbackBuilder().setMac(MAC_ADDRESS).build()); + + private final static VppInterfaceAugmentationBuilder vppAugmentationBuilderWithBD = + new VppInterfaceAugmentationBuilder(vppAugmentationBuilder.build()) + .setL2(new L2Builder().setInterconnection(new BridgeBasedBuilder().setBridgeDomain(BRIDGE_DOMAIN) + .setBridgedVirtualInterface(IS_BVI).setSplitHorizonGroup((short)0) + .build()).build()); + + private final static InterfaceBuilder interfaceBuilder = + new InterfaceBuilder().setKey(new InterfaceKey(INTERFACE_NAME)) + .setEnabled(true) + .setDescription(DESCRIPTION) + .setType(Loopback.class) + .setName(INTERFACE_NAME) + .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled); + + private final static Interface1Builder + interface1Builder = + new Interface1Builder().setIpv4(new Ipv4Builder().setAddress(Collections.singletonList( + new AddressBuilder() + .setIp(new Ipv4AddressNoZone(IP_ADDRESS.getIpv4Address())) + .setSubnet(new PrefixLengthBuilder().setPrefixLength((short) NetUtils.getMaskFromPrefix(IP_PREFIX.getIpv4Prefix().getValue())).build()) + .build())) + .setEnabled(true) + .setForwarding(false) + .build()); + + private final static Interface BASIC_INTERFACE = + interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentationBuilder.build()) + .addAugmentation(Interface1.class, interface1Builder.build()).build(); + + private final static Interface BASIC_INTERFACE_WITH_BD = interfaceBuilder + .addAugmentation(VppInterfaceAugmentation.class, vppAugmentationBuilderWithBD.build()).build(); + + private DataBroker dataBroker; + + @Before + public void init() { + dataBroker = getDataBroker(); + } + + @Test + public void testAddLoopback() throws ExecutionException, InterruptedException { + ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction(); + LoopbackCommand addCommand = LoopbackCommand.builder() + .setOperation(General.Operations.PUT) + .setInterfaceName(INTERFACE_NAME) + .setDescription(DESCRIPTION) + .setBvi(IS_BVI) + .setPhysAddress(MAC_ADDRESS) + .setIpPrefix(IP_PREFIX) + .setIpAddress(IP_ADDRESS) + .setEnabled(true) + .build(); + + Assert.assertEquals(IS_BVI, addCommand.getBvi()); + Assert.assertEquals(MAC_ADDRESS, addCommand.getPhysAddress()); + Assert.assertEquals(IP_ADDRESS, addCommand.getIpAddress()); + Assert.assertEquals(IP_PREFIX, addCommand.getIpPrefix()); + + Optional optional = executeCommand(rwTx, addCommand); + + Assert.assertTrue(optional.isPresent()); + Assert.assertEquals(BASIC_INTERFACE, optional.get()); + + } + + @Test + public void testAddLoopback_WithBridgeDomain() throws ExecutionException, InterruptedException { + ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction(); + LoopbackCommand addCommand = LoopbackCommand.builder() + .setOperation(General.Operations.PUT) + .setInterfaceName(INTERFACE_NAME) + .setDescription(DESCRIPTION) + .setBvi(IS_BVI) + .setPhysAddress(MAC_ADDRESS) + .setIpPrefix(IP_PREFIX) + .setIpAddress(IP_ADDRESS) + .setBridgeDomain(BRIDGE_DOMAIN) + .setEnabled(true) + .build(); + + Assert.assertEquals(BRIDGE_DOMAIN, addCommand.getBridgeDomain()); + + Optional optional = executeCommand(rwTx, addCommand); + + Assert.assertTrue(optional.isPresent()); + Assert.assertEquals(BASIC_INTERFACE_WITH_BD, optional.get()); + + } + + private Optional executeCommand(ReadWriteTransaction rwTx, LoopbackCommand addCommand) + throws ExecutionException, InterruptedException { + addCommand.execute(rwTx); + + rwTx.submit().get(); + + ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction(); + + return DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + VppIidFactory.getInterfaceIID(new InterfaceKey(INTERFACE_NAME)), rTx); + } + + @Test + public void testDeleteLoopbackPort() throws ExecutionException, InterruptedException { + ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction(); + + rwTx.put(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()), + BASIC_INTERFACE, true); + rwTx.submit().get(); + + Optional optional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()), dataBroker.newReadOnlyTransaction()); + + Assert.assertTrue(optional.isPresent()); + + LoopbackCommand deleteCommand = LoopbackCommand.builder() + .setOperation(General.Operations.DELETE) + .setInterfaceName(INTERFACE_NAME) + .build(); + + ReadWriteTransaction rwTxDel = dataBroker.newReadWriteTransaction(); + deleteCommand.execute(rwTxDel); + rwTxDel.submit(); + + Optional optionalDeleted = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + VppIidFactory.getInterfaceIID(new InterfaceKey(deleteCommand.getName())), + dataBroker.newReadOnlyTransaction()); + + Assert.assertFalse(optionalDeleted.isPresent()); + } + + @Test + public void testUpdateLoopbackPort() throws ExecutionException, InterruptedException { + ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction(); + + rwTx.put(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()), + BASIC_INTERFACE, true); + rwTx.submit().get(); + + Optional optional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + VppIidFactory.getInterfaceIID(BASIC_INTERFACE.getKey()), dataBroker.newReadOnlyTransaction()); + + Assert.assertTrue(optional.isPresent()); + + LoopbackCommand updateCommand = LoopbackCommand.builder() + .setOperation(General.Operations.MERGE) + .setInterfaceName(INTERFACE_NAME) + .setDescription(UPD_DESCRIPTION) + .setPhysAddress(UPD_MAC_ADDRESS) + .setIpPrefix(UPD_IP_PREFIX) + .setIpAddress(UPD_IP_ADDRESS) + .setEnabled(false) + .build(); + + ReadWriteTransaction rwTxUpd = dataBroker.newReadWriteTransaction(); + updateCommand.execute(rwTxUpd); + rwTxUpd.submit().get(); + + Optional optionalUpdated = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + VppIidFactory.getInterfaceIID(new InterfaceKey(updateCommand.getName())), + dataBroker.newReadOnlyTransaction()); + + Assert.assertTrue(optionalUpdated.isPresent()); + Interface updatedInterface = optionalUpdated.get(); + + Assert.assertEquals(UPD_DESCRIPTION, updatedInterface.getDescription()); + Assert.assertFalse(updatedInterface.isEnabled()); + VppInterfaceAugmentation augmentation = updatedInterface.getAugmentation(VppInterfaceAugmentation.class); + Assert.assertEquals(INTERFACE_NAME, updatedInterface.getName()); + Assert.assertEquals(UPD_MAC_ADDRESS, augmentation.getLoopback().getMac()); + Interface1 interface1 = updatedInterface.getAugmentation(Interface1.class); + + // merge operation will add new ip address to list so index is 1 for new ip + String ip = interface1.getIpv4().getAddress().get(1).getIp().getValue(); + Subnet subnet = interface1.getIpv4().getAddress().get(1).getSubnet(); + String prefix = ""; + + if ( subnet instanceof PrefixLength){ + prefix = ((PrefixLength) subnet).getPrefixLength().toString(); + } + IpPrefix ipPrefix = new IpPrefix(new Ipv4Prefix(ip + "/" + prefix)); + IpAddress ipAddress = new IpAddress( new Ipv4Address(ip)); + Assert.assertEquals(UPD_IP_PREFIX, ipPrefix); + Assert.assertEquals(UPD_IP_ADDRESS, ipAddress); + } +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManagerTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManagerTest.java index fb9da42f9..801bbfbbe 100644 --- a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManagerTest.java +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManagerTest.java @@ -52,6 +52,7 @@ public class ForwardingManagerTest extends CustomDataBrokerTest { private static final String BD_1 = "bd1"; private static final NodeId NODE_1 = new NodeId("node1"); private static final VlanId VLAN_1 = new VlanId(1); + private static final boolean IS_BVI = false; @Mock private InterfaceManager ifaceManager; @Mock @@ -146,12 +147,12 @@ public class ForwardingManagerTest extends CustomDataBrokerTest { AddressEndpointWithLocation firstAddrEpWithLoc = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(firstRendererEp.getKey())); Mockito.when(ifaceManager.addBridgeDomainToInterface(Mockito.eq(DtoFactory.L2FD_CTX.getValue()), - Mockito.eq(firstAddrEpWithLoc))) + Mockito.eq(firstAddrEpWithLoc), Mockito.eq(IS_BVI))) .thenReturn(Futures.immediateFuture(null)); fwdManager.createForwardingForEndpoint(firstRendererEp.getKey(), policyCtx); Mockito.verify(ifaceManager).addBridgeDomainToInterface(Matchers.eq(DtoFactory.L2FD_CTX.getValue()), - Matchers.eq(firstAddrEpWithLoc)); + Matchers.eq(firstAddrEpWithLoc), Mockito.eq(IS_BVI)); } @Test -- 2.36.6