&& !dpnIfaceInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)
&& dpnIfaceInfo.getDpId() != null) {
ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(), elanTag,
- ipv6Address.getValue(), Ipv6ServiceConstants.ADD_FLOW);
+ ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
} else if (action == Ipv6ServiceConstants.DEL_FLOW
&& dpnIfaceInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)) {
ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(), elanTag,
- ipv6Address.getValue(), Ipv6ServiceConstants.DEL_FLOW);
+ ipv6Address, Ipv6ServiceConstants.DEL_FLOW);
dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
}
}
for (Ipv6Address ipv6Address : routerPort.getIpv6Addresses()) {
if (!dpnInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)) {
ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
- elanTag, ipv6Address.getValue(), Ipv6ServiceConstants.ADD_FLOW);
+ elanTag, ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
dpnInfo.updateNDTargetAddress(ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
}
}
for (Ipv6Address ipv6Address : dpnIfaceInfo.ndTargetFlowsPunted) {
if (ipv6ServiceEosHandler.isClusterOwner()) {
ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
- elanTag, ipv6Address.getValue(), Ipv6ServiceConstants.DEL_FLOW);
+ elanTag, ipv6Address, Ipv6ServiceConstants.DEL_FLOW);
}
dpnIfaceInfo.updateNDTargetAddress(ipv6Address, Ipv6ServiceConstants.DEL_ENTRY);
}
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.opendaylight.genius.ipv6util.api.Ipv6Util;
import org.opendaylight.netvirt.ipv6service.api.IVirtualNetwork;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceConstants;
-import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
}
public void updateNDTargetAddress(Ipv6Address ipv6Address, int addOrRemove) {
- Ipv6Address ipv6 =
- Ipv6Address.getDefaultInstance(Ipv6ServiceUtils.getFormattedIpv6Address(ipv6Address.getValue()));
+ Ipv6Address ipv6 = Ipv6Address.getDefaultInstance(Ipv6Util.getFormattedIpv6Address(ipv6Address));
if (addOrRemove == Ipv6ServiceConstants.ADD_ENTRY) {
this.ndTargetFlowsPunted.add(ipv6);
} else {
}
public boolean isNdTargetFlowAlreadyConfigured(Ipv6Address ipv6Address) {
- Ipv6Address ipv6 =
- Ipv6Address.getDefaultInstance(Ipv6ServiceUtils.getFormattedIpv6Address(ipv6Address.getValue()));
+ Ipv6Address ipv6 = Ipv6Address.getDefaultInstance(Ipv6Util.getFormattedIpv6Address(ipv6Address));
return this.ndTargetFlowsPunted.contains(ipv6);
}
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.ipv6util.api.Icmpv6Type;
import org.opendaylight.genius.ipv6util.api.Ipv6Constants;
+import org.opendaylight.genius.ipv6util.api.Ipv6Util;
import org.opendaylight.genius.mdsalutil.ActionInfo;
import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
.append(flowType).toString();
}
- /**
- * Gets the formatted IPv6 address. <br>
- * e.g., <br>
- * 1. input = "1001:db8:0:2::1", return = "1001:db8:0:2:0:0:0:1" <br>
- * 2. input = "2607:f0d0:1002:51::4", return = "2607:f0d0:1002:51:0:0:0:4" <br>
- * 3. input = "1001:db8:0:2:0:0:0:1", return = "1001:db8:0:2:0:0:0:1"
- *
- * @param ipv6Address the ipv6 address
- * @return the formatted ipv6 address
- */
- public static String getFormattedIpv6Address(String ipv6Address) {
- try {
- return InetAddress.getByName(ipv6Address).getHostAddress();
- } catch (UnknownHostException e) {
- LOG.warn("Unknown host {}", ipv6Address, e);
- return null;
- }
- }
-
- public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, String ipv6Address,
+ public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, Ipv6Address ipv6Address,
int addOrRemove) {
- List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
+ List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address.getValue());
List<InstructionInfo> instructions = new ArrayList<>();
List<ActionInfo> actionsInfos = new ArrayList<>();
actionsInfos.add(new ActionPuntToController());
instructions.add(new InstructionApplyActions(actionsInfos));
- String formattedIp = getFormattedIpv6Address(ipv6Address);
+ String formattedIp = Ipv6Util.getFormattedIpv6Address(ipv6Address);
FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, getIPv6FlowRef(dpId, elanTag, formattedIp),
Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE,
neighborSolicitationMatch, instructions);
}
}
- public Optional<IpAddress> getIpv4GatewayAddressFromInterface(String srcInterface) {
+ public Optional<IpAddress> getGatewayIpAddressFromInterface(MacEntry macEntry) {
Optional<IpAddress> gatewayIp = Optional.absent();
+ String srcInterface = macEntry.getInterfaceName();
+ InetAddress hiddenIp = macEntry.getIpAddress();
if (neutronVpnService != null) {
//TODO(Gobinath): Need to fix this as assuming port will belong to only one Subnet would be incorrect"
Port port = neutronVpnService.getNeutronPort(srcInterface);
if (port != null && port.getFixedIps() != null) {
- for (FixedIps portIp: port.getFixedIps()) {
- if (portIp.getIpAddress().getIpv6Address() != null) {
- // Skip IPv6 address
- continue;
+ for (FixedIps portIp : port.getFixedIps()) {
+ if (doesInterfaceAndHiddenIpAddressTypeMatch(hiddenIp, portIp)) {
+ gatewayIp =
+ Optional.of(neutronVpnService.getNeutronSubnet(portIp.getSubnetId()).getGatewayIp());
+ break;
}
- gatewayIp = Optional.of(
- neutronVpnService.getNeutronSubnet(portIp.getSubnetId()).getGatewayIp());
}
}
} else {
return gatewayIp;
}
+ private boolean doesInterfaceAndHiddenIpAddressTypeMatch(InetAddress hiddenIp, FixedIps portIp) {
+ return (hiddenIp instanceof Inet4Address && portIp.getIpAddress().getIpv4Address() != null)
+ || hiddenIp instanceof Inet6Address && portIp.getIpAddress().getIpv6Address() != null;
+ }
+
public Optional<String> getGWMacAddressFromInterface(MacEntry macEntry, IpAddress gatewayIp) {
Optional<String> gatewayMac = Optional.absent();
long vpnId = getVpnId(macEntry.getVpnName());
return gatewayMac;
}
VpnPortipToPort vpnTargetIpToPort = getNeutronPortFromVpnPortFixedIp(macEntry.getVpnName(),
- gatewayIp.getIpv4Address().getValue());
+ String.valueOf(gatewayIp.getValue()));
if (vpnTargetIpToPort != null && vpnTargetIpToPort.isSubnetIp()) {
gatewayMac = Optional.of(vpnTargetIpToPort.getMacAddress());
} else {
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput.ArpReponderInputBuilder;
import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
import org.opendaylight.netvirt.elanmanager.api.IElanService;
gatewayIp = gwIpOptional.get();
}
}
- if (gatewayIp != null) {
+ if (gatewayIp != null && NWUtil.isIpv4Address(gatewayIp)) {
ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
builder.setDpId(dpId).setInterfaceName(ifName).setSpa(gatewayIp).setLportTag(lportTag);
elanService.removeArpResponderFlow(builder.buildForRemoveFlow());
this.config = vpnConfig;
this.vpnUtil = vpnUtil;
- long duration = config.getArpLearnTimeout() * 10;
- long cacheSize = config.getArpCacheSize().longValue();
+ long duration = config.getIpLearnTimeout() * 10;
+ long cacheSize = config.getMigrateIpCacheSize().longValue();
migrateIpCache =
CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(duration,
TimeUnit.MILLISECONDS).build();
}
private void putVpnIpToMigrateIpCache(String vpnName, String ipToQuery, MacAddress srcMac) {
- long cacheSize = config.getArpCacheSize().longValue();
+ long cacheSize = config.getMigrateIpCacheSize().longValue();
if (migrateIpCache.size() >= cacheSize) {
LOG.debug("IP_MIGRATE_CACHE: max size {} reached, assuming cache eviction we still put IP {}"
+ " vpnName {} with MAC {}", cacheSize, ipToQuery, vpnName, srcMac);
ipToQuery, vpnName);
return false;
}
- if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getArpLearnTimeout()) {
+ if (System.currentTimeMillis() > prevTimeStampCached.longValue() + config.getIpLearnTimeout()) {
LOG.debug("IP_MIGRATE_CACHE: older than timeout value - remove from dirty cache IP {} vpnName {}",
ipToQuery, vpnName);
migrateIpCache.invalidate(keyPair);
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.Profile;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.ProfileBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.start.input.ConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.config.rev161130.VpnConfig;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final AlivenessMonitorService alivenessManager;
private final IInterfaceManager interfaceManager;
private final VpnUtil vpnUtil;
+ private final VpnConfig vpnConfig;
@Inject
public AlivenessMonitorUtils(DataBroker dataBroker, VpnUtil vpnUtil, INeutronVpnManager neutronvpnService,
- AlivenessMonitorService alivenessManager, IInterfaceManager interfaceManager) {
+ AlivenessMonitorService alivenessManager, IInterfaceManager interfaceManager, VpnConfig vpnConfig) {
this.dataBroker = dataBroker;
this.vpnUtil = vpnUtil;
this.neutronvpnService = neutronvpnService;
this.alivenessManager = alivenessManager;
this.interfaceManager = interfaceManager;
+ this.vpnConfig = vpnConfig;
}
void startIpMonitoring(MacEntry macEntry, Long ipMonitorProfileId) {
return;
}
Optional<IpAddress> gatewayIpOptional =
- vpnUtil.getIpv4GatewayAddressFromInterface(macEntry.getInterfaceName());
+ vpnUtil.getGatewayIpAddressFromInterface(macEntry);
if (!gatewayIpOptional.isPresent()) {
- LOG.info("Interface{} does not have an IPv4 GatewayIp", macEntry.getInterfaceName());
+ LOG.info("Interface{} does not have an GatewayIp", macEntry.getInterfaceName());
return;
}
final IpAddress gatewayIp = gatewayIpOptional.get();
private Optional<Long> allocateIpMonitorProfile(IpAddress targetIp) {
Optional<Long> profileIdOptional = Optional.absent();
if (targetIp.getIpv4Address() != null) {
- profileIdOptional = allocateProfile(ArpConstants.FAILURE_THRESHOLD,
- ArpConstants.ARP_CACHE_TIMEOUT_MILLIS, ArpConstants.MONITORING_WINDOW, EtherTypes.Arp);
+ profileIdOptional = allocateArpMonitorProfile();
} else if (targetIp.getIpv6Address() != null) {
- // TODO: handle IPv6 case
- LOG.warn("allocateIpMonitorProfile: IPv6 address monitoring is not yet supported. targetIp={}", targetIp);
+ profileIdOptional = allocateIpv6NaMonitorProfile();
}
return profileIdOptional;
}
+ public Optional<Long> allocateArpMonitorProfile() {
+ return allocateProfile(ArpConstants.FAILURE_THRESHOLD, ArpConstants.ARP_CACHE_TIMEOUT_MILLIS,
+ ArpConstants.MONITORING_WINDOW, EtherTypes.Arp);
+ }
+
+ public Optional<Long> allocateIpv6NaMonitorProfile() {
+ Long monitorInterval = vpnConfig.getIpv6NdMonitorInterval() * 1000; // converting to milliseconds
+ return allocateProfile(vpnConfig.getIpv6NdMonitorFailureThreshold(), monitorInterval,
+ vpnConfig.getIpv6NdMonitorWindow(), EtherTypes.Ipv6Nd);
+ }
+
public Optional<Long> allocateProfile(long failureThreshold, long monitoringInterval, long monitoringWindow,
EtherTypes etherTypes) {
MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder()
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.genius.arputil.api.ArpConstants;
import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.netvirt.vpnmanager.iplearn.model.MacEntry;
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.alivenessmonitor.rev160411.AlivenessMonitorService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
private final VpnUtil vpnUtil;
private Optional<Long> arpMonitorProfileId = Optional.absent();
+ private Optional<Long> ipv6NdMonitorProfileId = Optional.absent();
private EntityOwnershipCandidateRegistration candidateRegistration;
@Inject
@PostConstruct
public void start() {
- Optional<Long> profileIdOptional = alivenessMonitorUtils.allocateProfile(ArpConstants.FAILURE_THRESHOLD,
- ArpConstants.ARP_CACHE_TIMEOUT_MILLIS, ArpConstants.MONITORING_WINDOW, EtherTypes.Arp);
- if (profileIdOptional.isPresent()) {
- arpMonitorProfileId = profileIdOptional;
- } else {
- LOG.error("Error while allocating Profile Id {}", profileIdOptional);
+ this.arpMonitorProfileId = alivenessMonitorUtils.allocateArpMonitorProfile();
+ this.ipv6NdMonitorProfileId = alivenessMonitorUtils.allocateIpv6NaMonitorProfile();
+ if (this.arpMonitorProfileId == null || this.ipv6NdMonitorProfileId == null) {
+ LOG.error("Error while allocating ARP and IPv6 ND Profile Ids: ARP={}, IPv6ND={}", arpMonitorProfileId,
+ ipv6NdMonitorProfileId);
}
registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
if (NWUtil.isIpv4Address(ipAddress)) {
return this.arpMonitorProfileId;
} else {
- // TODO: Handle for IPv6 case
- LOG.warn("IPv6 address monitoring is not yet supported - getMonitorProfileId(). ipAddress={}", ipAddress);
- return Optional.absent();
+ return this.ipv6NdMonitorProfileId;
}
}
}
<vpnmanager-config xmlns="urn:opendaylight:netvirt:vpn:config">
- <arp-cache-size>10000</arp-cache-size>
- <arp-learn-timeout>2000</arp-learn-timeout>
+ <migrate-ip-cache-size>10000</migrate-ip-cache-size>
+ <ip-learn-timeout>2000</ip-learn-timeout>
<subnet-route-punt-timeout>10</subnet-route-punt-timeout>
+ <ipv6-nd-monitor-failure-threshold>2</ipv6-nd-monitor-failure-threshold>
+ <ipv6-nd-monitor-interval>120</ipv6-nd-monitor-interval>
+ <ipv6-nd-monitor-window>4</ipv6-nd-monitor-window>
</vpnmanager-config>
"Initial revision";
}
-
container vpn-config {
config true;
- leaf arp-cache-size {
- description "arp cache size";
+ leaf migrate-ip-cache-size {
+ description "Migrate IP cache size";
type uint64;
default 10000;
}
- leaf arp-learn-timeout {
- description "arp learning timeout value (unit - ms)";
+ leaf ip-learn-timeout {
+ description "IP learning timeout value (unit - ms)";
type uint32;
default 2000;
}
type uint32;
default 10;
}
+ leaf ipv6-nd-monitor-failure-threshold {
+ description "IPv6 ND monitor failure threshold";
+ type uint32;
+ default 2;
+ }
+ leaf ipv6-nd-monitor-interval {
+ description "IPv6 ND monitor interval (unit - secs)";
+ type uint32;
+ default 120;
+ }
+ leaf ipv6-nd-monitor-window {
+ description "IPv6 ND monitor window";
+ type uint32;
+ default 4;
+ }
}
}