DHCP Neutron Port ARP handling for SR-IOV VMs.
Handled removal of stale flows entry from ArpResponderTable.
New pipeline for processing Neutron port DHCP ARPs
Table 0 -> Table 18 -> Table 38 -> Table 81
Change-Id: Id5ee3160240cfcb6caec5790734d9f003c16640e
Signed-off-by: Achuth Maniyedath <achuth.maniyedath@gmail.com>
Signed-off-by: Vijayalakshmi Chickkamenahalli Nagaraju <vijayalakshmi.c@altencalsoftlabs.com>
int DEFAULT_DHCP_FLOW_PRIORITY = 50;
int DEFAULT_DHCP_ALLOCATION_POOL_FLOW_PRIORITY = DEFAULT_DHCP_FLOW_PRIORITY - 1;
+ int DEFAULT_DHCP_ARP_FLOW_PRIORITY = 10;
int ARP_FLOW_PRIORITY = 50;
short DEFAULT_FLOW_PRIORITY = 100;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+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.binding.InstanceIdentifier;
import org.slf4j.Logger;
del.getTunnelRemoteIpAddress(), del.getElanInstanceName());
dhcpExternalTunnelManager.unInstallDhcpFlowsForVms(del.getElanInstanceName(),
del.getTunnelRemoteIpAddress(), DhcpServiceUtils.getListOfDpns(broker));
+ LOG.trace("Removing designated DPN {} DHCP Arp Flows for Elan {}.", del.getDpId(), del.getElanInstanceName());
+ java.util.Optional<SubnetToDhcpPort> subnetDhcpData = dhcpExternalTunnelManager
+ .getSubnetDhcpPortData(del.getElanInstanceName());
+ if (subnetDhcpData.isPresent()) {
+ dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(BigInteger.valueOf(del.getDpId()),
+ del.getElanInstanceName(), false, del.getTunnelRemoteIpAddress(),
+ subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
+ }
+
}
@Override
protected void update(InstanceIdentifier<DesignatedSwitchForTunnel> identifier, DesignatedSwitchForTunnel original,
DesignatedSwitchForTunnel update) {
LOG.debug("Update for DesignatedSwitchForTunnel original {}, update {}", original, update);
+ dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()),
+ original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
BigInteger designatedDpnId = BigInteger.valueOf(update.getDpId());
IpAddress tunnelRemoteIpAddress = update.getTunnelRemoteIpAddress();
String elanInstanceName = update.getElanInstanceName();
- dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()),
- original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+ java.util.Optional<SubnetToDhcpPort> subnetDhcpData = dhcpExternalTunnelManager
+ .getSubnetDhcpPortData(elanInstanceName);
+ if (subnetDhcpData.isPresent()) {
+ LOG.trace("Removing Designated DPN {} DHCP Arp Flows for Elan {}.", original.getDpId(),
+ original.getElanInstanceName());
+ dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(BigInteger.valueOf(original.getDpId()),
+ original.getElanInstanceName(), false, original.getTunnelRemoteIpAddress(),
+ subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
+ LOG.trace("Configuring DHCP Arp Flows for Designated dpn {} Elan {}", designatedDpnId, elanInstanceName);
+ dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(designatedDpnId, elanInstanceName,
+ true, tunnelRemoteIpAddress, subnetDhcpData.get().getPortFixedip(),
+ subnetDhcpData.get().getPortMacaddress());
+ }
}
@Override
String elanInstanceName = add.getElanInstanceName();
dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
+ LOG.trace("Configuring DHCP Arp Flows for Designated dpn {} Elan {}", designatedDpnId, elanInstanceName);
+ java.util.Optional<SubnetToDhcpPort> subnetDhcpData = dhcpExternalTunnelManager
+ .getSubnetDhcpPortData(elanInstanceName);
+ if (subnetDhcpData.isPresent()) {
+ dhcpExternalTunnelManager.configureDhcpArpRequestResponseFlow(designatedDpnId, elanInstanceName,
+ true, tunnelRemoteIpAddress, subnetDhcpData.get().getPortFixedip(),
+ subnetDhcpData.get().getPortMacaddress());
+ }
}
@Override
import java.util.concurrent.Future;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+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.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.subnet.dhcp.port.data.SubnetToDhcpPort;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
private final IInterfaceManager interfaceManager;
private final JobCoordinator jobCoordinator;
private final L2GatewayCache l2GatewayCache;
+ private IElanService elanService;
private final ConcurrentMap<BigInteger, Set<Pair<IpAddress, String>>> designatedDpnsToTunnelIpElanNameCache =
new ConcurrentHashMap<>();
public DhcpExternalTunnelManager(final DataBroker broker,
final IMdsalApiManager mdsalUtil, final ItmRpcService itmRpcService,
final EntityOwnershipService entityOwnershipService, final IInterfaceManager interfaceManager,
- final JobCoordinator jobCoordinator, final L2GatewayCache l2GatewayCache) {
+ final JobCoordinator jobCoordinator, final L2GatewayCache l2GatewayCache,
+ @Named("elanService") IElanService ielanService) {
this.broker = broker;
this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
this.mdsalUtil = mdsalUtil;
this.interfaceManager = interfaceManager;
this.jobCoordinator = jobCoordinator;
this.l2GatewayCache = l2GatewayCache;
+ this.elanService = ielanService;
}
@PostConstruct
LOG.trace("Updating DHCP flows for VMs {} with new designated DPN {}", setOfVmMacs, newDesignatedDpn);
installDhcpFlowsForVms(newDesignatedDpn, setOfVmMacs, tx);
}
+ java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(pair.getRight());
+ if (subnetDhcpData.isPresent()) {
+ configureDhcpArpRequestResponseFlow(newDesignatedDpn, pair.getRight(), true,
+ pair.getLeft(), subnetDhcpData.get().getPortFixedip(), subnetDhcpData.get().getPortMacaddress());
+ }
}
private void changeExistingFlowToDrop(Pair<IpAddress, String> tunnelIpElanNamePair, BigInteger dpnId,
vmMacAddress, NwConstants.ADD_FLOW, mdsalUtil, tx);
}
+ public void addOrRemoveDhcpArpFlowforElan(String elanInstanceName, boolean addFlow, String dhcpIpAddress,
+ String dhcpMacAddress) {
+ LOG.trace("Configure DHCP SR-IOV Arp flows for Elan {} dpns .", elanInstanceName);
+ for (Entry<BigInteger, Set<Pair<IpAddress,String>>> entry : designatedDpnsToTunnelIpElanNameCache.entrySet()) {
+ BigInteger dpn = entry.getKey();
+ Set<Pair<IpAddress,String>> tunnelIpElanNameSet = entry.getValue();
+ for (Pair<IpAddress, String> pair : tunnelIpElanNameSet) {
+ if (pair.getRight().equalsIgnoreCase(elanInstanceName)) {
+ if (addFlow) {
+ LOG.trace("Adding SR-IOV DHCP Arp Flows for Elan {} and tunnelIp {}",
+ elanInstanceName, pair.getLeft());
+ configureDhcpArpRequestResponseFlow(dpn, elanInstanceName, true,
+ pair.getLeft(), dhcpIpAddress, dhcpMacAddress);
+ } else {
+ LOG.trace("Deleting SR-IOV DHCP Arp Flows for Elan {} and tunnelIp {}",
+ elanInstanceName, pair.getLeft());
+ configureDhcpArpRequestResponseFlow(dpn, elanInstanceName, false,
+ pair.getLeft(), dhcpIpAddress, dhcpMacAddress);
+ }
+ }
+ }
+ }
+ }
+
+
+ public void configureDhcpArpRequestResponseFlow(BigInteger dpnId, String elanInstanceName, boolean addFlow,
+ IpAddress tunnelIp, String dhcpIpAddress, String dhcpMacAddress) {
+ L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+ if (device == null) {
+ LOG.error("Unable to get L2Device for tunnelIp {} and elanInstanceName {}", tunnelIp,
+ elanInstanceName);
+ }
+ jobCoordinator.enqueueJob(getJobKey(elanInstanceName), () -> {
+ if (entityOwnershipUtils.isEntityOwner(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME)) {
+ String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(dpnId),
+ device.getHwvtepNodeId());
+ int lportTag = interfaceManager.getInterfaceInfo(tunnelInterfaceName).getInterfaceTag();
+ InstanceIdentifier<ElanInstance> elanIdentifier = InstanceIdentifier.builder(ElanInstances.class)
+ .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+ Optional<ElanInstance> optElan = MDSALUtil.read(broker,
+ LogicalDatastoreType.CONFIGURATION, elanIdentifier);
+ if (optElan.isPresent()) {
+ LOG.trace("Configuring the SR-IOV Arp request/response flows for LPort {} ElanTag {}.",
+ lportTag, optElan.get().getElanTag());
+ Uuid nwUuid = new Uuid(elanInstanceName);
+ String strVni = DhcpServiceUtils.getSegmentationId(nwUuid, broker);
+ BigInteger vni = strVni != null ? new BigInteger(strVni) : BigInteger.ZERO;
+ if (!vni.equals(BigInteger.ZERO)) {
+ if (addFlow) {
+ LOG.trace("Installing the SR-IOV DHCP Arp flow for DPN {} Port Ip {}, Lport {}.",
+ dpnId, dhcpIpAddress, lportTag);
+ installDhcpArpRequestFlows(dpnId, vni, dhcpIpAddress, lportTag,
+ optElan.get().getElanTag());
+ installDhcpArpResponderFlows(dpnId, tunnelInterfaceName, lportTag, elanInstanceName,
+ dhcpIpAddress, dhcpMacAddress);
+ } else {
+ LOG.trace("Uninstalling the SR-IOV DHCP Arp flows for DPN {} Port Ip {}, Lport {}.",
+ dpnId, dhcpIpAddress, lportTag);
+ uninstallDhcpArpRequestFlows(dpnId, vni, dhcpIpAddress, lportTag);
+ uninstallDhcpArpResponderFlows(dpnId, tunnelInterfaceName, lportTag, dhcpIpAddress);
+ }
+ }
+ }
+ }
+ return null;
+ });
+ }
+
+ public java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(String elanInstanceName) {
+ java.util.Optional<SubnetToDhcpPort> optSubnetDhcp = java.util.Optional.empty();
+ Uuid nwUuid = new Uuid(elanInstanceName);
+ List<Uuid> subnets = DhcpServiceUtils.getSubnetIdsFromNetworkId(broker, nwUuid);
+ for (Uuid subnet : subnets) {
+ if (DhcpServiceUtils.isIpv4Subnet(broker, subnet)) {
+ optSubnetDhcp = DhcpServiceUtils.getSubnetDhcpPortData(broker, subnet.getValue());
+ return optSubnetDhcp;
+ }
+ }
+ return optSubnetDhcp;
+ }
+
+ private void installDhcpArpRequestFlows(BigInteger dpnId, BigInteger vni, String dhcpIpAddress,
+ int lportTag, Long elanTag) {
+ DhcpServiceUtils.setupDhcpArpRequest(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, vni, dhcpIpAddress,
+ lportTag, elanTag, true, mdsalUtil);
+ }
+
+ private void installDhcpArpResponderFlows(BigInteger dpnId, String interfaceName, int lportTag,
+ String elanInstanceName, String dhcpIpAddress, String dhcpMacAddress) {
+ LOG.trace("Adding SR-IOV DHCP ArpResponder for elan {} Lport {} Port Ip {}.",
+ elanInstanceName, lportTag, dhcpIpAddress);
+ ArpResponderInput.ArpReponderInputBuilder builder = new ArpResponderInput.ArpReponderInputBuilder();
+ builder.setDpId(dpnId).setInterfaceName(interfaceName).setSpa(dhcpIpAddress).setSha(dhcpMacAddress)
+ .setLportTag(lportTag);
+ builder.setInstructions(ArpResponderUtil.getInterfaceInstructions(interfaceManager, interfaceName,
+ dhcpIpAddress, dhcpMacAddress));
+ elanService.addExternalTunnelArpResponderFlow(builder.buildForInstallFlow(), elanInstanceName);
+ }
+
+ private void uninstallDhcpArpResponderFlows(BigInteger dpnId, String interfaceName, int lportTag,
+ String dhcpIpAddress) {
+ LOG.trace("Removing SR-IOV DHCP ArpResponder flow for interface {} on DPN {}", interfaceName, dpnId);
+ ArpResponderInput arpInput = new ArpResponderInput.ArpReponderInputBuilder().setDpId(dpnId)
+ .setInterfaceName(interfaceName).setSpa(dhcpIpAddress)
+ .setLportTag(lportTag).buildForRemoveFlow();
+ elanService.removeArpResponderFlow(arpInput);
+ }
+
+ private void uninstallDhcpArpRequestFlows(BigInteger dpnId, BigInteger vni, String dhcpIpAddress,
+ int lportTag) {
+ DhcpServiceUtils.setupDhcpArpRequest(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE, vni, dhcpIpAddress,
+ lportTag, null, false, mdsalUtil);
+ }
+
+
public void unInstallDhcpEntries(BigInteger dpnId, String vmMacAddress, WriteTransaction tx) {
DhcpServiceUtils.setupDhcpFlowEntry(dpnId, NwConstants.DHCP_TABLE_EXTERNAL_TUNNEL,
vmMacAddress, NwConstants.DEL_FLOW, mdsalUtil, tx);
return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
for (Pair<IpAddress, String> tunnelElanPair : tunnelElanPairSet) {
IpAddress tunnelIpInDpn = tunnelElanPair.getLeft();
+ String elanInstanceName = tunnelElanPair.getRight();
if (tunnelIpInDpn.equals(tunnelIp)) {
if (!checkL2GatewayConnection(tunnelElanPair)) {
LOG.trace("Couldn't find device for given tunnelIpElanPair {} in L2GwConnCache",
List<BigInteger> dpns = DhcpServiceUtils.getListOfDpns(broker);
dpns.remove(interfaceDpn);
changeExistingFlowToDrop(tunnelElanPair, interfaceDpn, tx);
+ java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(elanInstanceName);
+ if (subnetDhcpData.isPresent()) {
+ configureDhcpArpRequestResponseFlow(interfaceDpn, elanInstanceName, false,
+ tunnelIpInDpn, subnetDhcpData.get().getPortFixedip(),
+ subnetDhcpData.get().getPortMacaddress());
+ }
updateCacheAndInstallNewFlows(interfaceDpn, dpns, tunnelElanPair, tx);
}
}
return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
for (Pair<IpAddress, String> pair : tunnelIpElanPair) {
if (tunnelIp.equals(pair.getLeft())) {
- BigInteger newDesignatedDpn = designateDpnId(tunnelIp, pair.getRight(), dpns);
+ String elanInstanceName = pair.getRight();
+ BigInteger newDesignatedDpn = designateDpnId(tunnelIp, elanInstanceName, dpns);
if (newDesignatedDpn != null && !newDesignatedDpn.equals(DhcpMConstants.INVALID_DPID)) {
Set<String> vmMacAddress = tunnelIpElanNameToVmMacCache.get(pair);
if (vmMacAddress != null && !vmMacAddress.isEmpty()) {
installDhcpFlowsForVms(newDesignatedDpn, vmMacAddress, tx);
}
}
+ java.util.Optional<SubnetToDhcpPort> subnetDhcpData = getSubnetDhcpPortData(elanInstanceName);
+ if (subnetDhcpData.isPresent()) {
+ configureDhcpArpRequestResponseFlow(newDesignatedDpn, elanInstanceName,
+ true, tunnelIp, subnetDhcpData.get().getPortFixedip(),
+ subnetDhcpData.get().getPortMacaddress());
+ }
}
}
}));
private final JobCoordinator jobCoordinator;
private final IInterfaceManager interfaceManager;
private final IElanService elanService;
+ private final DhcpPortCache dhcpPortCache;
public DhcpInterfaceEventListener(DhcpManager dhcpManager, DataBroker dataBroker,
DhcpExternalTunnelManager dhcpExternalTunnelManager,
IInterfaceManager interfaceManager, IElanService elanService,
- JobCoordinator jobCoordinator) {
+ DhcpPortCache dhcpPortCache, JobCoordinator jobCoordinator) {
super(Interface.class, DhcpInterfaceEventListener.class);
this.dhcpManager = dhcpManager;
this.dataBroker = dataBroker;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.interfaceManager = interfaceManager;
this.elanService = elanService;
+ this.dhcpPortCache = dhcpPortCache;
this.jobCoordinator = jobCoordinator;
registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
}
return;
}
String interfaceName = del.getName();
- Port port = dhcpManager.getNeutronPort(interfaceName);
+ Port port = dhcpPortCache.get(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, del, dpnId, interfaceManager, elanService);
+ dataBroker, del, dpnId, interfaceManager, elanService, port);
jobCoordinator.enqueueJob(DhcpServiceUtils.getJobKey(interfaceName), job, DhcpMConstants.RETRY_COUNT);
+ dhcpPortCache.remove(interfaceName);
}
@Override
if (NeutronConstants.IS_DHCP_PORT.test(port)) {
return;
}
-
+ dhcpPortCache.put(interfaceName, port);
NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
BigInteger dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
DhcpInterfaceAddJob job = new DhcpInterfaceAddJob(dhcpManager, dhcpExternalTunnelManager, dataBroker,
private final IInterfaceManager interfaceManager;
private final IElanService elanService;
private final JobCoordinator jobCoordinator;
+ private DhcpPortCache dhcpPortCache;
private volatile int dhcpOptLeaseTime = 0;
private volatile String dhcpOptDefDomainName;
final INeutronVpnManager neutronVpnManager,
final DhcpserviceConfig config, final DataBroker dataBroker,
final DhcpExternalTunnelManager dhcpExternalTunnelManager, final IInterfaceManager interfaceManager,
- final @Named("elanService") IElanService ielanService,
+ @Named("elanService") IElanService ielanService, final DhcpPortCache dhcpPortCache,
final JobCoordinator jobCoordinator) {
this.mdsalUtil = mdsalApiManager;
this.neutronVpnService = neutronVpnManager;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.interfaceManager = interfaceManager;
this.elanService = ielanService;
+ this.dhcpPortCache = dhcpPortCache;
this.jobCoordinator = jobCoordinator;
configureLeaseDuration(DhcpMConstants.DEFAULT_LEASE_TIME);
}
LOG.trace("Netvirt DHCP Manager Init .... {}",config.isControllerDhcpEnabled());
if (config.isControllerDhcpEnabled()) {
dhcpInterfaceEventListener = new DhcpInterfaceEventListener(this, broker, dhcpExternalTunnelManager,
- interfaceManager, elanService, jobCoordinator);
+ interfaceManager, elanService, dhcpPortCache, jobCoordinator);
dhcpInterfaceConfigListener = new DhcpInterfaceConfigListener(broker, dhcpExternalTunnelManager, this,
jobCoordinator);
LOG.info("DHCP Service initialized");
if (NeutronConstants.IS_ODL_DHCP_PORT.test(del)) {
jobCoordinator.enqueueJob(getJobKey(del),
() -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+ java.util.Optional<String> ip4Address = DhcpServiceUtils.getIpV4Address(del);
+ if (ip4Address.isPresent()) {
+ dhcpExternalTunnelManager.addOrRemoveDhcpArpFlowforElan(del.getNetworkId().getValue(),
+ false, ip4Address.get(), del.getMacAddress().getValue());
+ }
DhcpServiceUtils.removeSubnetDhcpPortData(del, subnetDhcpPortIdfr -> tx
.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());
+ LOG.trace("Removing ARPResponder Flows for dhcp port {} with ipaddress {} with mac {} "
+ + " on dpn {}. ",arpInput.getInterfaceName(), arpInput.getSpa(),
+ arpInput.getSha(), arpInput.getDpId());
elanService.removeArpResponderFlow(arpInput);
});
})));
elanService.addArpResponderFlow(builder.buildForInstallFlow());
});
})));
+ java.util.Optional<String> ip4Address = DhcpServiceUtils.getIpV4Address(add);
+ if (ip4Address.isPresent()) {
+ dhcpExternalTunnelManager.addOrRemoveDhcpArpFlowforElan(add.getNetworkId().getValue(),
+ true, ip4Address.get(), add.getMacAddress().getValue());
+ }
}
if (!isVnicTypeDirectOrMacVtap(add)) {
return;
LOG.error("Failed to get interface info for interface name {}", interfaceName);
return;
}
- Port port = getNeutronPort(interfaceName);
+ Port port;
+ if (tunnelId != null) {
+ port = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
+ } else {
+ port = getNeutronPort(interfaceName);
+ }
Subnet subnet = getNeutronSubnet(port);
- //When neutronport-dhcp flag is disabled continue running DHCP Server by hijacking the subnet-gateway-ip
String serverMacAddress = interfaceInfo.getMacAddress();
String serverIp = null;
if (subnet != null) {
java.util.Optional<SubnetToDhcpPort> dhcpPortData = DhcpServiceUtils
.getSubnetDhcpPortData(broker, subnet.getUuid().getValue());
- /* 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 enable_dhcp_service 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 (dhcpPortData.isPresent()) {
serverIp = dhcpPortData.get().getPortFixedip();
return;
}
}
- DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, tunnelId, port, subnet, serverIp);
+ DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName, macAddress, port, subnet, serverIp);
+ if (replyPkt == null) {
+ LOG.warn("Unable to construct reply packet for interface name {}", interfaceName);
+ return;
+ }
byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, serverMacAddress);
sendPacketOut(pktOut, interfaceInfo.getDpId(), interfaceName, tunnelId);
}
JdkFutures.addErrorLogging(pktService.transmitPacket(output), LOG, "Transmit packet");
}
- private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, BigInteger tunnelId,
- Port interfacePort, Subnet subnet, String serverIp) {
+ private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName, String macAddress, Port interfacePort,
+ Subnet subnet, String serverIp) {
LOG.trace("DHCP pkt rcvd {}", dhcpPkt);
byte msgType = dhcpPkt.getMsgType();
- Port port;
- if (tunnelId != null) {
- port = dhcpExternalTunnelManager.readVniMacToPortCache(tunnelId, macAddress);
- } else {
- port = interfacePort;
- }
DhcpInfo dhcpInfo = null;
- if (port != null) {
- dhcpInfo = handleDhcpNeutronPacket(msgType, port, subnet, serverIp);
+ if (interfacePort != null) {
+ dhcpInfo = handleDhcpNeutronPacket(msgType, interfacePort, subnet, serverIp);
} else if (config.isDhcpDynamicAllocationPoolEnabled()) {
dhcpInfo = handleDhcpAllocationPoolPacket(msgType, dhcpPkt, interfaceName, macAddress);
}
--- /dev/null
+/*
+ * Copyright © 2015, 2018 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.dhcpservice;
+
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PostConstruct;
+import javax.inject.Singleton;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class DhcpPortCache {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DhcpPortCache.class);
+ private final ConcurrentHashMap<String, Port> portMap = new ConcurrentHashMap<String, Port>();
+
+ @PostConstruct
+ public void init() {
+ LOG.trace("Initialize DhcpPortCache. ");
+ }
+
+ public void put(@Nonnull String interfaceName, Port port) {
+ portMap.put(interfaceName, port);
+ LOG.trace("Added the interface {} to DhcpPortCache",interfaceName);
+ }
+
+ @Nullable
+ public Port get(@Nonnull String interfaceName) {
+ return portMap.get(interfaceName);
+ }
+
+ public void remove(@Nonnull String interfaceName) {
+ portMap.remove(interfaceName);
+ }
+}
import com.google.common.base.Optional;
import com.google.common.util.concurrent.FutureCallback;
import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.opendaylight.genius.mdsalutil.MDSALDataStoreUtils;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
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.MatchArpTpa;
import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
import org.opendaylight.genius.utils.ServiceIndex;
import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
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.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
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.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.interfacemanager.servicebinding.rev160406.ServiceBindings;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
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.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
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.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.neutron.subnets.rev150712.subnets.attributes.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
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._interface.name.mac.addresses.InterfaceNameMacAddress;
.append(vmMacAddress).toString();
}
+ private static String getDhcpArpFlowRef(BigInteger dpId, long tableId, long lportTag, String ipAddress) {
+ return new StringBuffer().append(DhcpMConstants.FLOWID_PREFIX)
+ .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(lportTag).append(NwConstants.FLOWID_SEPARATOR)
+ .append(ipAddress).toString();
+ }
+
public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove,
IMdsalApiManager mdsalUtil, WriteTransaction tx) {
if (dpId == null || dpId.equals(DhcpMConstants.INVALID_DPID) || vmMacAddress == null) {
}
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static void setupDhcpArpRequest(BigInteger dpId, short tableId, BigInteger vni, String dhcpIpAddress,
+ int lportTag, Long elanTag, boolean add, IMdsalApiManager mdsalUtil) {
+ List<MatchInfo> matches = getDhcpArpMatch(vni, dhcpIpAddress);
+ if (add) {
+ Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
+ DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
+ generateDhcpArpCookie(lportTag, dhcpIpAddress), matches, null);
+ LOG.trace("Removing DHCP ARP Flow DpId {}, DHCP Port IpAddress {}", dpId, dhcpIpAddress);
+ mdsalUtil.removeFlow(dpId, flow);
+ } else {
+ Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
+ DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
+ generateDhcpArpCookie(lportTag, dhcpIpAddress), matches,
+ getDhcpArpInstructions(elanTag, lportTag));
+ LOG.trace("Adding DHCP ARP Flow DpId {}, DHCPPort IpAddress {}", dpId, dhcpIpAddress);
+ mdsalUtil.installFlow(dpId, flow);
+ }
+ }
+
public static List<MatchInfo> getDhcpMatch() {
List<MatchInfo> matches = new ArrayList<>();
matches.add(MatchEthernetType.IPV4);
return matches;
}
- @Nonnull
+ private static List<MatchInfo> getDhcpArpMatch(BigInteger vni, String ipAddress) {
+ return Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST, new MatchTunnelId(vni),
+ new MatchArpTpa(ipAddress, "32"));
+ }
+
+ private static List<Instruction> getDhcpArpInstructions(Long elanTag, int lportTag) {
+ List<Instruction> mkInstructions = new ArrayList<>();
+ int instructionKey = 0;
+ mkInstructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(
+ ElanHelper.getElanMetadataLabel(elanTag, lportTag), ElanHelper.getElanMetadataMask(),
+ ++instructionKey));
+ mkInstructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_RESPONDER_TABLE,
+ ++instructionKey));
+ return mkInstructions;
+ }
+
+ private static BigInteger generateDhcpArpCookie(int lportTag, String ipAddress) {
+ try {
+ BigInteger cookie = NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(255))
+ .add(BigInteger.valueOf(NWUtil.convertInetAddressToLong(InetAddress.getByName(ipAddress))));
+ return cookie.add(BigInteger.valueOf(lportTag));
+ } catch (UnknownHostException e) {
+ return NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(lportTag));
+ }
+ }
+
public static List<BigInteger> getListOfDpns(DataBroker broker) {
return extractDpnsFromNodes(MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
InstanceIdentifier.builder(Nodes.class).build()));
return null;
}
+ public static List<Uuid> getSubnetIdsFromNetworkId(DataBroker broker, Uuid networkId) {
+ InstanceIdentifier id = buildNetworkMapIdentifier(networkId);
+ Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+ if (optionalNetworkMap.isPresent()) {
+ return optionalNetworkMap.get().getSubnetIdList();
+ }
+ return null;
+ }
+
+ static InstanceIdentifier<NetworkMap> buildNetworkMapIdentifier(Uuid networkId) {
+ InstanceIdentifier<NetworkMap> id = InstanceIdentifier.builder(NetworkMaps.class).child(NetworkMap.class, new
+ NetworkMapKey(networkId)).build();
+ return id;
+ }
+
+ public static boolean isIpv4Subnet(DataBroker broker, Uuid subnetUuid) {
+ final SubnetKey subnetkey = new SubnetKey(subnetUuid);
+ final InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
+ .child(Subnets.class).child(Subnet.class, subnetkey);
+ final Optional<Subnet> subnet = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetidentifier);
+ if (subnet.isPresent()) {
+ Class<? extends IpVersionBase> ipVersionBase = subnet.get().getIpVersion();
+ if (ipVersionBase.equals(IpVersionV4.class)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
+
private final BigInteger dpnId;
private final IInterfaceManager interfaceManager;
private final IElanService elanService;
+ private final Port port;
public DhcpInterfaceRemoveJob(DhcpManager dhcpManager, DhcpExternalTunnelManager dhcpExternalTunnelManager,
DataBroker dataBroker,
Interface interfaceDel, BigInteger dpnId, IInterfaceManager interfaceManager,
- IElanService elanService) {
+ IElanService elanService, Port port) {
this.dhcpManager = dhcpManager;
this.dhcpExternalTunnelManager = dhcpExternalTunnelManager;
this.dataBroker = dataBroker;
this.dpnId = dpnId;
this.interfaceManager = interfaceManager;
this.elanService = elanService;
+ this.port = port;
}
@Override
// Support for VM migration use cases.
futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
tx -> DhcpServiceUtils.unbindDhcpService(interfaceName, tx)));
- Port port = dhcpManager.getNeutronPort(interfaceName);
java.util.Optional<String> subnetId = DhcpServiceUtils.getNeutronSubnetId(port);
if (subnetId.isPresent()) {
java.util.Optional<SubnetToDhcpPort> subnetToDhcp = DhcpServiceUtils.getSubnetDhcpPortData(dataBroker,
*/
void addArpResponderFlow(ArpResponderInput arpResponderInput);
+ /**
+ * Add ARP Responder Flow on the given dpn for the SR-IOV VMs ingress interface.
+ *
+ * @param arpResponderInput
+ * ArpResponder Input parameters
+ * @see ArpResponderInput
+ * @param elanInstanceName
+ * The elanInstance corresponding to the interface
+ */
+ void addExternalTunnelArpResponderFlow(ArpResponderInput arpResponderInput, String elanInstanceName);
+
/**
* Remove ARP Responder flow from the given dpn for the ingress interface.
*
arpResponderInput.getInstructions());
}
+ @Override
+ public void addExternalTunnelArpResponderFlow(ArpResponderInput arpResponderInput, String elanInstanceName) {
+ elanUtils.addExternalTunnelArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getSpa(),
+ arpResponderInput.getSha(), arpResponderInput.getLportTag(),
+ arpResponderInput.getInstructions(), elanInstanceName);
+ }
+
@Override
public void removeArpResponderFlow(ArpResponderInput arpResponderInput) {
elanUtils.removeArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName);
}
+ public void addExternalTunnelArpResponderFlow(BigInteger dpnId, String ipAddress, String macAddress,
+ int lportTag, List<Instruction> instructions, String elanInstanceName) {
+ LOG.trace("Installing the ExternalTunnel ARP responder flow on DPN {} for ElanInstance {} with MAC {} & IP {}",
+ dpnId, elanInstanceName, macAddress, ipAddress);
+ ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName);
+ 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.trace("Installed the ExternalTunnel ARP Responder flow for ElanInstance {}", elanInstanceName);
+ }
+
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,