yang-gen-config
yang-gen-sal
maven-metadata-local.xml
+.metadata
+.recommenders
+/.gitignore
}
}
}
+
+ container subnet-dhcp-port-data {
+ config true;
+ list subnet-to-dhcp-port {
+ key "subnet-id";
+ leaf subnet-id { type string;}
+ leaf port-name { type string;}
+ leaf port-fixedip { type string;}
+ leaf port-macaddress { type string;}
+ }
+ }
+
}
\ No newline at end of file
import java.math.BigInteger;
import java.util.List;
-
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
import org.opendaylight.netvirt.dhcpservice.jobs.DhcpInterfaceAddJob;
import org.opendaylight.netvirt.dhcpservice.jobs.DhcpInterfaceRemoveJob;
import org.opendaylight.netvirt.dhcpservice.jobs.DhcpInterfaceUpdateJob;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
private DataStoreJobCoordinator dataStoreJobCoordinator;
private final IInterfaceManager interfaceManager;
+ private final IElanService elanService;
public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker,
DhcpExternalTunnelManager dhcpExternalTunnelManager,
- IInterfaceManager interfaceManager) {
+ IInterfaceManager interfaceManager, IElanService elanService) {
super(Interface.class, DhcpInterfaceEventListener.class);
this.dhcpManager = dhcpManager;
this.dataBroker = dataBroker;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.interfaceManager = interfaceManager;
+ this.elanService = elanService;
registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
}
return;
}
String interfaceName = del.getName();
+ Port port = dhcpManager.getNeutronPort(interfaceName);
+ if (NeutronConstants.IS_DHCP_PORT.test(port)) {
+ return;
+ }
NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
BigInteger dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
DhcpInterfaceRemoveJob job = new DhcpInterfaceRemoveJob(dhcpManager, dhcpExternalTunnelManager,
- dataBroker, interfaceName, dpnId, interfaceManager);
+ dataBroker, del, dpnId, interfaceManager, elanService);
dataStoreJobCoordinator.enqueueJob(DhcpServiceUtils.getJobKey(interfaceName), job, DhcpMConstants.RETRY_COUNT);
}
@Override
protected void add(InstanceIdentifier<Interface> identifier, Interface add) {
String interfaceName = add.getName();
+ LOG.trace("DhcpInterfaceAddJob to be created for interface {}", interfaceName);
List<String> ofportIds = add.getLowerLayerIf();
if (ofportIds == null || ofportIds.isEmpty()) {
return;
}
+ Port port = dhcpManager.getNeutronPort(interfaceName);
+ if (NeutronConstants.IS_DHCP_PORT.test(port)) {
+ return;
+ }
+
NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
BigInteger dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
DhcpInterfaceAddJob job = new DhcpInterfaceAddJob(dhcpManager, dhcpExternalTunnelManager, dataBroker,
- interfaceName, dpnId, interfaceManager);
+ add, dpnId, interfaceManager, elanService);
dataStoreJobCoordinator.enqueueJob(DhcpServiceUtils.getJobKey(interfaceName), job, DhcpMConstants.RETRY_COUNT);
}
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
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.Port;
private final DataBroker broker;
private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
private final IInterfaceManager interfaceManager;
+ private final IElanService elanService;
private int dhcpOptLeaseTime = 0;
private String dhcpOptDefDomainName;
public DhcpManager(final IMdsalApiManager mdsalApiManager,
final INeutronVpnManager neutronVpnManager,
final DhcpserviceConfig config, final DataBroker dataBroker,
- final DhcpExternalTunnelManager dhcpExternalTunnelManager, final IInterfaceManager interfaceManager) {
+ final DhcpExternalTunnelManager dhcpExternalTunnelManager, final IInterfaceManager interfaceManager,
+ final @Named("elanService") IElanService ielanService) {
this.mdsalUtil = mdsalApiManager;
this.neutronVpnService = neutronVpnManager;
this.config = config;
this.broker = dataBroker;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.interfaceManager = interfaceManager;
-
+ this.elanService = ielanService;
configureLeaseDuration(DhcpMConstants.DEFAULT_LEASE_TIME);
}
@PostConstruct
public void init() {
+ LOG.trace("Netvirt DHCP Manager Init .... {}",config.isControllerDhcpEnabled());
if (config.isControllerDhcpEnabled()) {
- dhcpInterfaceEventListener =
- new DhcpInterfaceEventListener(this, broker, dhcpExternalTunnelManager, interfaceManager);
+ dhcpInterfaceEventListener = new DhcpInterfaceEventListener(this, broker, dhcpExternalTunnelManager,
+ interfaceManager, elanService);
dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(broker, dhcpExternalTunnelManager, this);
LOG.info("DHCP Service initialized");
}
*/
package org.opendaylight.netvirt.dhcpservice;
+import com.google.common.util.concurrent.ListenableFuture;
import java.math.BigInteger;
+import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
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.neutron.binding.rev150712.PortBindingExtension;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
private static final Logger LOG = LoggerFactory.getLogger(DhcpNeutronPortListener.class);
private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
+ private final IElanService elanService;
private final DataBroker broker;
- private DhcpserviceConfig config;
+ private final DhcpserviceConfig config;
+ private final IInterfaceManager interfaceManager;
@Inject
- public DhcpNeutronPortListener(final DataBroker db, final DhcpExternalTunnelManager dhcpExternalTunnelManager,
- final DhcpserviceConfig config) {
+ public DhcpNeutronPortListener(DataBroker db, DhcpExternalTunnelManager dhcpExternalTunnelManager,
+ @Named("elanService") IElanService ielanService, IInterfaceManager interfaceManager,
+ DhcpserviceConfig config) {
super(Port.class, DhcpNeutronPortListener.class);
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
+ this.elanService = ielanService;
+ this.interfaceManager = interfaceManager;
this.broker = db;
this.config = config;
}
}
@Override
+ @SuppressWarnings("deprecation")
protected void remove(InstanceIdentifier<Port> identifier, Port del) {
LOG.trace("Port removed: {}", del);
+ if (NeutronConstants.IS_ODL_DHCP_PORT.test(del)) {
+ DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ portDataStoreCoordinator.enqueueJob(getJobKey(del), () -> {
+ WriteTransaction wrtConfigTxn = broker.newWriteOnlyTransaction();
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ DhcpServiceUtils.removeSubnetDhcpPortData(del, subnetDhcpPortIdfr -> wrtConfigTxn
+ .delete(LogicalDatastoreType.CONFIGURATION, subnetDhcpPortIdfr));
+ processArpResponderForElanDpns(del, arpInput -> {
+ LOG.trace("Removing ARP RESPONDER Flows for dhcp port {} with ipaddress {} with mac {} on dpn {}",
+ arpInput.getInterfaceName(), arpInput.getSpa(), arpInput.getSha(), arpInput.getDpId());
+ elanService.removeArpResponderFlow(arpInput);
+ });
+ futures.add(wrtConfigTxn.submit());
+ return futures;
+ });
+ }
if (isVnicTypeDirectOrMacVtap(del)) {
removePort(del);
}
}
+ private String getJobKey(Port port) {
+ return "PORT- " + port.getUuid().getValue();
+ }
+
@Override
protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
LOG.trace("Port changed to {}", update);
}
@Override
+ @SuppressWarnings("deprecation")
protected void add(InstanceIdentifier<Port> identifier, Port add) {
LOG.trace("Port added {}", add);
+ if (NeutronConstants.IS_ODL_DHCP_PORT.test(add)) {
+ DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ portDataStoreCoordinator.enqueueJob(getJobKey(add), () -> {
+ WriteTransaction wrtConfigTxn = broker.newWriteOnlyTransaction();
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ DhcpServiceUtils.createSubnetDhcpPortData(add, (subnetDhcpPortIdfr, subnetToDhcpport) -> wrtConfigTxn
+ .put(LogicalDatastoreType.CONFIGURATION, subnetDhcpPortIdfr, subnetToDhcpport));
+ processArpResponderForElanDpns(add, arpInput -> {
+ LOG.trace("Installing ARP RESPONDER Flows for dhcp port {} ipaddress {} with mac {} on dpn {}",
+ arpInput.getInterfaceName(), arpInput.getSpa(), arpInput.getSha(), arpInput.getDpId());
+ ArpReponderInputBuilder builder = new ArpReponderInputBuilder(arpInput);
+ builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager,
+ arpInput.getInterfaceName(), arpInput.getSpa(), arpInput.getSha()));
+ elanService.addArpResponderFlow(builder.buildForInstallFlow());
+ });
+ futures.add(wrtConfigTxn.submit());
+ return futures;
+ });
+ }
if (!isVnicTypeDirectOrMacVtap(add)) {
return;
}
return;
}
dhcpExternalTunnelManager.updateVniMacToPortCache(new BigInteger(segmentationId), macAddress, port);
+
}
private String getMacAddress(Port port) {
protected DhcpNeutronPortListener getDataTreeChangeListener() {
return DhcpNeutronPortListener.this;
}
+
+ /**
+ * Handle(Add/Remove) ARP Responder for DHCP IP on all the DPNs when DHCP is
+ * enabled/disabled on subnet add or update or delete.
+ *
+ * @param port
+ * DHCP port for which ARP Responder flow to be added when dhcp
+ * flag is enabled on the subnet or DHCP port for which ARP
+ * Responder flow to be removed when dhcp flag is disabled on the
+ * Subnet
+ * @param arpResponderAction
+ * ARP Responder Action to be performed i.e., add or remove flow
+ */
+ private void processArpResponderForElanDpns(Port port, Consumer<ArpResponderInput> arpResponderAction) {
+
+ java.util.Optional<String> ip4Address = DhcpServiceUtils.getIpV4Address(port);
+ if (!ip4Address.isPresent()) {
+ LOG.warn("There is no IPv4Address for port {}, not performing ARP responder add/remove flow operation",
+ port.getName());
+ return;
+ }
+ ElanHelper.getDpnInterfacesInElanInstance(broker, port.getNetworkId().getValue()).stream()
+ .map(ifName -> DhcpServiceUtils.getInterfaceInfo(interfaceManager, ifName)).forEach(interfaceInfo -> {
+ ArpResponderInput arpResponderInput = new ArpResponderInput.ArpReponderInputBuilder()
+ .setDpId(interfaceInfo.getDpId()).setInterfaceName(interfaceInfo.getInterfaceName())
+ .setLportTag(interfaceInfo.getInterfaceTag()).setSha(port.getMacAddress().getValue())
+ .setSpa(ip4Address.get()).build();
+ arpResponderAction.accept(arpResponderInput);
+ });
+
+ }
+
}
\ No newline at end of file
*/
package org.opendaylight.netvirt.dhcpservice;
+import com.google.common.base.Optional;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import org.opendaylight.controller.liblldp.EtherTypes;
import org.opendaylight.controller.liblldp.NetUtils;
import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.config.rev150710.DhcpserviceConfig;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
@Singleton
public class DhcpPktHandler implements PacketProcessingListener {
private final IInterfaceManager interfaceManager;
private final DhcpserviceConfig config;
private final DhcpAllocationPoolManager dhcpAllocationPoolMgr;
+ private final DataBroker broker;
@Inject
public DhcpPktHandler(final DhcpManager dhcpManager,
final PacketProcessingService pktService,
final IInterfaceManager interfaceManager,
final DhcpserviceConfig config,
- final DhcpAllocationPoolManager dhcpAllocationPoolMgr) {
+ final DhcpAllocationPoolManager dhcpAllocationPoolMgr,
+ final DataBroker dataBroker) {
this.interfaceManagerRpc = interfaceManagerRpc;
this.pktService = pktService;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.interfaceManager = interfaceManager;
this.config = config;
this.dhcpAllocationPoolMgr = dhcpAllocationPoolMgr;
+ this.broker = dataBroker;
}
//TODO: Handle this in a separate thread
private DhcpInfo getDhcpInfo(Port port, Subnet subnet) {
DhcpInfo dhcpInfo = null;
+ List<IpAddress> dnsServers = subnet.getDnsNameservers();
if (port != null && subnet != null) {
String clientIp = getIpv4Address(port);
String serverIp = null;
- if (isIpv4Address(subnet.getGatewayIp())) {
+ /* If neutronport-dhcp flag was enabled and an ODL network DHCP Port data was made available use the
+ * ports Fixed IP as server IP for DHCP communication.
+ */
+ if (config.getControllerDhcpMode() == DhcpserviceConfig.ControllerDhcpMode.UseOdlDhcpNeutronPort) {
+ java.util.Optional<SubnetToDhcpPort> dhcpPortData = DhcpServiceUtils.getSubnetDhcpPortData(broker,
+ subnet.getUuid().getValue());
+ if (dhcpPortData.isPresent()) {
+ serverIp = dhcpPortData.get().getPortFixedip();
+ dhcpInfo = new DhcpInfo();
+ if (isIpv4Address(subnet.getGatewayIp())) {
+ dhcpInfo.setGatewayIp(subnet.getGatewayIp().getIpv4Address().getValue());
+ }
+ dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
+ .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes())
+ .setDnsServersIpAddrs(dnsServers);
+ } else {
+ // DHCP Neutron Port not found for this network
+ LOG.error("Neutron DHCP port is not available for the Subnet {} and port {}.", subnet.getUuid(),
+ port.getUuid());
+ }
+ //When neutronport-dhcp flag is disabled continue running DHCP Server by hijacking the subnet-gateway-ip
+ } else if (isIpv4Address(subnet.getGatewayIp())) {
serverIp = subnet.getGatewayIp().getIpv4Address().getValue();
- }
- if (clientIp != null && serverIp != null) {
- List<IpAddress> dnsServers = subnet.getDnsNameservers();
- dhcpInfo = new DhcpInfo();
- dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
- .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes())
- .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
+ if (clientIp != null && serverIp != null) {
+ dhcpInfo = new DhcpInfo();
+ dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
+ .setCidr(String.valueOf(subnet.getCidr().getValue())).setHostRoutes(subnet.getHostRoutes())
+ .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
+ }
}
}
return dhcpInfo;
}
private void setCommonOptions(DHCP pkt, DhcpInfo dhcpInfo) {
- String gwIp = dhcpInfo.getGatewayIp();
+ String serverIp = dhcpInfo.getServerIp();
if (pkt.getMsgType() != DHCPConstants.MSG_NAK) {
setNonNakOptions(pkt, dhcpInfo);
}
* options to maintain order. If we can't fill them, unset to avoid
* sending wrong information in reply.
*/
- if (gwIp != null) {
- pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, gwIp);
+ if (serverIp != null) {
+ pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, serverIp);
} else {
pkt.unsetOption(DHCPConstants.OPT_SERVER_IDENTIFIER);
}
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
-
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.ActionInfo;
import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
+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.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.SubnetDhcpPortData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPortBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPortKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return;
}
List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
-
List<InstructionInfo> instructions = new ArrayList<>();
List<ActionInfo> actionsInfos = new ArrayList<>();
.addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ protected static void createSubnetDhcpPortData(Port port,
+ BiConsumer<InstanceIdentifier<SubnetToDhcpPort>, SubnetToDhcpPort> consumer) {
+ java.util.Optional<String> ip4Address = getIpV4Address(port);
+ java.util.Optional<String> subnetId = getNeutronSubnetId(port);
+ if (!(ip4Address.isPresent() && subnetId.isPresent())) {
+ return;
+ }
+ LOG.trace("Adding SubnetPortData entry for subnet {}", subnetId.get());
+ InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId.get());
+ SubnetToDhcpPort subnetToDhcpPort = getSubnetToDhcpPort(port, subnetId.get(), ip4Address.get());
+ try {
+ LOG.trace("Adding to SubnetToDhcpPort subnet {} mac {}.", subnetId.get(),
+ port.getMacAddress().getValue());
+ consumer.accept(identifier, subnetToDhcpPort);
+ } catch (Exception e) {
+ LOG.error("Failure while creating SubnetToDhcpPort map for network {}.", port.getNetworkId(), e);
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ protected static void removeSubnetDhcpPortData(Port port, Consumer<InstanceIdentifier<SubnetToDhcpPort>> consumer) {
+ java.util.Optional<String> subnetId = getNeutronSubnetId(port);
+ if (!subnetId.isPresent()) {
+ return;
+ }
+ LOG.trace("Removing NetworkPortData entry for Subnet {}", subnetId);
+ InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId.get());
+ try {
+ consumer.accept(identifier);
+ LOG.trace("Deleted SubnetDhcpPort for Network {}", subnetId.get());
+ } catch (Exception e) {
+ LOG.error("Failure while removing SubnetToDhcpPort for subnet {}.", subnetId, e);
+ }
+
+ }
+
+ static InstanceIdentifier<SubnetToDhcpPort> buildSubnetToDhcpPort(String subnetId) {
+ return InstanceIdentifier.builder(SubnetDhcpPortData.class)
+ .child(SubnetToDhcpPort.class, new SubnetToDhcpPortKey(subnetId)).build();
+ }
+
+ public static java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(DataBroker broker, String subnetId) {
+ InstanceIdentifier<SubnetToDhcpPort> id = buildSubnetToDhcpPort(subnetId);
+ try {
+ return java.util.Optional
+ .ofNullable(SingleTransactionDataBroker.syncRead(broker, LogicalDatastoreType.CONFIGURATION, id));
+ } catch (ReadFailedException e) {
+ LOG.warn("Failed to read SubnetToDhcpPort for DS due to error {}", e.getMessage());
+ }
+ return java.util.Optional.empty();
+ }
+
static IpAddress convertIntToIp(int ipn) {
String[] array = IntStream.of(24, 16, 8, 0) //
.map(x -> (ipn >> x) & 0xFF).boxed() //
return result;
}
+
+ static SubnetToDhcpPort getSubnetToDhcpPort(Port port, String subnetId, String ipAddress) {
+ return new SubnetToDhcpPortBuilder()
+ .setKey(new SubnetToDhcpPortKey(subnetId))
+ .setSubnetId(subnetId).setPortName(port.getUuid().getValue())
+ .setPortMacaddress(port.getMacAddress().getValue()).setPortFixedip(ipAddress).build();
+ }
+
+ static InterfaceInfo getInterfaceInfo(IInterfaceManager interfaceManager, String interfaceName) {
+ return interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
+ }
+
+ static BigInteger getDpIdFromInterface(IInterfaceManager interfaceManager, String interfaceName) {
+ return interfaceManager.getDpnForInterface(interfaceName);
+ }
+
+ public static java.util.Optional<String> getIpV4Address(Port port) {
+ if (port.getFixedIps() == null) {
+ return java.util.Optional.empty();
+ }
+ return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
+ .map(v -> v.getIpAddress().getIpv4Address().getValue()).findFirst();
+ }
+
+ public static java.util.Optional<String> getNeutronSubnetId(Port port) {
+ if (port.getFixedIps() == null) {
+ return java.util.Optional.empty();
+ }
+ return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
+ .map(v -> v.getSubnetId().getValue()).findFirst();
+ }
+
+ public static boolean isIpV4AddressAvailable(FixedIps fixedIp) {
+ return fixedIp != null && fixedIp.getIpAddress() != null && fixedIp.getIpAddress().getIpv4Address() != null;
+ }
+
}
\ No newline at end of file
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import org.opendaylight.netvirt.dhcpservice.DhcpManager;
import org.opendaylight.netvirt.dhcpservice.DhcpServiceUtils;
import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
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.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
DhcpManager dhcpManager;
DhcpExternalTunnelManager dhcpExternalTunnelManager;
DataBroker dataBroker;
- String interfaceName;
+ private final Interface interfaceAdd;
BigInteger dpnId;
IInterfaceManager interfaceManager;
+ private final IElanService elanService;
private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
@Override
public void onSuccess(Void result) {
};
public DhcpInterfaceAddJob(DhcpManager dhcpManager, DhcpExternalTunnelManager dhcpExternalTunnelManager,
- DataBroker dataBroker, String interfaceName, BigInteger dpnId,
- IInterfaceManager interfaceManager) {
+ DataBroker dataBroker, Interface interfaceAdd, BigInteger dpnId,
+ IInterfaceManager interfaceManager, IElanService elanService) {
super();
this.dhcpManager = dhcpManager;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.dataBroker = dataBroker;
- this.interfaceName = interfaceName;
+ this.interfaceAdd = interfaceAdd;
this.dpnId = dpnId;
this.interfaceManager = interfaceManager;
+ this.elanService = elanService;
}
@Override
public List<ListenableFuture<Void>> call() throws Exception {
List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String interfaceName = interfaceAdd.getName();
LOG.trace("Received add DCN for interface {}, dpid {}", interfaceName, dpnId);
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
if (!dpnId.equals(DhcpMConstants.INVALID_DPID)) {
Port port = dhcpManager.getNeutronPort(interfaceName);
Subnet subnet = dhcpManager.getNeutronSubnet(port);
- if (null != subnet && subnet.isEnableDhcp()) {
- LOG.info("DhcpInterfaceEventListener add isEnableDhcp" + subnet.isEnableDhcp());
- installDhcpEntries(interfaceName, dpnId, futures);
+ if (null == subnet || !subnet.isEnableDhcp()) {
+ LOG.debug("DHCP is not enabled for port {}", port.getName());
+ return Collections.emptyList();
}
+ LOG.info("DhcpInterfaceEventListener add isEnableDhcp:{}", subnet.isEnableDhcp());
+ installDhcpEntries(interfaceAdd.getName(), dpnId, futures);
+ LOG.trace("Checking ElanDpnInterface {} for dpn {} ", interfaceName, dpnId);
+ String subnetId = subnet.getUuid().getValue();
+ java.util.Optional<SubnetToDhcpPort> subnetToDhcp = DhcpServiceUtils
+ .getSubnetDhcpPortData(dataBroker, subnetId);
+ if (!subnetToDhcp.isPresent()) {
+ return Collections.emptyList();
+ }
+ LOG.trace("Installing the Arp responder for interface {} with DHCP MAC {} & IP {}.", interfaceName,
+ subnetToDhcp.get().getPortMacaddress(), subnetToDhcp.get().getPortFixedip());
+ ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
+ builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(subnetToDhcp.get().getPortFixedip())
+ .setSha(subnetToDhcp.get().getPortMacaddress()).setLportTag(interfaceAdd.getIfIndex());
+ builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName,
+ subnetToDhcp.get().getPortFixedip(), subnetToDhcp.get().getPortMacaddress()));
+ elanService.addArpResponderFlow(builder.buildForInstallFlow());
}
return futures;
}
import org.opendaylight.netvirt.dhcpservice.DhcpExternalTunnelManager;
import org.opendaylight.netvirt.dhcpservice.DhcpManager;
import org.opendaylight.netvirt.dhcpservice.DhcpServiceUtils;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
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.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
DhcpManager dhcpManager;
DhcpExternalTunnelManager dhcpExternalTunnelManager;
DataBroker dataBroker;
- String interfaceName;
+ Interface interfaceDel;
BigInteger dpnId;
IInterfaceManager interfaceManager;
+ private final IElanService elanService;
private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
@Override
public void onSuccess(Void result) {
public DhcpInterfaceRemoveJob(DhcpManager dhcpManager, DhcpExternalTunnelManager dhcpExternalTunnelManager,
DataBroker dataBroker,
- String interfaceName, BigInteger dpnId, IInterfaceManager interfaceManager) {
+ Interface interfaceDel, BigInteger dpnId, IInterfaceManager interfaceManager,
+ IElanService elanService) {
super();
this.dhcpManager = dhcpManager;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.dataBroker = dataBroker;
- this.interfaceName = interfaceName;
+ this.interfaceDel = interfaceDel;
this.dpnId = dpnId;
this.interfaceManager = interfaceManager;
+ this.elanService = elanService;
}
@Override
public List<ListenableFuture<Void>> call() throws Exception {
List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String interfaceName = interfaceDel.getName();
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
if (iface != null) {
return futures;
}
}
- unInstallDhcpEntries(interfaceName, dpnId, futures);
+ Port port = dhcpManager.getNeutronPort(interfaceName);
+ java.util.Optional<String> subnetId = DhcpServiceUtils.getNeutronSubnetId(port);
+ if (subnetId.isPresent()) {
+ java.util.Optional<SubnetToDhcpPort> subnetToDhcp = DhcpServiceUtils.getSubnetDhcpPortData(dataBroker,
+ subnetId.get());
+ if (subnetToDhcp.isPresent()) {
+ LOG.trace("Removing ArpResponder flow for last interface {} on DPN {}", interfaceName, dpnId);
+ ArpResponderInput arpInput = new ArpResponderInput.ArpReponderInputBuilder().setDpId(dpnId)
+ .setInterfaceName(interfaceName).setSpa(subnetToDhcp.get().getPortFixedip())
+ .setLportTag(interfaceDel.getIfIndex()).buildForRemoveFlow();
+ elanService.removeArpResponderFlow(arpInput);
+ }
+ }
+ unInstallDhcpEntries(interfaceDel.getName(), dpnId, futures);
return futures;
}
<dhcpservice-config xmlns="urn:opendaylight:params:xml:ns:yang:dhcpservice:config">
<controller-dhcp-enabled>false</controller-dhcp-enabled>
<dhcp-dynamic-allocation-pool-enabled>false</dhcp-dynamic-allocation-pool-enabled>
+ <controller-dhcp-mode>use-odl-dhcp-neutron-port</controller-dhcp-mode>
</dhcpservice-config>
interface="org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager" />
<reference id="iInterfaceManager"
interface="org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager" />
+ <reference id="elanService"
+ interface="org.opendaylight.netvirt.elanmanager.api.IElanService" />
<odl:rpc-service id="odlInterfaceRpcService"
interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService" />
type boolean;
default false;
}
+
+ leaf controller-dhcp-mode {
+ description "Specify the controller DHCP mode to use Neutron port or Subnet gateway as DHCP server IP";
+ type enumeration {
+ enum "use-odl-dhcp-neutron-port";
+ enum "use-subnet-gateway-ip";
+ }
+ default "use-odl-dhcp-neutron-port";
+ }
+
}
}
<groupId>org.opendaylight.genius</groupId>
<artifactId>interfacemanager-api</artifactId>
<version>${genius.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.genius</groupId>
+ <artifactId>idmanager-api</artifactId>
+ <version>${genius.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.genius</groupId>
+ <artifactId>idmanager-api</artifactId>
+ <version>${genius.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
* 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.netvirt.vpnmanager.arp.responder;
+package org.opendaylight.netvirt.elan.arp.responder;
public enum ArpResponderConstant {
* <p>Value:<b>Arp:tbl_{0}:lport_{1}:gw_{2}</b>
* <ul><li>0: Table Id</li>
* <li>1: LPort Tag</li>
- * <li>2: Gateway IP in String</li></ul>
+ * <li>2: Target Protocol Address IP in String</li></ul>
*/
- FLOW_ID_FORMAT("Arp:tbl_{0}:lport_{1}:gw_{2}"),
+ FLOW_ID_FORMAT_WITH_LPORT("Arp:tbl_{0}:lport_{1}:tpa_{2}"),
+ /**
+ * ARP Responder Flow ID.
+ *
+ * <p>Value:<b>Arp:tbl_{0}:lport_{1}:gw_{2}</b>
+ * <ul><li>0: Table Id</li>
+ * <li>1: LPort Tag</li>
+ * <li>2: Target Protocol Address IP in String</li></ul>
+ */
+ FLOW_ID_FORMAT_WITHOUT_LPORT("Arp:tbl_{0}:tpa_{1}"),
/**
* Pool name from which group id to be generated.
*
*
* <p>Value:<b>arp.responder.group.id</b>
*/
- ARP_RESPONDER_GROUP_ID("arp.responder.group.id");
+ ARP_RESPONDER_GROUP_ID("arp.responder.group.id"),
+ /**
+ * Prefix for arp check table.
+ *
+ * <p>Value:<b>arp.check.table.</b>
+ */
+ FLOWID_PREFIX_FOR_ARP_CHECK("arp.check.table."),
+ /**
+ * Prefix for l3 gateway mac table.
+ *
+ * <p>Value:<b>arp.l3.gwmac.table.</b>
+ */
+ FLOWID_PREFIX_FOR_MY_GW_MAC("arp.l3.gwmac.table.");
/**
* enum value holder.
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. 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.netvirt.elan.arp.responder;
+
+import com.google.common.base.Strings;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+
+public class ArpResponderInput {
+
+ private BigInteger dpId;
+ private String interfaceName;
+ private String spa;
+ private String sha;
+ private int lportTag;
+ private List<Instruction> instructions;
+
+
+ private ArpResponderInput() {}
+
+ public BigInteger getDpId() {
+ return dpId;
+ }
+
+ public String getInterfaceName() {
+ return interfaceName;
+ }
+
+ public String getSpa() {
+ return spa;
+ }
+
+ public String getSha() {
+ return sha;
+ }
+
+ public int getLportTag() {
+ return lportTag;
+ }
+
+ public List<Instruction> getInstructions() {
+ if (instructions == null) {
+ instructions = Collections.emptyList();
+ }
+ return instructions;
+ }
+
+ public static class ArpReponderInputBuilder {
+
+ private ArpResponderInput input;
+
+ public ArpReponderInputBuilder() {
+ input = new ArpResponderInput();
+ }
+
+ public ArpResponderInput build() {
+ return input;
+ }
+
+ public ArpResponderInput buildForInstallFlow() {
+
+ if (input.dpId == null || Strings.isNullOrEmpty(input.interfaceName) || Strings.isNullOrEmpty(input.spa)
+ || Strings.isNullOrEmpty(input.sha) || input.lportTag == 0 || input.instructions.isEmpty()) {
+ throw new AssertionError("Missing mandatory fields for ARP Responder Install Flow");
+ }
+
+ return input;
+ }
+
+ public ArpResponderInput buildForRemoveFlow() {
+
+ if (input.dpId == null || Strings.isNullOrEmpty(input.interfaceName) || Strings.isNullOrEmpty(input.spa)
+ || input.lportTag == 0) {
+ throw new AssertionError("Missing mandatory fields for ARP Responder Install Flow");
+ }
+
+ return input;
+ }
+
+ public ArpReponderInputBuilder(ArpResponderInput input) {
+ super();
+ this.input = input;
+ }
+
+ public ArpReponderInputBuilder setDpId(BigInteger dpId) {
+ input.dpId = dpId;
+ return this;
+ }
+
+ public ArpReponderInputBuilder setInterfaceName(String interfaceName) {
+ input.interfaceName = interfaceName;
+ return this;
+ }
+
+ public ArpReponderInputBuilder setSpa(String spa) {
+ input.spa = spa;
+ return this;
+ }
+
+ public ArpReponderInputBuilder setSha(String sha) {
+ input.sha = sha;
+ return this;
+ }
+
+ public ArpReponderInputBuilder setLportTag(int lportTag) {
+ input.lportTag = lportTag;
+ return this;
+ }
+
+ public ArpReponderInputBuilder setInstructions(List<Instruction> instructions) {
+ input.instructions = instructions == null ? Collections.emptyList() : instructions;
+ return this;
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. 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.netvirt.elan.arp.responder;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.BucketInfo;
+import org.opendaylight.genius.mdsalutil.FlowEntity;
+import org.opendaylight.genius.mdsalutil.GroupEntity;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
+import org.opendaylight.genius.mdsalutil.actions.ActionLoadIpToSpa;
+import org.opendaylight.genius.mdsalutil.actions.ActionLoadMacToSha;
+import org.opendaylight.genius.mdsalutil.actions.ActionMoveShaToTha;
+import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
+import org.opendaylight.genius.mdsalutil.actions.ActionMoveSpaToTpa;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetArpOp;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpTpa;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Arp Responder Utility Class.
+ */
+public class ArpResponderUtil {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ArpResponderUtil.class);
+
+ private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
+
+ /**
+ * A Utility class.
+ */
+ private ArpResponderUtil() {
+
+ }
+
+ /**
+ * Install Group flow on the DPN.
+ *
+ * @param mdSalManager
+ * Reference of MDSAL API RPC that provides API for installing
+ * group flow
+ * @param dpnId
+ * DPN on which group flow to be installed
+ * @param groupdId
+ * Uniquely identifiable Group Id for the group flow
+ * @param groupName
+ * Name of the group flow
+ * @param buckets
+ * List of the bucket actions for the group flow
+ */
+ public static void installGroup(IMdsalApiManager mdSalManager, BigInteger dpnId, long groupdId, String groupName,
+ List<BucketInfo> buckets) {
+ LOG.trace("Installing group flow on dpn {}", dpnId);
+ GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupdId, groupName, GroupTypes.GroupAll, buckets);
+ mdSalManager.syncInstallGroup(groupEntity, WAIT_TIME_FOR_SYNC_INSTALL);
+ try {
+ Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
+ } catch (InterruptedException e1) {
+ LOG.warn("Error while waiting for ARP Responder Group Entry to be installed on DPN {} ", dpnId);
+ }
+ }
+
+ /**
+ * Get Default ARP Responder Drop flow on the DPN.
+ *
+ * @param dpnId
+ * DPN on which group flow to be installed
+ */
+ public static FlowEntity getArpResponderTableMissFlow(BigInteger dpnId) {
+ return MDSALUtil.buildFlowEntity(dpnId, NwConstants.ARP_RESPONDER_TABLE,
+ String.valueOf(NwConstants.ARP_RESPONDER_TABLE), NwConstants.TABLE_MISS_PRIORITY,
+ ArpResponderConstant.DROP_FLOW_NAME.value(), 0, 0, NwConstants.COOKIE_ARP_RESPONDER,
+ new ArrayList<MatchInfo>(),
+ Collections.singletonList(new InstructionApplyActions(Collections.singletonList(new ActionDrop()))));
+ }
+
+ /**
+ * Get Bucket Actions for ARP Responder Group Flow.
+ *
+ * <p>
+ * Install Default Groups, Group has 3 Buckets
+ * </p>
+ * <ul>
+ * <li>Punt to controller</li>
+ * <li>Resubmit to Table {@link NwConstants#LPORT_DISPATCHER_TABLE}, for
+ * ELAN flooding
+ * <li>Resubmit to Table {@link NwConstants#ARP_RESPONDER_TABLE}, for ARP
+ * Auto response from DPN itself</li>
+ * </ul>
+ *
+ * @param resubmitTableId
+ * Resubmit Flow Table Id
+ * @param resubmitTableId2
+ * Resubmit Flow Table Id
+ * @return List of bucket actions
+ */
+ public static List<BucketInfo> getDefaultBucketInfos(short resubmitTableId, short resubmitTableId2) {
+ return Arrays.asList(
+ new BucketInfo(Collections.singletonList(new ActionPuntToController())),
+ new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId))),
+ new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId2))));
+ }
+
+ /**
+ * Get Match Criteria for the ARP Responder Flow.
+ *
+ * <p>
+ * List of Match Criteria for ARP Responder
+ * </p>
+ * <ul>
+ * <li>Packet is ARP</li>
+ * <li>Packet is ARP Request</li>
+ * <li>The ARP packet is requesting for Gateway IP</li>
+ * <li>Metadata which is generated by using Service
+ * Index({@link NwConstants#L3VPN_SERVICE_INDEX}) Lport Tag
+ * ({@link MetaDataUtil#METADATA_MASK_LPORT_TAG}) and VRF
+ * ID({@link MetaDataUtil#METADATA_MASK_VRFID})</li>
+ * </ul>
+ *
+ * @param lportTag
+ * LPort Tag
+ * @param elanInstance
+ * Elan Instance
+ * @param ipAddress
+ * Ip Address to be matched to this flow
+ * @return List of Match criteria
+ */
+ public static List<MatchInfo> getMatchCriteria(int lportTag, ElanInstance elanInstance,
+ String ipAddress) {
+
+ BigInteger metadata = ElanHelper.getElanMetadataLabel(elanInstance.getElanTag(), lportTag);
+ BigInteger metadataMask = ElanHelper.getElanMetadataMask();
+ return Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST, new MatchArpTpa(ipAddress, "32"),
+ new MatchMetadata(metadata, metadataMask));
+
+ }
+
+ /**
+ * Get List of actions for ARP Responder Flows.
+ *
+ * <p>
+ * Actions consists of all the ARP actions and Resubmit Action to table
+ * {@link NwConstants#ELAN_BASE_TABLE} such that packets can flow ELAN Rule
+ *
+ * @param ipAddress
+ * IP Address for which ARP Response packet is to be generated
+ * @param macAddress
+ * MacAddress for which ARP Response packet is to be generated
+ * @return List of ARP Responder Actions actions
+ */
+ public static List<Action> getActions(IInterfaceManager ifaceMgrRpcService, String ifName, String ipAddress,
+ String macAddress) {
+
+ AtomicInteger actionCounter = new AtomicInteger();
+ List<Action> actions = arpActions.apply(actionCounter, macAddress, ipAddress);
+ actions.addAll(getEgressActionsForInterface(ifaceMgrRpcService, ifName, actionCounter.get()));
+ LOG.trace("Total Number of actions is {}", actionCounter);
+ return actions;
+
+ }
+
+ /**
+ * A Interface that represent lambda TriFunction.
+ *
+ * @param <T>
+ * Input type
+ * @param <U>
+ * Input type
+ * @param <S>
+ * Input type
+ * @param <R>
+ * Return Type
+ */
+ @SuppressWarnings("checkstyle:ParameterName")
+ public interface TriFunction<T, U, S, R> {
+ /**
+ * Apply the Action.
+ *
+ * @param t
+ * Input1
+ * @param u
+ * Input2
+ * @param s
+ * Input3
+ * @return computed result
+ */
+ R apply(T t, U u, S s);
+ }
+
+ /**
+ * Lambda to apply arpAction. Inputs action counter, mac address and ip
+ * address
+ */
+ private static TriFunction<AtomicInteger, String, String, List<Action>> arpActions = (actionCounter, mac, ip) -> {
+ List<Action> actions = new ArrayList<>();
+ Collections.addAll(actions, new ActionMoveSourceDestinationEth().buildAction(actionCounter.getAndIncrement()),
+ new ActionSetFieldEthernetSource(new MacAddress(mac)).buildAction(actionCounter.getAndIncrement()),
+ new ActionSetArpOp(NwConstants.ARP_REPLY).buildAction(actionCounter.getAndIncrement()),
+ new ActionMoveShaToTha().buildAction(actionCounter.getAndIncrement()),
+ new ActionMoveSpaToTpa().buildAction(actionCounter.getAndIncrement()),
+ new ActionLoadMacToSha(new MacAddress(mac)).buildAction(actionCounter.getAndIncrement()),
+ new ActionLoadIpToSpa(ip).buildAction(actionCounter.getAndIncrement()),
+ new ActionNxLoadInPort(BigInteger.ZERO).buildAction(actionCounter.getAndIncrement()));
+ return actions;
+
+ };
+
+ /**
+ * Get instruction list for ARP responder flows.
+ */
+ public static List<Instruction> getInterfaceInstructions(IInterfaceManager ifaceMgrRpcService, String interfaceName,
+ String ipAddress, String macAddress) {
+ List<Action> actions = ArpResponderUtil.getActions(ifaceMgrRpcService, interfaceName, ipAddress, macAddress);
+ return Collections.singletonList(MDSALUtil.buildApplyActionsInstruction(actions));
+ }
+
+ /**
+ * Get instruction list for ARP responder flows originated from ext-net e.g.
+ * router-gw/fip.<br>
+ * The split-horizon bit should be reset in order to allow traffic from
+ * provider network to be routed back to flat/VLAN network and override the
+ * egress table drop flow.<br>
+ * In order to allow write-metadata in the ARP responder table the resubmit
+ * action needs to be replaced with goto instruction.
+ */
+ public static List<Instruction> getExtInterfaceInstructions(IInterfaceManager ifaceMgrRpcService,
+ String extInterfaceName, String ipAddress, String macAddress) {
+ AtomicInteger tableId = new AtomicInteger(-1);
+ List<Instruction> instructions = new ArrayList<>();
+ List<Action> actions = getActions(ifaceMgrRpcService, extInterfaceName, ipAddress, macAddress);
+ actions.removeIf(v -> {
+ org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = v
+ .getAction();
+ if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
+ tableId.set(((NxActionResubmitRpcAddGroupCase) actionClass).getNxResubmit().getTable());
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, 0));
+
+ if (tableId.get() != -1) {
+ // replace resubmit action with goto so it can co-exist with
+ // write-metadata
+ if ((short) tableId.get() > NwConstants.ARP_RESPONDER_TABLE) {
+ instructions.add(new InstructionGotoTable((short) tableId.get()).buildInstruction(2));
+ } else {
+ LOG.warn("Failed to insall responder flow for interface {}. Resubmit to {} can't be replaced with goto",
+ extInterfaceName, tableId);
+ }
+ }
+
+ return instructions;
+ }
+
+ /**
+ * Install ARP Responder FLOW.
+ *
+ * @param mdSalManager
+ * Reference of MDSAL API RPC that provides API for installing
+ * flow
+ * @param dpnId
+ * DPN on which flow to be installed
+ * @param flowId
+ * Uniquely Identifiable Arp Responder Table flow Id
+ * @param flowName
+ * Readable flow name
+ * @param priority
+ * Flow Priority
+ * @param cookie
+ * Flow Cookie
+ * @param matches
+ * List of Match Criteria for the flow
+ * @param instructions
+ * List of Instructions for the flow
+ */
+ public static void installFlow(IMdsalApiManager mdSalManager, BigInteger dpnId, String flowId, String flowName,
+ int priority, BigInteger cookie, List<MatchInfo> matches, List<Instruction> instructions) {
+ Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ARP_RESPONDER_TABLE, flowId, priority, flowName, 0, 0,
+ cookie, matches, instructions);
+ mdSalManager.installFlow(dpnId, flowEntity);
+ }
+
+ /**
+ * Remove flow form DPN.
+ *
+ * @param mdSalManager
+ * Reference of MDSAL API RPC that provides API for installing
+ * flow
+ * @param dpnId
+ * DPN form which flow to be removed
+ * @param flowId
+ * Uniquely Identifiable Arp Responder Table flow Id that is to
+ * be removed
+ */
+ public static void removeFlow(IMdsalApiManager mdSalManager, BigInteger dpnId, String flowId) {
+ Flow flowEntity = MDSALUtil.buildFlow(NwConstants.ARP_RESPONDER_TABLE, flowId);
+ mdSalManager.removeFlow(dpnId, flowEntity);
+ }
+
+ /**
+ * Creates Uniquely Identifiable flow Id.
+ *
+ * @param lportTag
+ * LportTag of the flow
+ * @param ipAdress
+ * Gateway IP for which ARP Response flow to be installed
+ * @return Unique Flow Id
+ *
+ * @see ArpResponderConstant#FLOW_ID_FORMAT_WITH_LPORT
+ * @see ArpResponderConstant#FLOW_ID_FORMAT_WITHOUT_LPORT
+ */
+ public static String getFlowId(int lportTag, String ipAdress) {
+ return MessageFormat.format(ArpResponderConstant.FLOW_ID_FORMAT_WITH_LPORT.value(),
+ NwConstants.ARP_RESPONDER_TABLE, lportTag, ipAdress);
+ }
+
+ /**
+ * Generate Cookie per flow.
+ *
+ * <p>
+ * Cookie is generated by Summation of
+ * {@link NwConstants#COOKIE_ARP_RESPONDER} + 1 + lportTag + Gateway IP
+ *
+ * @param lportTag
+ * Lport Tag of the flow
+ * @param ipAddress
+ * Gateway IP for which ARP Response flow to be installed
+ * @return Cookie
+ */
+ public static BigInteger generateCookie(int lportTag, String ipAddress) {
+ LOG.trace("IPAddress in long {}", ipAddress);
+ BigInteger cookie = NwConstants.COOKIE_ARP_RESPONDER.add(BigInteger.valueOf(255))
+ .add(BigInteger.valueOf(ipTolong(ipAddress)));
+ return cookie.add(BigInteger.valueOf(lportTag));
+ }
+
+ private static BiFunction<Short, Integer, BigInteger> cookie = (tableId,
+ arpOpType) -> NwConstants.COOKIE_ARP_RESPONDER.add(BigInteger.ONE).add(BigInteger.valueOf(tableId))
+ .add(BigInteger.valueOf(arpOpType));
+
+ private static BiFunction<Short, Integer, String> flowRef = (tableId,
+ arpOpType) -> (tableId == NwConstants.ARP_CHECK_TABLE
+ ? ArpResponderConstant.FLOWID_PREFIX_FOR_ARP_CHECK.value()
+ : ArpResponderConstant.FLOWID_PREFIX_FOR_MY_GW_MAC.value()) + tableId + NwConstants.FLOWID_SEPARATOR
+ + (arpOpType == NwConstants.ARP_REQUEST ? "arp.request" : "arp.replay");
+
+ public static FlowEntity createArpDefaultFlow(BigInteger dpId, short tableId, int arpOpType,
+ Supplier<List<MatchInfo>> matches, Supplier<List<ActionInfo>> actions) {
+
+ List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actions.get()));
+ return MDSALUtil.buildFlowEntity(dpId, tableId, flowRef.apply(tableId, arpOpType),
+ NwConstants.DEFAULT_ARP_FLOW_PRIORITY, flowRef.apply(tableId, arpOpType), 0, 0,
+ cookie.apply(tableId, arpOpType), matches.get(), instructions);
+ }
+
+ /**
+ * Get IP Address in Long from String.
+ *
+ * @param address
+ * IP Address that to be converted to long
+ * @return Long value of the IP Address
+ */
+ private static long ipTolong(String address) {
+
+ // Parse IP parts into an int array
+ long[] ip = new long[4];
+ String[] parts = address.split("\\.");
+
+ for (int i = 0; i < 4; i++) {
+ ip[i] = Long.parseLong(parts[i]);
+ }
+ // Add the above IP parts into an int number representing your IP
+ // in a 32-bit binary form
+ long ipNumbers = 0;
+ for (int i = 0; i < 4; i++) {
+ ipNumbers += ip[i] << (24 - (8 * i));
+ }
+ return ipNumbers;
+
+ }
+
+ /**
+ * Get List of Egress Action for the VPN interface.
+ *
+ * @param ifaceMgrRpcService
+ * Interface Manager RPC reference that invokes API to retrieve
+ * Egress Action
+ * @param ifName
+ * VPN Interface for which Egress Action to be retrieved
+ * @param actionCounter
+ * Action Key
+ * @return List of Egress Actions
+ */
+ public static List<Action> getEgressActionsForInterface(IInterfaceManager ifaceMgrRpcService, String ifName,
+ int actionCounter) {
+ List<ActionInfo> actionInfos = ifaceMgrRpcService.getInterfaceEgressActions(ifName);
+ AtomicInteger counter = new AtomicInteger(actionCounter);
+ return actionInfos.stream().map(v -> v.buildAction(counter.getAndIncrement())).collect(Collectors.toList());
+ }
+
+ /**
+ * Uses the IdManager to retrieve ARP Responder GroupId from ELAN pool.
+ *
+ * @param idManager
+ * the id manager
+ * @return the integer
+ */
+ public static Long retrieveStandardArpResponderGroupId(IdManagerService idManager) {
+
+ AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+ .setPoolName(ArpResponderConstant.ELAN_ID_POOL_NAME.value())
+ .setIdKey(ArpResponderConstant.ARP_RESPONDER_GROUP_ID.value()).build();
+
+ try {
+ Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+ RpcResult<AllocateIdOutput> rpcResult = result.get();
+ if (rpcResult.isSuccessful()) {
+ LOG.trace("Retrieved Group Id is {}", rpcResult.getResult().getIdValue());
+ return rpcResult.getResult().getIdValue();
+ } else {
+ LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when Allocating Id", e);
+ }
+ return 0L;
+ }
+
+}
*/
package org.opendaylight.netvirt.elanmanager.api;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ElanHelper {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ElanHelper.class);
+
+ private ElanHelper() {
+ throw new AssertionError(ElanHelper.class.getName() + " cannot be initialized.");
+ }
+
public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
return InstanceIdentifier.builder(ElanInstances.class)
.child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
}
+
+ public static BigInteger getElanMetadataLabel(long elanTag) {
+ return MetaDataUtil.getElanTagMetadata(elanTag);
+ }
+
+ public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
+ return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
+ }
+
+ public static BigInteger getElanMetadataMask() {
+ return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
+ }
+
+ public static List<String> getDpnInterfacesInElanInstance(DataBroker broker, String elanInstanceName) {
+
+ InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
+ try {
+ ElanDpnInterfacesList existingElanDpnInterfaces = SingleTransactionDataBroker.syncRead(broker,
+ LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+ if (existingElanDpnInterfaces != null) {
+ return existingElanDpnInterfaces.getDpnInterfaces().stream().flatMap(v -> v.getInterfaces().stream())
+ .collect(Collectors.toList());
+ }
+ } catch (ReadFailedException e) {
+ LOG.warn("Failed to read ElanDpnInterfacesList with error {}", e.getMessage());
+ }
+ return Collections.emptyList();
+ }
+
+ public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
+ return InstanceIdentifier.builder(ElanDpnInterfaces.class)
+ .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
+
+ }
}
import java.util.List;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
import org.opendaylight.netvirt.elanmanager.exceptions.MacNotFoundException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
Boolean isOpenStackVniSemanticsEnforced();
+ /**
+ * Add ARP Responder Flow on the given dpn for the ingress interface.
+ *
+ * @param arpResponderInput
+ * ArpResponder Input parameters
+ * @see ArpResponderInput
+ */
+ void addArpResponderFlow(ArpResponderInput arpResponderInput);
+
+ /**
+ * Remove ARP Responder flow from the given dpn for the ingress interface.
+ *
+ * @param arpResponderInput
+ * ArpResponder Input parameters
+ * @see ArpResponderInput
+ */
+ void removeArpResponderFlow(ArpResponderInput arpResponderInput);
+
}
<artifactId>interfacemanager-api</artifactId>
<version>${genius.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.genius</groupId>
- <artifactId>idmanager-api</artifactId>
- <version>${genius.version}</version>
- </dependency>
<dependency>
<groupId>org.opendaylight.genius</groupId>
<artifactId>itm-api</artifactId>
import org.opendaylight.netvirt.elan.utils.ElanConstants;
import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
import org.opendaylight.netvirt.elan.utils.ElanUtils;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
*/
private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
List<InstructionInfo> mkInstructions = new ArrayList<>();
- mkInstructions.add(new InstructionWriteMetadata(ElanUtils.getElanMetadataLabel(elanTag), ElanUtils
+ mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
.getElanMetadataMask()));
/* applicable for EXTERNAL_TUNNEL_TABLE only
* TODO: We should point to SMAC or DMAC depending on a configuration property to enable mac learning
WriteTransaction tx) {
int instructionKey = 0;
List<Instruction> instructions = new ArrayList<>();
- instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
+ instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
List<Action> actions = new ArrayList<>();
elanTag).buildAction());
instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, ++instructionKey));
- instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_BASE_TABLE,
+ instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_CHECK_TABLE,
++instructionKey));
short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.BucketInfo;
import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
+import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderConstant;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
import org.opendaylight.netvirt.elan.utils.ElanConstants;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
private final DataBroker broker;
private final IMdsalApiManager mdsalManager;
+ private final IdManagerService idManagerService;
private final int tempSmacLearnTimeout;
private final boolean puntLldpToController;
- public ElanNodeListener(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanConfig elanConfig) {
+ public ElanNodeListener(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanConfig elanConfig,
+ IdManagerService idManagerService) {
this.broker = dataBroker;
this.mdsalManager = mdsalManager;
this.tempSmacLearnTimeout = elanConfig.getTempSmacLearnTimeout();
this.puntLldpToController = elanConfig.isPuntLldpToController();
+ this.idManagerService = idManagerService;
}
@Override
BigInteger dpId = new BigInteger(node[1]);
createTableMissEntry(dpId);
createMulticastFlows(dpId);
+ createArpDefaultFlowsForArpCheckTable(dpId);
+ }
+
+ @SuppressWarnings("deprecation")
+ private void createArpDefaultFlowsForArpCheckTable(BigInteger dpId) {
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob("ARP_CHECK_TABLE-" + dpId.toString(), () -> {
+ WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
+ LOG.debug("Received notification to install Arp Check Default entries for dpn {} ", dpId);
+ createArpRequestMatchFlows(dpId, writeFlowTx);
+ createArpResponseMatchFlows(dpId, writeFlowTx);
+ return Arrays.asList(writeFlowTx.submit());
+ });
}
public void createTableMissEntry(BigInteger dpnId) {
setupTableMissSmacFlow(dpnId);
setupTableMissDmacFlow(dpnId);
+ setupTableMissArpCheckFlow(dpnId);
+ setupTableMissApResponderFlow(dpnId);
}
private void createMulticastFlows(BigInteger dpId) {
@Override
protected ElanNodeListener getDataTreeChangeListener() {
- // TODO Auto-generated method stub
return ElanNodeListener.this;
}
-}
+ private void setupTableMissApResponderFlow(final BigInteger dpnId) {
+ mdsalManager.installFlow(dpnId, ArpResponderUtil.getArpResponderTableMissFlow(dpnId));
+ }
+
+ private void setupTableMissArpCheckFlow(BigInteger dpnId) {
+ mdsalManager.installFlow(dpnId,
+ MDSALUtil.buildFlowEntity(dpnId, NwConstants.ARP_CHECK_TABLE,
+ String.valueOf("L2.ELAN." + NwConstants.ARP_CHECK_TABLE), NwConstants.TABLE_MISS_PRIORITY,
+ ArpResponderConstant.DROP_FLOW_NAME.value(), 0, 0, NwConstants.COOKIE_ARP_RESPONDER,
+ new ArrayList<MatchInfo>(),
+ Collections.singletonList(new InstructionGotoTable(NwConstants.ELAN_BASE_TABLE))));
+ }
+
+ private void createArpRequestMatchFlows(BigInteger dpId, WriteTransaction writeFlowTx) {
+
+ long arpRequestGroupId = ArpResponderUtil.retrieveStandardArpResponderGroupId(idManagerService);
+ List<BucketInfo> buckets = ArpResponderUtil.getDefaultBucketInfos(NwConstants.ELAN_BASE_TABLE,
+ NwConstants.ARP_RESPONDER_TABLE);
+ ArpResponderUtil.installGroup(mdsalManager, dpId, arpRequestGroupId,
+ ArpResponderConstant.GROUP_FLOW_NAME.value(), buckets);
+
+ FlowEntity arpReqArpCheckTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.ARP_CHECK_TABLE,
+ NwConstants.ARP_REQUEST, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST),
+ () -> Collections.singletonList(new ActionGroup(arpRequestGroupId)));
+ LOG.trace("Invoking MDSAL to install Arp Rquest Match Flow for table {}", NwConstants.ARP_CHECK_TABLE);
+ mdsalManager.addFlowToTx(arpReqArpCheckTbl, writeFlowTx);
+
+ }
+
+ private void createArpResponseMatchFlows(BigInteger dpId, WriteTransaction writeFlowTx) {
+ FlowEntity arpRepArpCheckTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.ARP_CHECK_TABLE,
+ NwConstants.ARP_REPLY, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REPLY),
+ () -> Arrays.asList(new ActionPuntToController(), new ActionNxResubmit(NwConstants.ELAN_BASE_TABLE)));
+ LOG.trace("Invoking MDSAL to install Arp Reply Match Flow for Table {} ", NwConstants.ARP_CHECK_TABLE);
+ mdsalManager.addFlowToTx(arpRepArpCheckTbl, writeFlowTx);
+
+ }
+
+}
\ No newline at end of file
import org.opendaylight.genius.utils.clustering.EntityOwnerUtils;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.infrautils.inject.AbstractLifecycle;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
import org.opendaylight.netvirt.elan.statusanddiag.ElanStatusMonitor;
import org.opendaylight.netvirt.elan.utils.ElanConstants;
import org.opendaylight.netvirt.elan.utils.ElanUtils;
isL2BeforeL3 = false;
}
}
+
+ @Override
+ public void addArpResponderFlow(ArpResponderInput arpResponderInput) {
+ elanUtils.addArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
+ arpResponderInput.getSpa(), arpResponderInput.getSha(), arpResponderInput.getLportTag(),
+ arpResponderInput.getInstructions());
+ }
+
+ @Override
+ public void removeArpResponderFlow(ArpResponderInput arpResponderInput) {
+ elanUtils.removeArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
+ arpResponderInput.getSpa(), arpResponderInput.getLportTag());
+ }
+
}
import org.opendaylight.genius.mdsalutil.packet.IPv4;
import org.opendaylight.genius.utils.ServiceIndex;
import org.opendaylight.netvirt.elan.ElanException;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
import org.opendaylight.netvirt.elan.internal.ElanInterfaceManager;
import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2;
}
- public static BigInteger getElanMetadataLabel(long elanTag) {
- return MetaDataUtil.getElanTagMetadata(elanTag);
- }
-
public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
int shBit = isSHFlagSet ? 1 : 0;
return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit));
}
- public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
- return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
- }
-
- public static BigInteger getElanMetadataMask() {
- return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
- }
-
/**
* Setting SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs.
*
int lportTag = interfaceInfo.getInterfaceTag();
// Matching metadata and eth_src fields
List<MatchInfo> mkMatches = new ArrayList<>();
- mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanInfo.getElanTag(), lportTag), getElanMetadataMask()));
+ mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag),
+ ElanHelper.getElanMetadataMask()));
mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress)));
List<InstructionInfo> mkInstructions = new ArrayList<>();
mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
ElanInstance elanInfo, long ifTag) {
List<MatchInfo> mkMatches = new ArrayList<>();
- mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+ mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
List<Instruction> mkInstructions = new ArrayList<>();
public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
String macAddress, String displayName, ElanInstance elanInstance) throws ElanException {
List<MatchInfo> mkMatches = new ArrayList<>();
- mkMatches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+ mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
List<Instruction> mkInstructions = new ArrayList<>();
int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
int instructionKey = 0;
List<Instruction> instructions = new ArrayList<>();
- instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(getElanMetadataLabel(elanTag),
+ instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress,
String displayName, long elanTag) {
List<MatchInfo> matches = new ArrayList<>();
- matches.add(new MatchMetadata(getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+ matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress)));
List<InstructionInfo> instructions = new ArrayList<>();
List<ActionInfo> actions = new ArrayList<>();
Set<String> removed = elanInstanceToInterfacesCache.remove(elanInstanceName);
return removed != null ? removed : Collections.emptySet();
}
-}
+
+ public void addArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, String macAddress,
+ int lportTag, List<Instruction> instructions) {
+ LOG.info("Installing the ARP responder flow on DPN {} for Interface {} with MAC {} & IP {}", dpnId,
+ ingressInterfaceName, macAddress, ipAddress);
+ ElanInterface elanIface = getElanInterfaceByElanInterfaceName(broker, ingressInterfaceName);
+ ElanInstance elanInstance = getElanInstanceByName(broker, elanIface.getElanInstanceName());
+ String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress);
+ ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY,
+ ArpResponderUtil.generateCookie(lportTag, ipAddress),
+ ArpResponderUtil.getMatchCriteria(lportTag, elanInstance, ipAddress), instructions);
+ LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName);
+
+ }
+
+ public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress,
+ int lportTag) {
+ LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,
+ ipAddress);
+ ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress));
+ }
+}
\ No newline at end of file
<argument ref="dataBroker" />
<argument ref="mdsalUtils" />
<argument ref="elanConfig" />
+ <argument ref="idManagerService" />
</bean>
<bean id="elanPacketInHandler"
LOG.debug("vpn-to-dpn-list is not empty for vpnName {}, dpn id {}, rd {} and floatingIp {}",
vpnName, dpnId, rd, externalIp);
List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
- if (ipAddressList.size() > 0) {
+ if (ipAddressList != null && !ipAddressList.isEmpty()) {
int floatingIpPresentCount = 0;
for (IpAddresses ipAddress: ipAddressList) {
if (!ipAddress.getIpAddress().equals(externalIp)
*/
package org.opendaylight.netvirt.neutronvpn.api.utils;
+import java.util.function.Predicate;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+
public class NeutronConstants {
public static final String DEVICE_OWNER_GATEWAY_INF = "network:router_gateway";
public static final String VIF_TYPE_MACVTAP = "macvtap";
public static final String VNIC_TYPE_NORMAL = "normal";
+ public static final Predicate<Port> IS_DHCP_PORT = port -> port != null
+ && port.getDeviceOwner().equals(DEVICE_OWNER_DHCP);
+
+ public static final Predicate<Port> IS_ODL_DHCP_PORT = port -> port != null
+ && port.getDeviceOwner().equals(DEVICE_OWNER_DHCP) && port.getDeviceId() != null
+ && port.getDeviceId().startsWith("OpenDaylight");
+
}
final Uuid portId = port.getUuid();
final Uuid subnetId = port.getFixedIps().get(0).getSubnetId();
final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
+ return;
+ }
portDataStoreCoordinator.enqueueJob("PORT- " + portName, () -> {
WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
List<ListenableFuture<Void>> futures = new ArrayList<>();
final String portName = port.getUuid().getValue();
final Uuid portId = port.getUuid();
final Uuid subnetId = port.getFixedIps().get(0).getSubnetId();
+ if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
+ return;
+ }
final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
portDataStoreCoordinator.enqueueJob("PORT- " + portName, () -> {
WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
BigInteger metadata = notification.getMetadata();
boolean isGarp = srcIP.equals(targetIP);
if (!isGarp) {
- LOG.trace("ArpNotification Non-Gratuitous Request Received from "
+ LOG.info("ArpNotification Non-Gratuitous Request Received from "
+ "interface {} and IP {} having MAC {} target destination {}, ignoring..",
srcInterface, srcIP.getIpv4Address().getValue(),srcMac.getValue(),
targetIP.getIpv4Address().getValue());
return;
}
- LOG.trace("ArpNotification Gratuitous Request Received from "
+ LOG.info("ArpNotification Gratuitous Request Received from "
+ "interface {} and IP {} having MAC {} target destination {}, learning MAC",
srcInterface, srcIP.getIpv4Address().getValue(),srcMac.getValue(),
targetIP.getIpv4Address().getValue());
PhysAddress srcMac = notification.getSrcMac();
BigInteger metadata = notification.getMetadata();
IpAddress targetIP = notification.getDstIpaddress();
- LOG.trace("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
+ LOG.info("ArpNotification Response Received from interface {} and IP {} having MAC {}, learning MAC",
srcInterface, srcIP.getIpv4Address().getValue(), srcMac.getValue());
processArpLearning(srcInterface, srcIP, srcMac, metadata, targetIP);
}
private void processArpLearning(String srcInterface, IpAddress srcIP, PhysAddress srcMac, BigInteger metadata,
IpAddress dstIP) {
if (metadata != null && !Objects.equals(metadata, BigInteger.ZERO)) {
- long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
- // Process ARP only if vpnservice is configured on the interface
- InstanceIdentifier<VpnIds> vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
- Optional<VpnIds> vpnIdsOptional
- = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
- if (!vpnIdsOptional.isPresent()) {
- LOG.trace("ARP NO_RESOLVE: VPN {} not configured. Ignoring responding to ARP requests on this VPN",
- vpnId);
- return;
- }
- VpnIds vpnIds = vpnIdsOptional.get();
- String vpnName = vpnIds.getVpnInstanceName();
- if (VpnUtil.isInterfaceAssociatedWithVpn(dataBroker, vpnName, srcInterface)) {
- LOG.debug("Received ARP for sender MAC {} and sender IP {} via interface {}",
+ Optional<String> vpn = VpnUtil.getVpnAssociatedWithInterface(dataBroker, srcInterface);
+ if (vpn.isPresent()) {
+ String vpnName = vpn.get();
+ LOG.info("Received ARP for sender MAC {} and sender IP {} via interface {}",
srcMac.getValue(), srcIP.getIpv4Address().getValue(), srcInterface);
String ipToQuery = srcIP.getIpv4Address().getValue();
- LOG.trace("ARP being processed for Source IP {}", ipToQuery);
+ LOG.info("ARP being processed for Source IP {}", ipToQuery);
VpnPortipToPort vpnPortipToPort =
VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipToQuery);
if (vpnPortipToPort != null) {
String oldMac = learntVpnVipToPort.getMacAddress();
if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
//MAC has changed for requested IP
- LOG.trace("ARP Source IP/MAC data modified for IP {} with MAC {} and Port {}",
+ LOG.info("ARP Source IP/MAC data modified for IP {} with MAC {} and Port {}",
ipToQuery, srcMac, srcInterface);
synchronized ((vpnName + ipToQuery).intern()) {
removeMipAdjacency(vpnName, oldPortName, srcIP);
} else if (!isIpInArpMigrateCache(vpnName, ipToQuery)) {
learnMacFromArpPackets(vpnName, srcInterface, srcIP, srcMac, dstIP);
}
+ } else {
+ LOG.info("ARP NO_RESOLVE: VPN not configured. Ignoring responding to ARP requests from this"
+ + " Interface {}.", srcInterface);
+ return;
+
}
}
}
import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService;
import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler;
import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
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.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
private final IInterfaceManager interfaceManager;
private final IVpnManager vpnManager;
private final IVpnLinkService ivpnLinkService;
+ private final ArpResponderHandler arpResponderHandler;
private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<>();
final VpnFootprintService vpnFootprintService,
final IInterfaceManager interfaceManager,
final IVpnManager vpnManager,
- final IVpnLinkService ivpnLnkSrvce) {
+ final IVpnLinkService ivpnLnkSrvce,
+ final ArpResponderHandler arpResponderHandler) {
super(VpnInterface.class, VpnInterfaceManager.class);
this.dataBroker = dataBroker;
this.interfaceManager = interfaceManager;
this.vpnManager = vpnManager;
this.ivpnLinkService = ivpnLnkSrvce;
+ this.arpResponderHandler = arpResponderHandler;
vpnInfUpdateTaskExecutor.scheduleWithFixedDelay(new VpnInterfaceUpdateTimerTask(),
0, VPN_INF_UPDATE_TIMER_TASK_DELAY, TIME_UNIT);
}
String gatewayMac = null;
long label = 0;
if (VpnUtil.isL3VpnOverVxLan(l3vni)) {
- gatewayMac = getGatewayMacAddressForInterface(vpnInstanceOpData.getVpnInstanceName(),
- intf.getName(), nextHop.getIpAddress()).get();
+ final VpnPortipToPort gwPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker,
+ vpnInstanceOpData.getVpnInstanceName(), nextHop.getIpAddress());
+ gatewayMac = arpResponderHandler.getGatewayMacAddressForInterface(gwPort, intf.getName()).get();
} else {
label = nextHop.getLabel();
}
// Use this for programming ARP_RESPONDER table here. And save this
// info into vpnInterface operational, so it can used in VrfEntryProcessor
// to populate L3_GW_MAC_TABLE there.
- addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName, subnetId,
- gwMac.get(), gatewayIp.get(), writeInvTxn);
+ arpResponderHandler.addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName,
+ subnetId, gatewayIp.get(), gwMac.get());
vpnInterfaceSubnetGwMacAddress = gwMac.get();
} else {
// A valid mac-address is not available for this subnet-gateway-ip
if (gwMac.isPresent()) {
VpnUtil.setupGwMacIfExternalVpn(dataBroker, mdsalManager, dpnId, interfaceName,
vpnId, writeInvTxn, NwConstants.ADD_FLOW, interfaceState);
- addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName, subnetId,
- gwMac.get(), gatewayIp.get(), writeInvTxn);
+ arpResponderHandler.addArpResponderFlow(dpnId, lportTag, vpnName, vpnId, interfaceName,
+ subnetId, gatewayIp.get(), gwMac.get());
} else {
LOG.error("Gateway MAC for subnet ID {} could not be obtained, cannot create "
+ "ARP responder flow for interface name {}, vpnName {}, gwIp {}",
vpnId, writeInvTxn, NwConstants.DEL_FLOW, interfaceState);
}
- removeArpResponderFlow(dpnId, lportTag, subnetId, writeInvTxn);
+ arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, vpnName, vpnId,
+ subnetId);
}
if (!nhList.isEmpty()) {
}
}
- private void addArpResponderFlow(final BigInteger dpId, final int lportTag, final String vpnName,
- final long vpnId, final String ifName, final Uuid subnetId,
- final String subnetGwMac, final String gwIp, final WriteTransaction writeInvTxn) {
- LOG.trace("Creating the ARP Responder flow for VPN Interface {}",ifName);
- final String flowId = ArpResponderUtil.getFlowID(lportTag, gwIp);
- List<Action> actions = ArpResponderUtil.getActions(ifaceMgrRpcService, ifName, gwIp, subnetGwMac);
- ArpResponderUtil.installFlow(mdsalManager, writeInvTxn, dpId, flowId, flowId,
- NwConstants.DEFAULT_ARP_FLOW_PRIORITY, ArpResponderUtil.generateCookie(lportTag, gwIp),
- ArpResponderUtil.getMatchCriteria(lportTag, vpnId, gwIp),
- Collections.singletonList(MDSALUtil.buildApplyActionsInstruction(actions)));
- LOG.trace("Installed the ARP Responder flow for VPN Interface {}", ifName);
- }
-
- private Optional<String> getGatewayMacAddressForInterface(String vpnName, String ifName, String ipAddress) {
- VpnPortipToPort gwPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipAddress);
- //Check if a router gateway interface is available for the subnet gw is so then use Router interface
- // else use connected interface
- return Optional.of((gwPort != null && gwPort.isSubnetIp())
- ? gwPort.getMacAddress() : InterfaceUtils.getMacAddressForInterface(dataBroker, ifName).get());
- }
-
private Optional<String> getMacAddressForSubnetIp(String vpnName, String ifName, String ipAddress) {
VpnPortipToPort gwPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnName, ipAddress);
//Check if a router gateway interface is available for the subnet gw is so then use Router interface
return Optional.absent();
}
- private void removeArpResponderFlow(final BigInteger dpId, final int lportTag, final Uuid subnetUuid,
- final WriteTransaction writeInvTxn) {
- final Optional<String> gwIp = VpnUtil.getVpnSubnetGatewayIp(dataBroker, subnetUuid);
- if (gwIp.isPresent()) {
- LOG.trace("VPNInterface adjacency Gsteway IP {} for ARP Responder removal", gwIp.get());
- final String flowId = ArpResponderUtil.getFlowID(lportTag, gwIp.get());
- ArpResponderUtil.removeFlow(mdsalManager, writeInvTxn, dpId, flowId);
- }
- }
-
// TODO Clean up the exception handling
@SuppressWarnings("checkstyle:IllegalCatch")
private void removePrefixFromBGP(String primaryRd, String rd, String vpnName, String prefix, String nextHop,
operationalAdjacency = populator.createOperationalAdjacency(input);
int label = operationalAdjacency.getLabel().intValue();
addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
- currVpnIntf.getVpnInstanceName(), (int) label, l3vni, origin,
+ currVpnIntf.getVpnInstanceName(), label, l3vni, origin,
currVpnIntf.getName(), operationalAdjacency, encapType, writeConfigTxn);
} else {
LOG.error("No rds to allocate extraroute {}", prefix);
package org.opendaylight.netvirt.vpnmanager;
import java.math.BigInteger;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
private final VpnInstanceListener vpnInstanceListener;
private final IdManagerService idManager;
private final IMdsalApiManager mdsalManager;
- private final VpnFootprintService vpnFootprintService;
- private final OdlInterfaceRpcService ifaceMgrRpcService;
private final IElanService elanService;
+ private final IInterfaceManager interfaceManager;
private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
public VpnManagerImpl(final DataBroker dataBroker,
final VpnInterfaceManager vpnInterfaceManager,
final IMdsalApiManager mdsalManager,
final VpnFootprintService vpnFootprintService,
- final OdlInterfaceRpcService ifaceMgrRpcService,
final IElanService elanService,
+ final IInterfaceManager interfaceManager,
final VpnSubnetRouteHandler vpnSubnetRouteHandler) {
this.dataBroker = dataBroker;
this.vpnInterfaceManager = vpnInterfaceManager;
this.vpnInstanceListener = vpnInstanceListener;
this.idManager = idManagerService;
this.mdsalManager = mdsalManager;
- this.vpnFootprintService = vpnFootprintService;
- this.ifaceMgrRpcService = ifaceMgrRpcService;
this.elanService = elanService;
+ this.interfaceManager = interfaceManager;
this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
}
installArpResponderFlowsToExternalNetworkIp(macAddress, dpnId, extInterfaceName, lportTag, vpnId,
fixedIp, writeTx);
} else {
- removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, writeTx);
+ removeArpResponderFlowsToExternalNetworkIp(dpnId, lportTag, fixedIp, writeTx,extInterfaceName);
}
}
}
private void installArpResponderFlowsToExternalNetworkIp(String macAddress, BigInteger dpnId,
- String extInterfaceName, Integer lportTag, long vpnId, String fixedIp, WriteTransaction writeTx) {
- String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
- List<Instruction> instructions = ArpResponderUtil.getExtInterfaceInstructions(ifaceMgrRpcService,
- extInterfaceName, fixedIp, macAddress);
- ArpResponderUtil.installFlow(mdsalManager, writeTx, dpnId, flowId, flowId,
- NwConstants.DEFAULT_ARP_FLOW_PRIORITY, ArpResponderUtil.generateCookie(lportTag, fixedIp),
- ArpResponderUtil.getMatchCriteria(lportTag, vpnId, fixedIp), instructions);
+ String extInterfaceName, int lportTag, long vpnId, String fixedIp, WriteTransaction writeTx) {
+ // reset the split-horizon bit to allow traffic to be sent back to the
+ // provider port
+ List<Instruction> instructions = new ArrayList<>();
+ instructions.add(
+ new InstructionWriteMetadata(BigInteger.ZERO, MetaDataUtil.METADATA_MASK_SH_FLAG).buildInstruction(1));
+ instructions.addAll(
+ ArpResponderUtil.getExtInterfaceInstructions(interfaceManager, extInterfaceName, fixedIp, macAddress));
+ ArpReponderInputBuilder builder = new ArpReponderInputBuilder().setDpId(dpnId)
+ .setInterfaceName(extInterfaceName).setSpa(fixedIp).setSha(macAddress).setLportTag(lportTag);
+ builder.setInstructions(instructions);
+ elanService.addArpResponderFlow(builder.buildForInstallFlow());
}
private void removeArpResponderFlowsToExternalNetworkIp(BigInteger dpnId, Integer lportTag, String fixedIp,
- WriteTransaction writeTx) {
- String flowId = ArpResponderUtil.getFlowID(lportTag, fixedIp);
- ArpResponderUtil.removeFlow(mdsalManager, writeTx, dpnId, flowId);
+ WriteTransaction writeTx,String extInterfaceName) {
+ ArpResponderInput arpInput = new ArpReponderInputBuilder().setDpId(dpnId).setInterfaceName(extInterfaceName)
+ .setSpa(fixedIp).setLportTag(lportTag).buildForRemoveFlow();
+ elanService.removeArpResponderFlow(arpInput);
}
private long getVpnIdFromExtNetworkId(Uuid extNetworkId) {
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.genius.mdsalutil.ActionInfo;
-import org.opendaylight.genius.mdsalutil.BucketInfo;
import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfo;
import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderConstant;
-import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
makeL3IntfTblMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
makeSubnetRouteTableMissFlow(writeFlowTx, dpId, NwConstants.ADD_FLOW);
createTableMissForVpnGwFlow(writeFlowTx, dpId);
- createArpRequestMatchFlowForGwMacTable(writeFlowTx, dpId);
- createArpResponseMatchFlowForGwMacTable(writeFlowTx, dpId);
+ createL3GwMacArpFlows(writeFlowTx, dpId);
programTableMissForVpnVniDemuxTable(writeFlowTx, dpId, NwConstants.ADD_FLOW);
List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
futures.add(writeFlowTx.submit());
.LPORT_DISPATCHER_TABLE));
List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
List<MatchInfo> matches = new ArrayList<MatchInfo>();
- String flowRef = getTableMissFlowRef(dpnId, (short)NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+ String flowRef = getTableMissFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
NwConstants.TABLE_MISS_FLOW);
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, (short)NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
flowRef, NwConstants.TABLE_MISS_PRIORITY, "VPN-VNI Demux Table Miss", 0, 0,
new BigInteger("1080000", 16), matches, instructions);
instructions);
LOG.trace("Invoking MDSAL to install L3 Gw Mac Table Miss Entry");
mdsalManager.addFlowToTx(flowEntityMissforGw, writeFlowTx);
- mdsalManager.addFlowToTx(ArpResponderUtil.getArpResponderTableMissFlow(dpId), writeFlowTx);
}
- private void createArpRequestMatchFlowForGwMacTable(WriteTransaction writeFlowTx, BigInteger dpId) {
- final List<BucketInfo> buckets = ArpResponderUtil.getDefaultBucketInfos(
- NwConstants.LPORT_DISPATCHER_TABLE,
- NwConstants.ARP_RESPONDER_TABLE);
- ArpResponderUtil.installGroup(mdsalManager, dpId,
- ArpResponderUtil.retrieveStandardArpResponderGroupId(idManagerService),
- ArpResponderConstant.GROUP_FLOW_NAME.value(), buckets);
-
- final List<MatchInfo> matches = new ArrayList<>();
- matches.add(MatchEthernetType.ARP);
- matches.add(MatchArpOp.REQUEST);
- final List<ActionInfo> actionInfos = Collections.singletonList(
- new ActionGroup(ArpResponderUtil.retrieveStandardArpResponderGroupId(idManagerService)));
- final List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionInfos));
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
- getFlowRefForArpFlows(dpId, NwConstants.L3_GW_MAC_TABLE, NwConstants.ARP_REQUEST),
- NwConstants.DEFAULT_ARP_FLOW_PRIORITY, "L3GwMac Arp Rquest", 0, 0, new BigInteger("1080000", 16), matches,
- instructions);
- LOG.trace("Invoking MDSAL to install L3 Gw Mac Arp Rquest Match Flow");
- mdsalManager.addFlowToTx(flowEntity, writeFlowTx);
- }
-
- private void createArpResponseMatchFlowForGwMacTable(WriteTransaction writeFlowTx, BigInteger dpId) {
- List<MatchInfo> matches = new ArrayList<>();
- matches.add(MatchEthernetType.ARP);
- matches.add(MatchArpOp.REPLY);
- List<ActionInfo> actionsInfos = new ArrayList<>();
- actionsInfos.add(new ActionPuntToController());
- actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
- List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
- FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
- getFlowRefForArpFlows(dpId, NwConstants.L3_GW_MAC_TABLE, NwConstants.ARP_REPLY),
- NwConstants.DEFAULT_ARP_FLOW_PRIORITY, "L3GwMac Arp Reply", 0, 0, new BigInteger("1080000", 16), matches,
- instructions);
- LOG.trace("Invoking MDSAL to install L3 Gw Mac Arp Reply Match Flow");
- mdsalManager.addFlowToTx(flowEntity, writeFlowTx);
- }
-
- private String getFlowRefForArpFlows(BigInteger dpnId, short tableId, int arpRequestOrReply) {
- return new StringBuffer().append(FLOWID_PREFIX_FOR_ARP).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
- .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(arpRequestOrReply)
- .append(FLOWID_PREFIX).toString();
+ private void createL3GwMacArpFlows(WriteTransaction writeFlowTx, BigInteger dpId) {
+ FlowEntity arpReqGwMacTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.L3_GW_MAC_TABLE,
+ NwConstants.ARP_REQUEST, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST),
+ () -> Collections.singletonList(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE)));
+ LOG.trace("Invoking MDSAL to install Arp Rquest Match Flow for table {}", NwConstants.L3_GW_MAC_TABLE);
+ mdsalManager.addFlowToTx(arpReqGwMacTbl, writeFlowTx);
+ FlowEntity arpRepGwMacTbl = ArpResponderUtil.createArpDefaultFlow(dpId, NwConstants.L3_GW_MAC_TABLE,
+ NwConstants.ARP_REPLY, () -> Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REPLY),
+ () -> Collections.singletonList(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE)));
+ LOG.trace("Invoking MDSAL to install Arp Reply Match Flow for Table {} ", NwConstants.L3_GW_MAC_TABLE);
+ mdsalManager.addFlowToTx(arpRepGwMacTbl, writeFlowTx);
}
private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
new PrefixesKey(ipPrefix)).build();
}
- static InstanceIdentifier<VpnIds> getPrefixToInterfaceIdentifier(long vpnId) {
+ public static InstanceIdentifier<VpnIds> getPrefixToInterfaceIdentifier(long vpnId) {
return InstanceIdentifier.builder(PrefixToInterface.class)
.child(VpnIds.class, new VpnIdsKey(vpnId)).build();
}
return vpnId;
}
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
+ .to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(
+ String vpnName) {
+ return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
+ .VpnInstance.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn
+ .id.VpnInstanceKey(
+ vpnName))
+ .build();
+ }
+
/**
* Retrieves the VPN Route Distinguisher searching by its Vpn instance name.
*
return read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId).isPresent();
}
- static boolean isInterfaceAssociatedWithVpn(DataBroker broker, String vpnName, String interfaceName) {
+ static Optional<String> getVpnAssociatedWithInterface(DataBroker broker, String interfaceName) {
InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
- Optional<VpnInterface> optConfiguredVpnInterface =
- read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId);
-
+ Optional<String> vpnOptional = Optional.absent();
+ Optional<VpnInterface> optConfiguredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION,
+ interfaceId);
if (optConfiguredVpnInterface.isPresent()) {
- String configuredVpnName = optConfiguredVpnInterface.get().getVpnInstanceName();
- if (configuredVpnName != null && configuredVpnName.equalsIgnoreCase(vpnName)) {
- return true;
- }
+ vpnOptional = Optional.of(optConfiguredVpnInterface.get().getVpnInstanceName());
}
- return false;
+ return vpnOptional;
}
public static String getIpPrefix(String prefix) {
return id;
}
- static VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
+ public static VpnPortipToPort getNeutronPortFromVpnPortFixedIp(DataBroker broker, String vpnName, String fixedIp) {
InstanceIdentifier id = buildVpnPortipToPortIdentifier(vpnName, fixedIp);
Optional<VpnPortipToPort> vpnPortipToPortData = read(broker, LogicalDatastoreType.CONFIGURATION, id);
if (vpnPortipToPortData.isPresent()) {
--- /dev/null
+/*
+ * Copyright (c) 2016 - 2017 Ericsson India Global Services Pvt Ltd. and others. 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.netvirt.vpnmanager.arp.responder;
+
+import com.google.common.base.Optional;
+
+import java.math.BigInteger;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.vpnmanager.VpnUtil;
+import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
+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.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class that is responsible for handling ARP Responder flows which involves to
+ * differentiate between router and connected mac cases, identify DPNs and
+ * installation and uninstallation of flows.
+ *
+ */
+public class ArpResponderHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ArpResponderHandler.class);
+ /**
+ * MDSAL DataBroker reference.
+ */
+ private final DataBroker dataBroker;
+ /**
+ * Elan RPC service reference.
+ */
+ private final IElanService elanService;
+
+ /**
+ * RPC to access InterfaceManager APIs.
+ */
+ private final IInterfaceManager interfaceManager;
+
+ /**
+ * Constructor.
+ *
+ * @param dataBroker
+ * {@link #dataBroker}
+ * @param elanService
+ * {@link #elanService}
+ * @param interfaceManager
+ * {@link #interfaceManager}
+ *
+ */
+ public ArpResponderHandler(DataBroker dataBroker, IElanService elanService, IInterfaceManager interfaceManager) {
+ super();
+ this.dataBroker = dataBroker;
+ this.elanService = elanService;
+ this.interfaceManager = interfaceManager;
+ }
+
+ /**
+ * Add ARP Responder flow, by invoking ELan RPC service.
+ *
+ * @param dpnId
+ * dpn Id on which ARP responder flow to be added
+ * @param lportTag
+ * lport tag of the interface
+ * @param vpnName
+ * vpnname of the interface
+ * @param vpnId
+ * vpn id that interface belongs to
+ * @param interfaceName
+ * interface to which ARP responder flow to be added
+ * @param subnetId
+ * subnet Id of the interface
+ * @param gatewayIp
+ * gateway ip of the interface
+ * @param mac
+ * mac address
+ */
+
+ public void addArpResponderFlow(BigInteger dpnId, int lportTag, String vpnName, long vpnId, String interfaceName,
+ Uuid subnetId, String gatewayIp, String mac) {
+
+ LOG.trace("Creating the ARP Responder flow for VPN Interface {}", interfaceName);
+ ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
+ builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(gatewayIp).setSha(mac).setLportTag(lportTag);
+ builder.setInstructions(
+ ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName, gatewayIp, mac));
+ elanService.addArpResponderFlow(builder.buildForInstallFlow());
+ }
+
+ /**
+ * Remove ARP Responder flow when VM interface is removed, by invoking ELan
+ * RPC service.
+ *
+ * @param dpId
+ * dpn Id on which ARP responder flow to be removed
+ * @param lportTag
+ * lport tag of the interface
+ * @param ifName
+ * interface to which ARP responder flow to be removed
+ * @param vpnName
+ * vpnname of the interface
+ * @param vpnId
+ * vpn id that interface belongs to
+ *
+ * @param subnetUuid
+ * subnet Id of the interface
+ */
+ public void removeArpResponderFlow(BigInteger dpId, int lportTag, String ifName, String vpnName, long vpnId,
+ Uuid subnetUuid) {
+ Optional<String> gwIp = VpnUtil.getVpnSubnetGatewayIp(dataBroker, subnetUuid);
+ if (gwIp.isPresent()) {
+ ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
+ builder.setDpId(dpId).setInterfaceName(ifName).setSpa(gwIp.get()).setLportTag(lportTag);
+ elanService.removeArpResponderFlow(builder.buildForRemoveFlow());
+ }
+ }
+
+ /**
+ * Get Mac address from given gateway port and interface name.
+ *
+ * @param gwPort
+ * gateway port
+ * @param ifName
+ * interface for which gateway to be retrieved
+ * @return mac address if present else optional absent value
+ */
+ public Optional<String> getGatewayMacAddressForInterface(VpnPortipToPort gwPort, String ifName) {
+ // Check if a router gateway interface is available for the subnet gw is
+ // so then use Router interface
+ // else use connected interface
+ return Optional.of((gwPort != null && gwPort.isSubnetIp()) ? gwPort.getMacAddress()
+ : InterfaceUtils.getMacAddressForInterface(dataBroker, ifName).get());
+ }
+
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. 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.netvirt.vpnmanager.arp.responder;
-
-import java.math.BigInteger;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.genius.mdsalutil.BucketInfo;
-import org.opendaylight.genius.mdsalutil.FlowEntity;
-import org.opendaylight.genius.mdsalutil.GroupEntity;
-import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MatchInfo;
-import org.opendaylight.genius.mdsalutil.MetaDataUtil;
-import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
-import org.opendaylight.genius.mdsalutil.actions.ActionLoadIpToSpa;
-import org.opendaylight.genius.mdsalutil.actions.ActionLoadMacToSha;
-import org.opendaylight.genius.mdsalutil.actions.ActionMoveShaToTha;
-import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
-import org.opendaylight.genius.mdsalutil.actions.ActionMoveSpaToTpa;
-import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
-import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
-import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
-import org.opendaylight.genius.mdsalutil.actions.ActionSetArpOp;
-import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
-import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
-import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
-import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
-import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
-import org.opendaylight.genius.mdsalutil.matches.MatchArpTpa;
-import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
-import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Arp Responder Utility Class.
- */
-public class ArpResponderUtil {
-
- private static final Logger LOG = LoggerFactory.getLogger(ArpResponderUtil.class);
-
- private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
-
- /**
- * A Utility class.
- */
- private ArpResponderUtil() {
-
- }
-
- /**
- * Install Group flow on the DPN.
- *
- * @param mdSalManager Reference of MDSAL API RPC that provides API for installing group flow
- * @param dpnId DPN on which group flow to be installed
- * @param groupdId Uniquely identifiable Group Id for the group flow
- * @param groupName Name of the group flow
- * @param buckets List of the bucket actions for the group flow
- */
- public static void installGroup(final IMdsalApiManager mdSalManager,
- final BigInteger dpnId, final long groupdId, final String groupName,
- final List<BucketInfo> buckets) {
- LOG.trace("Installing group flow on dpn {}", dpnId);
- final GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId,
- groupdId, groupName, GroupTypes.GroupAll, buckets);
- mdSalManager.syncInstallGroup(groupEntity, WAIT_TIME_FOR_SYNC_INSTALL);
- try {
- Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
- } catch (InterruptedException e1) {
- LOG.warn("Error while waiting for ARP Responder Group Entry to be installed on DPN {} ", dpnId);
- }
- }
-
- /**
- * Get Default ARP Responder Drop flow on the DPN.
- *
- * @param dpnId DPN on which group flow to be installed
- */
- public static FlowEntity getArpResponderTableMissFlow(final BigInteger dpnId) {
- return MDSALUtil.buildFlowEntity(dpnId, NwConstants.ARP_RESPONDER_TABLE,
- String.valueOf(NwConstants.ARP_RESPONDER_TABLE),
- NwConstants.TABLE_MISS_PRIORITY,
- ArpResponderConstant.DROP_FLOW_NAME.value(), 0, 0,
- NwConstants.COOKIE_ARP_RESPONDER,
- new ArrayList<MatchInfo>(),
- Collections.singletonList(new InstructionApplyActions(Collections.singletonList(new ActionDrop()))));
- }
-
- /**
- * Get Bucket Actions for ARP Responder Group Flow.
- *
- * <p>Install Default Groups, Group has 3 Buckets
- * </p>
- * <ul>
- * <li>Punt to controller</li>
- * <li>Resubmit to Table {@link NwConstants#LPORT_DISPATCHER_TABLE}, for
- * ELAN flooding
- * <li>Resubmit to Table {@link NwConstants#ARP_RESPONDER_TABLE}, for ARP
- * Auto response from DPN itself</li>
- * </ul>
- *
- * @param resubmitTableId Resubmit Flow Table Id
- * @param resubmitTableId2 Resubmit Flow Table Id
- * @return List of bucket actions
- */
- public static List<BucketInfo> getDefaultBucketInfos(
- final short resubmitTableId, final short resubmitTableId2) {
- final List<BucketInfo> buckets = new ArrayList<>();
- buckets.add(new BucketInfo(Collections.singletonList(new ActionPuntToController())));
- buckets.add(new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId))));
- buckets.add(new BucketInfo(Collections.singletonList(new ActionNxResubmit(resubmitTableId2))));
- return buckets;
- }
-
- /**
- * Get Match Criteria for the ARP Responder Flow.
- *
- * <p>List of Match Criteria for ARP Responder
- * </p>
- * <ul>
- * <li>Packet is ARP</li>
- * <li>Packet is ARP Request</li>
- * <li>The ARP packet is requesting for Gateway IP</li>
- * <li>Metadata which is generated by using Service
- * Index({@link NwConstants#L3VPN_SERVICE_INDEX}) Lport Tag
- * ({@link MetaDataUtil#METADATA_MASK_LPORT_TAG}) and VRF
- * ID({@link MetaDataUtil#METADATA_MASK_VRFID})</li>
- * </ul>
- *
- * @param lportTag LPort Tag
- * @param vpnId VPN ID
- * @param ipAddress Gateway IP
- * @return List of Match criteria
- */
- public static List<MatchInfo> getMatchCriteria(final int lportTag,
- final long vpnId, final String ipAddress) {
-
- final List<MatchInfo> matches = new ArrayList<>();
- short matchIndex = NwConstants.L3VPN_SERVICE_INDEX;
- final BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(
- lportTag, ++matchIndex, MetaDataUtil.getVpnIdMetadata(vpnId));
- final BigInteger metadataMask = MetaDataUtil
- .getMetaDataMaskForLPortDispatcher(
- MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
- MetaDataUtil.METADATA_MASK_LPORT_TAG,
- MetaDataUtil.METADATA_MASK_VRFID);
-
- // Matching Arp request flows
- matches.add(MatchEthernetType.ARP);
- matches.add(new MatchMetadata(metadata, metadataMask));
- matches.add(MatchArpOp.REQUEST);
- matches.add(new MatchArpTpa(ipAddress, "32"));
- return matches;
-
- }
-
- /**
- * Get List of actions for ARP Responder Flows.
- *
- * <p>Actions consists of all the ARP actions from
- * and Egress Actions Retrieved
- *
- * @param ifaceMgrRpcService Interface manager RPC reference to invoke RPC to get Egress actions for the interface
- * @param vpnInterface VPN Interface for which flow to be installed
- * @param ipAddress Gateway IP Address
- * @param macAddress Gateway MacAddress
- * @return List of ARP Responder Actions actions
- */
- public static List<Action> getActions(
- final OdlInterfaceRpcService ifaceMgrRpcService,
- final String vpnInterface, final String ipAddress,
- final String macAddress) {
-
- final List<Action> actions = new ArrayList<>();
- int actionCounter = 0;
- actions.add(new ActionMoveSourceDestinationEth().buildAction(actionCounter++));
- actions.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)).buildAction(actionCounter++));
- actions.add(new ActionSetArpOp(NwConstants.ARP_REPLY).buildAction(actionCounter++));
- actions.add(new ActionMoveShaToTha().buildAction(actionCounter++));
- actions.add(new ActionMoveSpaToTpa().buildAction(actionCounter++));
- actions.add(new ActionLoadMacToSha(new MacAddress(macAddress)).buildAction(actionCounter++));
- actions.add(new ActionLoadIpToSpa(ipAddress).buildAction(actionCounter++));
- // A temporary fix until to send packet to incoming port by loading IN_PORT with zero, until in_port is
- // overridden in table=0
- actions.add(new ActionNxLoadInPort(BigInteger.ZERO).buildAction(actionCounter++));
-
- actions.addAll(getEgressActionsForInterface(ifaceMgrRpcService, vpnInterface, actionCounter));
- LOG.trace("Total Number of actions is {}", actionCounter);
- return actions;
-
- }
-
- /**
- * Get instruction list for ARP responder flows originated from ext-net e.g.
- * router-gw/fip.<br>
- * The split-horizon bit should be reset in order to allow traffic from
- * provider network to be routed back to flat/VLAN network and override the
- * egress table drop flow.<br>
- * In order to allow write-metadata in the ARP responder table the resubmit
- * action needs to be replaced with goto instruction.
- */
- public static List<Instruction> getExtInterfaceInstructions(final OdlInterfaceRpcService ifaceMgrRpcService,
- final String extInterfaceName, final String ipAddress, final String macAddress) {
- Short tableId = null;
- List<Instruction> instructions = new ArrayList<>();
- List<Action> actions = getActions(ifaceMgrRpcService, extInterfaceName, ipAddress, macAddress);
- for (Iterator<Action> iterator = actions.iterator(); iterator.hasNext();) {
- org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = iterator
- .next().getAction();
- if (actionClass instanceof NxActionResubmitRpcAddGroupCase) {
- tableId = ((NxActionResubmitRpcAddGroupCase) actionClass).getNxResubmit().getTable();
- iterator.remove();
- break;
- }
- }
-
- instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, 0));
- // reset the split-horizon bit to allow traffic to be sent back to the
- // provider port
- instructions.add(
- new InstructionWriteMetadata(BigInteger.ZERO, MetaDataUtil.METADATA_MASK_SH_FLAG).buildInstruction(1));
-
- if (tableId != null) {
- // replace resubmit action with goto so it can co-exist with
- // write-metadata
- if (tableId > NwConstants.ARP_RESPONDER_TABLE) {
- instructions.add(new InstructionGotoTable(tableId).buildInstruction(2));
- } else {
- LOG.warn("Failed to insall responder flow for interface {}. Resubmit to {} can't be replaced with goto",
- extInterfaceName, tableId);
- }
- }
-
- return instructions;
- }
-
- /**
- * Install ARP Responder FLOW.
- *
- * @param mdSalManager
- * Reference of MDSAL API RPC that provides API for installing
- * flow
- * @param writeInvTxn
- * Write Transaction to write the flow
- * @param dpnId
- * DPN on which flow to be installed
- * @param flowId
- * Uniquely Identifiable Arp Responder Table flow Id
- * @param flowName
- * Readable flow name
- * @param priority
- * Flow Priority
- * @param cookie
- * Flow Cookie
- * @param matches
- * List of Match Criteria for the flow
- * @param instructions
- * List of Instructions for the flow
- */
- public static void installFlow(final IMdsalApiManager mdSalManager,
- final WriteTransaction writeInvTxn, final BigInteger dpnId,
- final String flowId, final String flowName,
- final int priority, final BigInteger cookie,
- List<MatchInfo> matches, List<Instruction> instructions) {
- final Flow flowEntity = MDSALUtil.buildFlowNew(
- NwConstants.ARP_RESPONDER_TABLE, flowId, priority, flowName, 0,
- 0, cookie, matches, instructions);
- mdSalManager.addFlowToTx(dpnId, flowEntity, writeInvTxn);
- }
-
- /**
- * Remove flow form DPN.
- *
- * @param mdSalManager Reference of MDSAL API RPC that provides API for installing flow
- * @param writeInvTxn Write Transaction to write the flow
- * @param dpnId DPN form which flow to be removed
- * @param flowId Uniquely Identifiable Arp Responder Table flow Id that is to be removed
- */
- public static void removeFlow(final IMdsalApiManager mdSalManager,
- final WriteTransaction writeInvTxn,
- final BigInteger dpnId, final String flowId) {
- final Flow flowEntity = MDSALUtil
- .buildFlow(NwConstants.ARP_RESPONDER_TABLE, flowId);
- mdSalManager.removeFlowToTx(dpnId, flowEntity, writeInvTxn);
- }
-
- /**
- * Creates Uniquely Identifiable flow Id.
- *
- * <p><b>Refer:</b> {@link ArpResponderConstant#FLOW_ID_FORMAT}
- *
- * @param lportTag LportTag of the flow
- * @param gwIp Gateway IP for which ARP Response flow to be installed
- * @return Unique Flow Id
- */
- public static String getFlowID(final int lportTag, final String gwIp) {
- return MessageFormat.format(ArpResponderConstant.FLOW_ID_FORMAT.value(),
- NwConstants.ARP_RESPONDER_TABLE, lportTag, gwIp);
- }
-
- /**
- * Generate Cookie per flow.
- *
- * <p>Cookie is generated by Summation of
- * {@link NwConstants#COOKIE_ARP_RESPONDER} + 1 + lportTag + Gateway IP
- *
- * @param lportTag Lport Tag of the flow
- * @param gwIp Gateway IP for which ARP Response flow to be installed
- * @return Cookie
- */
- public static BigInteger generateCookie(final long lportTag,
- final String gwIp) {
- LOG.trace("IPAddress in long {}", gwIp);
- return NwConstants.COOKIE_ARP_RESPONDER.add(BigInteger.ONE)
- .add(BigInteger.valueOf(lportTag))
- .add(BigInteger.valueOf(ipTolong(gwIp)));
- }
-
- /**
- * Get IP Address in Long from String.
- *
- * @param address IP Address that to be converted to long
- * @return Long value of the IP Address
- */
- private static long ipTolong(String address) {
-
- // Parse IP parts into an int array
- long[] ip = new long[4];
- String[] parts = address.split("\\.");
-
- for (int i = 0; i < 4; i++) {
- ip[i] = Long.parseLong(parts[i]);
- }
- // Add the above IP parts into an int number representing your IP
- // in a 32-bit binary form
- long ipNumbers = 0;
- for (int i = 0; i < 4; i++) {
- ipNumbers += ip[i] << (24 - (8 * i));
- }
- return ipNumbers;
-
- }
-
- /**
- * Get List of Egress Action for the VPN interface.
- *
- * @param ifaceMgrRpcService Interface Manager RPC reference that invokes API to retrieve Egress Action
- * @param ifName VPN Interface for which Egress Action to be retrieved
- * @param actionCounter Action Key
- * @return List of Egress Actions
- */
- public static List<Action> getEgressActionsForInterface(
- final OdlInterfaceRpcService ifaceMgrRpcService, String ifName,
- int actionCounter) {
- final List<Action> listActions = new ArrayList<>();
- try {
- final RpcResult<GetEgressActionsForInterfaceOutput> result = ifaceMgrRpcService
- .getEgressActionsForInterface(
- new GetEgressActionsForInterfaceInputBuilder()
- .setIntfName(ifName).build())
- .get();
- if (result.isSuccessful()) {
- final List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action>
- actions = result
- .getResult().getAction();
- for (final Action action : actions) {
-
- listActions
- .add(
- new org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list
- .ActionBuilder(
- action).setKey(new ActionKey(actionCounter))
- .setOrder(actionCounter++).build());
-
- }
- } else {
- LOG.warn(
- "RPC Call to Get egress actions for interface {} returned with Errors {}",
- ifName, result.getErrors());
- }
- } catch (InterruptedException | ExecutionException e) {
- LOG.warn("Exception when egress actions for interface {}", ifName,
- e);
- }
- return listActions;
- }
-
- /**
- * Uses the IdManager to retrieve ARP Responder GroupId from ELAN pool.
- *
- * @param idManager the id manager
- * @return the integer
- */
- public static Long retrieveStandardArpResponderGroupId(IdManagerService idManager) {
-
- AllocateIdInput getIdInput =
- new AllocateIdInputBuilder().setPoolName(ArpResponderConstant.ELAN_ID_POOL_NAME.value())
- .setIdKey(ArpResponderConstant.ARP_RESPONDER_GROUP_ID.value()).build();
-
- try {
- Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
- RpcResult<AllocateIdOutput> rpcResult = result.get();
- if (rpcResult.isSuccessful()) {
- LOG.trace("Retrieved Group Id is {}", rpcResult.getResult().getIdValue());
- return rpcResult.getResult().getIdValue();
- } else {
- LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
- }
- } catch (InterruptedException | ExecutionException e) {
- LOG.warn("Exception when Allocating Id", e);
- }
- return 0L;
- }
-
-}
<service ref="vpnFootprintService"
interface="org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService" />
+ <bean id="arpResponderHandler" class="org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler">
+ <argument ref="dataBroker" />
+ <argument ref="elanService" />
+ <argument ref="interfaceManager" />
+ </bean>
+
<bean id="vpnInterfaceManager"
class="org.opendaylight.netvirt.vpnmanager.VpnInterfaceManager"
init-method="start" destroy-method="close">
<argument ref="interfaceManager" />
<argument ref="vpnManager" />
<argument ref="interVpnLinkService" />
+ <argument ref="arpResponderHandler" />
</bean>
<bean id="interfaceStateChangeListener"
<argument ref="vpnInterfaceManager" />
<argument ref="mdsalUtils" />
<argument ref="vpnFootprintService" />
- <argument ref="odlInterfaceRpcService" />
<argument ref="elanService" />
+ <argument ref="interfaceManager" />
<argument ref="vpnSubnetRouteHandler" />
-
</bean>
<service ref="vpnManagerImpl"
interface="org.opendaylight.netvirt.vpnmanager.api.IVpnManager" />