package org.opendaylight.netvirt.ipv6service;
+import com.google.common.collect.Lists;
import com.google.common.net.InetAddresses;
import io.netty.util.Timeout;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.ipv6util.api.Ipv6Constants.Ipv6RouterAdvertisementType;
+import org.opendaylight.genius.ipv6util.api.Ipv6Util;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.netvirt.elanmanager.api.IElanService;
import org.opendaylight.netvirt.ipv6service.api.IVirtualPort;
import org.opendaylight.netvirt.ipv6service.api.IVirtualRouter;
import org.opendaylight.netvirt.ipv6service.api.IVirtualSubnet;
-import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
-import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants.Ipv6RtrAdvertType;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6PeriodicTrQueue;
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceConstants;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6TimerWheel;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
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.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.action.types.rev131112.action.list.Action;
+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.GetInterfaceFromIfIndexInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
-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.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final ConcurrentMap<Uuid, VirtualSubnet> vsubnets = new ConcurrentHashMap<>();
private final ConcurrentMap<Uuid, VirtualPort> vintfs = new ConcurrentHashMap<>();
private final ConcurrentMap<Uuid, VirtualPort> vrouterv6IntfMap = new ConcurrentHashMap<>();
- private final ConcurrentMap<Uuid, List<VirtualPort>> unprocessedRouterIntfs = new ConcurrentHashMap<>();
- private final ConcurrentMap<Uuid, List<VirtualPort>> unprocessedSubnetIntfs = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Uuid, Set<VirtualPort>> unprocessedRouterIntfs = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Uuid, Set<VirtualPort>> unprocessedSubnetIntfs = new ConcurrentHashMap<>();
+ private static ConcurrentMap<Uuid, Set<VirtualPort>> unprocessedNetIntfs = new ConcurrentHashMap<>();
+ private static ConcurrentMap<Uuid, Integer> unprocessedNetRSFlowIntfs = new ConcurrentHashMap<>();
+ private static ConcurrentMap<Uuid, Set<Ipv6Address>> unprocessedNetNSFlowIntfs = new ConcurrentHashMap<>();
private final OdlInterfaceRpcService interfaceManagerRpc;
private final IElanService elanProvider;
private final Ipv6ServiceUtils ipv6ServiceUtils;
@Inject
public IfMgr(DataBroker dataBroker, IElanService elanProvider, OdlInterfaceRpcService interfaceManagerRpc,
- PacketProcessingService packetService, Ipv6ServiceUtils ipv6ServiceUtils,
- Ipv6ServiceEosHandler ipv6ServiceEosHandler) {
+ PacketProcessingService packetService, Ipv6ServiceUtils ipv6ServiceUtils,
+ Ipv6ServiceEosHandler ipv6ServiceEosHandler) {
this.dataBroker = dataBroker;
this.elanProvider = elanProvider;
this.interfaceManagerRpc = interfaceManagerRpc;
VirtualRouter rtr = VirtualRouter.builder().routerUUID(rtrUuid).tenantID(tenantId).name(rtrName).build();
vrouters.put(rtrUuid, rtr);
- List<VirtualPort> intfList = unprocessedRouterIntfs.remove(rtrUuid);
+ Set<VirtualPort> intfList = unprocessedRouterIntfs.remove(rtrUuid);
if (intfList == null) {
LOG.debug("No unprocessed interfaces for the router {}", rtrUuid);
return;
vsubnets.put(snetId, snet);
- List<VirtualPort> intfList = unprocessedSubnetIntfs.remove(snetId);
+ Set<VirtualPort> intfList = unprocessedSubnetIntfs.remove(snetId);
if (intfList == null) {
LOG.debug("No unprocessed interfaces for the subnet {}", snetId);
return;
if (rtr != null) {
rtr.addSubnet(snet);
}
+ updateInterfaceDpidOfPortInfo(intf.getIntfUUID());
}
}
}
Uuid networkId, IpAddress fixedIp, String macAddress,
String deviceOwner) {
LOG.debug("addRouterIntf portId {}, rtrId {}, snetId {}, networkId {}, ip {}, mac {}",
- portId, rtrId, snetId, networkId, fixedIp, macAddress);
+ portId, rtrId, snetId, networkId, fixedIp, macAddress);
//Save the interface ipv6 address in its fully expanded format
Ipv6Address addr = new Ipv6Address(InetAddresses
.forString(fixedIp.getIpv6Address().getValue()).getHostAddress());
if (prevIntf == null) {
newIntf = true;
MacAddress ifaceMac = MacAddress.getDefaultInstance(macAddress);
- Ipv6Address llAddr = ipv6ServiceUtils.getIpv6LinkLocalAddressFromMac(ifaceMac);
+ Ipv6Address llAddr = Ipv6Util.getIpv6LinkLocalAddressFromMac(ifaceMac);
/* A new router interface is created. This is basically triggered when an
IPv6 subnet is associated to the router. Check if network is already hosting
any VMs. If so, on all the hosts that have VMs on the network, program the
icmpv6 punt flows in IPV6_TABLE(45).
*/
- programIcmpv6RSPuntFlows(intf, Ipv6Constants.ADD_FLOW);
- programIcmpv6NSPuntFlowForAddress(intf, llAddr, Ipv6Constants.ADD_FLOW);
+ programIcmpv6RSPuntFlows(intf.getNetworkID(), Ipv6ServiceConstants.ADD_FLOW);
+ programIcmpv6NSPuntFlowForAddress(intf.getNetworkID(), llAddr, Ipv6ServiceConstants.ADD_FLOW);
+ programIcmpv6NaForwardFlows(intf, snetId, Ipv6ServiceConstants.ADD_FLOW);
} else {
intf = prevIntf;
intf.setSubnetInfo(snetId, fixedIp);
vrouterv6IntfMap.put(networkId, intf);
}
- programIcmpv6NSPuntFlowForAddress(intf, fixedIp.getIpv6Address(), Ipv6Constants.ADD_FLOW);
+ programIcmpv6NSPuntFlowForAddress(intf.getNetworkID(), fixedIp.getIpv6Address(), Ipv6ServiceConstants.ADD_FLOW);
+ programIcmpv6NaPuntFlow(networkId, intf.getSubnets(), Ipv6ServiceConstants.ADD_FLOW);
if (newIntf) {
LOG.debug("start the periodic RA Timer for routerIntf {}", portId);
}
}
- public void updateRouterIntf(Uuid portId, Uuid rtrId, List<FixedIps> fixedIpsList) {
+ public void updateRouterIntf(Uuid portId, Uuid rtrId, List<FixedIps> fixedIpsList, Set<FixedIps> deletedIps) {
LOG.info("updateRouterIntf portId {}, fixedIpsList {} ", portId, fixedIpsList);
VirtualPort intf = getPort(portId);
if (intf == null) {
LOG.info("Skip Router interface update for non-ipv6 port {}", portId);
return;
}
-
- List<Ipv6Address> existingIPv6AddressList = intf.getIpv6AddressesWithoutLLA();
- List<Ipv6Address> newlyAddedIpv6AddressList = new ArrayList<>();
+ Uuid networkID = intf.getNetworkID();
intf.clearSubnetInfo();
for (FixedIps fip : fixedIpsList) {
IpAddress fixedIp = fip.getIpAddress();
addUnprocessed(unprocessedSubnetIntfs, subnetId, intf);
}
-
- Uuid networkID = intf.getNetworkID();
if (networkID != null) {
vrouterv6IntfMap.put(networkID, intf);
}
-
- if (existingIPv6AddressList.contains(fixedIp.getIpv6Address())) {
- existingIPv6AddressList.remove(fixedIp.getIpv6Address());
- } else {
- newlyAddedIpv6AddressList.add(fixedIp.getIpv6Address());
- }
}
- /* This is a port update event for routerPort. Check if any IPv6 subnet is added
- or removed from the router port. Depending on subnet added/removed, we add/remove
- the corresponding flows from IPV6_TABLE(45).
+ /*
+ * This is a port update event for routerPort. Check if any IPv6 subnet is added or removed from the
+ * router port. Depending on subnet added/removed, we add/remove the corresponding flows from
+ * IPV6_TABLE(45). Add is handled in addInterfaceInfo(), delete case is handled here.
*/
- for (Ipv6Address ipv6Address: newlyAddedIpv6AddressList) {
- // Some v6 subnets are associated to the routerPort add the corresponding NS Flows.
- programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.ADD_FLOW);
- }
-
- for (Ipv6Address ipv6Address: existingIPv6AddressList) {
- // Some v6 subnets are disassociated from the routerPort, remove the corresponding NS Flows.
- programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.DEL_FLOW);
+ for (FixedIps ips : deletedIps) {
+ VirtualSubnet snet = getSubnet(ips.getSubnetId());
+ programIcmpv6NaPuntFlow(networkID, Lists.newArrayList(snet), Ipv6ServiceConstants.DEL_FLOW);
+ programIcmpv6NSPuntFlowForAddress(networkID, ips.getIpAddress().getIpv6Address(),
+ Ipv6ServiceConstants.DEL_FLOW);
}
}
public void addHostIntf(Uuid portId, Uuid snetId, Uuid networkId,
IpAddress fixedIp, String macAddress, String deviceOwner) {
LOG.debug("addHostIntf portId {}, snetId {}, networkId {}, ip {}, mac {}",
- portId, snetId, networkId, fixedIp, macAddress);
+ portId, snetId, networkId, fixedIp, macAddress);
//Save the interface ipv6 address in its fully expanded format
Ipv6Address addr = new Ipv6Address(InetAddresses
public void updateDpnInfo(Uuid portId, BigInteger dpId, Long ofPort) {
LOG.info("In updateDpnInfo portId {}, dpId {}, ofPort {}",
- portId, dpId, ofPort);
+ portId, dpId, ofPort);
VirtualPort intf = getPort(portId);
if (intf != null) {
intf.setDpId(dpId);
// Update the network <--> List[dpnIds, List<ports>] cache.
VirtualNetwork vnet = getNetwork(intf.getNetworkID());
if (null != vnet) {
- vnet.updateDpnPortInfo(dpId, ofPort, Ipv6Constants.ADD_ENTRY);
+ vnet.updateDpnPortInfo(dpId, ofPort, Ipv6ServiceConstants.ADD_ENTRY);
+ } else {
+ LOG.error("In updateDpnInfo networks NOT FOUND: networkID {}, portId {}, dpId {}, ofPort {}",
+ intf.getNetworkID(), portId, dpId, ofPort);
+ addUnprocessed(unprocessedNetIntfs, intf.getNetworkID(), intf);
}
+ } else {
+ LOG.error("In updateDpnInfo port NOT FOUND: portId {}, dpId {}, ofPort {}",
+ portId, dpId, ofPort);
}
}
+
public void updateInterfaceDpidOfPortInfo(Uuid portId) {
LOG.debug("In updateInterfaceDpidOfPortInfo portId {}", portId);
Interface interfaceState = ipv6ServiceUtils.getInterfaceStateFromOperDS(portId.getValue());
List<String> ofportIds = interfaceState.getLowerLayerIf();
NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
- BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
- if (!dpId.equals(Ipv6Constants.INVALID_DPID)) {
+ BigInteger dpId = ipv6ServiceUtils.getDpIdFromInterfaceState(interfaceState);
+ if (!dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
Long ofPort = MDSALUtil.getOfPortNumberFromPortName(nodeConnectorId);
updateDpnInfo(portId, dpId, ofPort);
}
if (intf != null) {
intf.removeSelf();
Uuid networkID = intf.getNetworkID();
- if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
+ if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6ServiceConstants.NETWORK_ROUTER_INTERFACE)) {
LOG.info("In removePort for router interface, portId {}", portId);
if (networkID != null) {
/* Router port is deleted. Remove the corresponding icmpv6 punt flows on all
the dpnIds which were hosting the VMs on the network.
*/
- programIcmpv6RSPuntFlows(intf, Ipv6Constants.DEL_FLOW);
+ programIcmpv6RSPuntFlows(intf.getNetworkID(), Ipv6ServiceConstants.DEL_FLOW);
+ programIcmpv6NaPuntFlow(networkID, intf.getSubnets(), Ipv6ServiceConstants.DEL_FLOW);
for (Ipv6Address ipv6Address: intf.getIpv6Addresses()) {
- programIcmpv6NSPuntFlowForAddress(intf, ipv6Address, Ipv6Constants.DEL_FLOW);
+ programIcmpv6NSPuntFlowForAddress(intf.getNetworkID(), ipv6Address, Ipv6ServiceConstants.DEL_FLOW);
+ }
+ for (VirtualSubnet subnet : intf.getSubnets()) {
+ programIcmpv6NaForwardFlows(intf, subnet.getSubnetUUID(), Ipv6ServiceConstants.DEL_FLOW);
}
- transmitRouterAdvertisement(intf, Ipv6RtrAdvertType.CEASE_ADVERTISEMENT);
+ transmitRouterAdvertisement(intf, Ipv6RouterAdvertisementType.CEASE_ADVERTISEMENT);
timer.cancelPeriodicTransmissionTimeout(intf.getPeriodicTimeout());
intf.resetPeriodicTimeout();
LOG.debug("Reset the periodic RA Timer for intf {}", intf.getIntfUUID());
VirtualNetwork vnet = getNetwork(networkID);
if (null != vnet) {
BigInteger dpId = intf.getDpId();
- vnet.updateDpnPortInfo(dpId, intf.getOfPort(), Ipv6Constants.DEL_ENTRY);
+ vnet.updateDpnPortInfo(dpId, intf.getOfPort(), Ipv6ServiceConstants.DEL_ENTRY);
}
}
}
// Nothing to do for now
}
- public void addUnprocessed(Map<Uuid, List<VirtualPort>> unprocessed, Uuid id, VirtualPort intf) {
+ public void addUnprocessed(Map<Uuid, Set<VirtualPort>> unprocessed, Uuid id, VirtualPort intf) {
if (id != null) {
- unprocessed.computeIfAbsent(id, key -> Collections.synchronizedList(new ArrayList<>())).add(intf);
+ unprocessed.computeIfAbsent(id,
+ key -> Collections.synchronizedSet(ConcurrentHashMap.newKeySet())).add(intf);
}
}
- public void removeUnprocessed(Map<Uuid, List<VirtualPort>> unprocessed, Uuid id) {
+ public Set<VirtualPort> removeUnprocessed(Map<Uuid, Set<VirtualPort>> unprocessed, Uuid id) {
if (id != null) {
- unprocessed.remove(id);
+ return unprocessed.remove(id);
+ }
+ return null;
+ }
+
+ public void addUnprocessedRSFlows(Map<Uuid, Integer>
+ unprocessed, Uuid id, Integer action) {
+ unprocessed.put(id, action);
+
+ }
+
+ public Integer removeUnprocessedRSFlows(Map<Uuid, Integer>
+ unprocessed, Uuid id) {
+ return unprocessed.remove(id);
+ }
+
+ public void addUnprocessedNSFlows(Map<Uuid, Set<Ipv6Address>> unprocessed,
+ Uuid id, Ipv6Address ipv6Address,
+ Integer action) {
+ Set<Ipv6Address> ipv6AddressesList = unprocessed.get(id);
+ if (action == Ipv6ServiceConstants.ADD_FLOW) {
+ unprocessed.computeIfAbsent(id, key -> Collections.synchronizedSet(ConcurrentHashMap.newKeySet()))
+ .add(ipv6Address);
+ } else if (action == Ipv6ServiceConstants.DEL_FLOW) {
+ if ((ipv6AddressesList != null) && (ipv6AddressesList.contains(ipv6Address))) {
+ ipv6AddressesList.remove(ipv6Address);
+ }
}
+ return;
+ }
+
+ public Set<Ipv6Address> removeUnprocessedNSFlows(Map<Uuid, Set<Ipv6Address>>
+ unprocessed, Uuid id) {
+ return unprocessed.remove(id);
}
public VirtualPort getRouterV6InterfaceForNetwork(Uuid networkId) {
return null;
}
for (VirtualSubnet snet : intf.getSubnets()) {
- if (snet.getIpVersion().equals(Ipv6Constants.IP_VERSION_V6)) {
+ if (snet.getIpVersion().equals(Ipv6ServiceConstants.IP_VERSION_V6)) {
return intf;
}
}
return null;
}
- private void programIcmpv6RSPuntFlows(IVirtualPort routerPort, int action) {
+ private void programIcmpv6RSPuntFlows(Uuid networkId, int action) {
if (!ipv6ServiceEosHandler.isClusterOwner()) {
LOG.trace("Not a cluster Owner, skip flow programming.");
return;
}
- Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
+ Long elanTag = getNetworkElanTag(networkId);
int flowStatus;
- VirtualNetwork vnet = getNetwork(routerPort.getNetworkID());
+ VirtualNetwork vnet = getNetwork(networkId);
if (vnet != null) {
List<BigInteger> dpnList = vnet.getDpnsHostingNetwork();
for (BigInteger dpId : dpnList) {
flowStatus = vnet.getRSPuntFlowStatusOnDpnId(dpId);
- if (action == Ipv6Constants.ADD_FLOW && flowStatus == Ipv6Constants.FLOWS_NOT_CONFIGURED) {
+ if (action == Ipv6ServiceConstants.ADD_FLOW
+ && flowStatus == Ipv6ServiceConstants.FLOWS_NOT_CONFIGURED) {
ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
- Ipv6Constants.ADD_FLOW);
- vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_CONFIGURED);
- } else if (action == Ipv6Constants.DEL_FLOW && flowStatus == Ipv6Constants.FLOWS_CONFIGURED) {
+ Ipv6ServiceConstants.ADD_FLOW);
+ vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6ServiceConstants.FLOWS_CONFIGURED);
+ } else if (action == Ipv6ServiceConstants.DEL_FLOW
+ && flowStatus == Ipv6ServiceConstants.FLOWS_CONFIGURED) {
ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
- Ipv6Constants.DEL_FLOW);
- vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_NOT_CONFIGURED);
+ Ipv6ServiceConstants.DEL_FLOW);
+ vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6ServiceConstants.FLOWS_NOT_CONFIGURED);
}
}
+ } else {
+ addUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId, action);
}
}
- private void programIcmpv6NSPuntFlowForAddress(IVirtualPort routerPort, Ipv6Address ipv6Address, int action) {
+ private void programIcmpv6NSPuntFlowForAddress(Uuid networkId, Ipv6Address ipv6Address, int action) {
if (!ipv6ServiceEosHandler.isClusterOwner()) {
LOG.trace("Not a cluster Owner, skip flow programming.");
return;
}
- Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
- VirtualNetwork vnet = getNetwork(routerPort.getNetworkID());
+ Long elanTag = getNetworkElanTag(networkId);
+ VirtualNetwork vnet = getNetwork(networkId);
if (vnet != null) {
Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
- if (action == Ipv6Constants.ADD_FLOW && !dpnIfaceInfo.ndTargetFlowsPunted.contains(ipv6Address)
+ if (action == Ipv6ServiceConstants.ADD_FLOW
+ && !dpnIfaceInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)
&& dpnIfaceInfo.getDpId() != null) {
- ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
- elanTag, ipv6Address.getValue(), Ipv6Constants.ADD_FLOW);
+ ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(), elanTag,
+ ipv6Address.getValue(), Ipv6ServiceConstants.ADD_FLOW);
dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
- } else if (action == Ipv6Constants.DEL_FLOW && dpnIfaceInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
- ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
- elanTag, ipv6Address.getValue(), Ipv6Constants.DEL_FLOW);
+ } else if (action == Ipv6ServiceConstants.DEL_FLOW
+ && dpnIfaceInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)) {
+ ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(), elanTag,
+ ipv6Address.getValue(), Ipv6ServiceConstants.DEL_FLOW);
dpnIfaceInfo.updateNDTargetAddress(ipv6Address, action);
}
}
+ } else {
+ addUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId, ipv6Address, action);
}
}
- public void programIcmpv6PuntFlowsIfNecessary(Uuid vmPortId, BigInteger dpId, VirtualPort routerPort) {
+ private void programIcmpv6NaPuntFlow(Uuid networkID, List<VirtualSubnet> subnets, int action) {
if (!ipv6ServiceEosHandler.isClusterOwner()) {
LOG.trace("Not a cluster Owner, skip flow programming.");
return;
}
+ Long elanTag = getNetworkElanTag(networkID);
+ VirtualNetwork vnet = getNetwork(networkID);
+ if (vnet != null) {
+ Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
+ for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
+ if (dpnIfaceInfo.getDpId() == null) {
+ continue;
+ }
+ for (VirtualSubnet subnet : subnets) {
+ Ipv6Prefix ipv6SubnetPrefix = subnet.getSubnetCidr().getIpv6Prefix();
+ if (ipv6SubnetPrefix != null) {
+ if (action == Ipv6ServiceConstants.ADD_FLOW
+ && !dpnIfaceInfo.isSubnetCidrFlowAlreadyConfigured(subnet.getSubnetUUID())) {
+ ipv6ServiceUtils.installIcmpv6NaPuntFlow(NwConstants.IPV6_TABLE, ipv6SubnetPrefix,
+ dpnIfaceInfo.getDpId(), elanTag, action);
+ dpnIfaceInfo.updateSubnetCidrFlowStatus(subnet.getSubnetUUID(), action);
+ } else if (action == Ipv6ServiceConstants.DEL_FLOW
+ && dpnIfaceInfo.isSubnetCidrFlowAlreadyConfigured(subnet.getSubnetUUID())) {
+ ipv6ServiceUtils.installIcmpv6NaPuntFlow(NwConstants.IPV6_TABLE, ipv6SubnetPrefix,
+ dpnIfaceInfo.getDpId(), elanTag, action);
+ dpnIfaceInfo.updateSubnetCidrFlowStatus(subnet.getSubnetUUID(), action);
+ }
+ }
+ }
+ }
+ }
+ }
- IVirtualPort vmPort = getPort(vmPortId);
- if (null != vmPort) {
- VirtualNetwork vnet = getNetwork(vmPort.getNetworkID());
- if (null != vnet) {
- VirtualNetwork.DpnInterfaceInfo dpnInfo = vnet.getDpnIfaceInfo(dpId);
- if (null != dpnInfo) {
- Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
- if (vnet.getRSPuntFlowStatusOnDpnId(dpId) == Ipv6Constants.FLOWS_NOT_CONFIGURED) {
- ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
- Ipv6Constants.ADD_FLOW);
- vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6Constants.FLOWS_CONFIGURED);
+ public void handleInterfaceStateEvent(IVirtualPort port, BigInteger dpId, VirtualPort routerPort, int addOrRemove) {
+ Long elanTag = getNetworkElanTag(port.getNetworkID());
+ if (addOrRemove == Ipv6ServiceConstants.ADD_FLOW && routerPort != null) {
+ // Check and program icmpv6 punt flows on the dpnID if its the first VM on the host.
+ programIcmpv6PuntFlows(port, dpId, elanTag, routerPort);
+ }
+ programIcmpv6NaForwardFlow(port, dpId, elanTag, addOrRemove);
+ }
+
+ private void programIcmpv6PuntFlows(IVirtualPort vmPort, BigInteger dpId, Long elanTag, VirtualPort routerPort) {
+ VirtualNetwork vnet = getNetwork(vmPort.getNetworkID());
+ if (null != vnet) {
+ VirtualNetwork.DpnInterfaceInfo dpnInfo = vnet.getDpnIfaceInfo(dpId);
+ if (null != dpnInfo) {
+ if (vnet.getRSPuntFlowStatusOnDpnId(dpId) == Ipv6ServiceConstants.FLOWS_NOT_CONFIGURED) {
+ ipv6ServiceUtils.installIcmpv6RsPuntFlow(NwConstants.IPV6_TABLE, dpId, elanTag,
+ Ipv6ServiceConstants.ADD_FLOW);
+ vnet.setRSPuntFlowStatusOnDpnId(dpId, Ipv6ServiceConstants.FLOWS_CONFIGURED);
+ }
+
+ for (Ipv6Address ipv6Address : routerPort.getIpv6Addresses()) {
+ if (!dpnInfo.isNdTargetFlowAlreadyConfigured(ipv6Address)) {
+ ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
+ elanTag, ipv6Address.getValue(), Ipv6ServiceConstants.ADD_FLOW);
+ dpnInfo.updateNDTargetAddress(ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
}
+ }
- for (Ipv6Address ipv6Address: routerPort.getIpv6Addresses()) {
- if (!dpnInfo.ndTargetFlowsPunted.contains(ipv6Address)) {
- ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpId,
- elanTag, ipv6Address.getValue(), Ipv6Constants.ADD_FLOW);
- dpnInfo.updateNDTargetAddress(ipv6Address, Ipv6Constants.ADD_FLOW);
- }
+ for (VirtualSubnet subnet : routerPort.getSubnets()) {
+ Ipv6Prefix ipv6SubnetPrefix = subnet.getSubnetCidr().getIpv6Prefix();
+ if (ipv6SubnetPrefix != null
+ && !dpnInfo.isSubnetCidrFlowAlreadyConfigured(subnet.getSubnetUUID())) {
+ ipv6ServiceUtils.installIcmpv6NaPuntFlow(NwConstants.IPV6_TABLE, ipv6SubnetPrefix, dpId,
+ elanTag, Ipv6ServiceConstants.ADD_FLOW);
+ dpnInfo.updateSubnetCidrFlowStatus(subnet.getSubnetUUID(), Ipv6ServiceConstants.ADD_FLOW);
+ }
+ }
+ }
+ }
+ }
+
+ private void programIcmpv6NaForwardFlows(IVirtualPort routerPort, Uuid snetId, int action) {
+ if (!ipv6ServiceEosHandler.isClusterOwner()) {
+ LOG.trace("Not a cluster Owner, skip flow programming.");
+ return;
+ }
+
+ VirtualNetwork vnet = getNetwork(routerPort.getNetworkID());
+ if (vnet != null) {
+ Long elanTag = getNetworkElanTag(routerPort.getNetworkID());
+ Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
+ for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
+ if (dpnIfaceInfo.getDpId() == null) {
+ continue;
+ }
+ List<VirtualPort> vmPorts = getVmPortsInSubnetByDpId(snetId, dpnIfaceInfo.getDpId());
+ for (VirtualPort vmPort : vmPorts) {
+ programIcmpv6NaForwardFlow(vmPort, dpnIfaceInfo.getDpId(), elanTag, action);
+ }
+ }
+ }
+ }
+
+ /**
+ * Programs ICMPv6 NA forwarding flow for fixed IPs of neutron port. NA's from non-fixed IPs are
+ * punted to controller for learning.
+ *
+ * @param vmPort the VM port
+ * @param dpId the DP ID
+ * @param elanTag the ELAN tag
+ * @param addOrRemove the add or remove flag
+ */
+ private void programIcmpv6NaForwardFlow(IVirtualPort vmPort, BigInteger dpId, Long elanTag, int addOrRemove) {
+ ipv6ServiceUtils.installIcmpv6NaForwardFlow(NwConstants.IPV6_TABLE, vmPort, dpId, elanTag, addOrRemove);
+ }
+
+ public List<VirtualPort> getVmPortsInSubnetByDpId(Uuid snetId, BigInteger dpId) {
+ List<VirtualPort> vmPorts = new ArrayList<>();
+ for (VirtualPort port : vintfs.values()) {
+ if (dpId.equals(port.getDpId()) && Ipv6ServiceUtils.isVmPort(port.getDeviceOwner())) {
+ for (VirtualSubnet subnet : port.getSubnets()) {
+ if (subnet.getSubnetUUID().equals(snetId)) {
+ vmPorts.add(port);
}
}
}
}
+ return vmPorts;
}
public String getInterfaceNameFromTag(long portTag) {
if (vnetworks.putIfAbsent(networkId, new VirtualNetwork(networkId)) == null) {
updateNetworkElanTag(networkId);
}
+ Set<VirtualPort> intfList = removeUnprocessed(unprocessedNetIntfs, networkId);
+ if (intfList == null) {
+ LOG.info("No unprocessed interfaces for the net {}", networkId);
+ return;
+ }
+
+ for (VirtualPort intf : intfList) {
+ if (intf != null) {
+ updateInterfaceDpidOfPortInfo(intf.getIntfUUID());
+ }
+ }
+
+ Set<Ipv6Address> ipv6Addresses =
+ removeUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId);
+
+ for (Ipv6Address ipv6Address : ipv6Addresses) {
+ programIcmpv6NSPuntFlowForAddress(networkId, ipv6Address, Ipv6ServiceConstants.ADD_FLOW);
+ }
+
+ Integer action = removeUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId);
+ programIcmpv6RSPuntFlows(networkId, action);
}
public void removeNetwork(Uuid networkId) {
// Delete the network and the corresponding dpnIds<-->List(ports) cache.
VirtualNetwork net = networkId != null ? vnetworks.remove(networkId) : null;
- if (null != net) {
+ if (null != net && null != net.getNetworkUuid()) {
+ /* removing all RS flows when network gets removed, as the DPN-list is maintained only as part of
+ * network cache. After removal of network there is no way to remove them today. */
+ programIcmpv6RSPuntFlows(net.getNetworkUuid(), Ipv6ServiceConstants.DEL_FLOW);
+ removeAllIcmpv6NSPuntFlowForNetwork(net.getNetworkUuid());
net.removeSelf();
}
+ removeUnprocessed(unprocessedNetIntfs, networkId);
+ removeUnprocessedRSFlows(unprocessedNetRSFlowIntfs, networkId);
+ removeUnprocessedNSFlows(unprocessedNetNSFlowIntfs, networkId);
}
- private void transmitRouterAdvertisement(VirtualPort intf, Ipv6RtrAdvertType advType) {
- Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(packetService);
+ private void transmitRouterAdvertisement(VirtualPort intf, Ipv6RouterAdvertisementType advType) {
+ Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(packetService, this);
- LOG.debug("in transmitRouterAdvertisement for {}", advType);
VirtualNetwork vnet = getNetwork(intf.getNetworkID());
if (vnet != null) {
- String nodeName;
- String outPort;
+ long elanTag = vnet.getElanTag();
Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
- nodeName = Ipv6Constants.OPENFLOW_NODE_PREFIX + dpnIfaceInfo.getDpId();
- List<NodeConnectorRef> ncRefList = new ArrayList<>();
- for (Long ofPort: dpnIfaceInfo.ofPortList) {
- outPort = nodeName + ":" + ofPort;
- LOG.debug("Transmitting RA {} for node {}, port {}", advType, nodeName, outPort);
- InstanceIdentifier<NodeConnector> outPortId = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class, new NodeKey(new NodeId(nodeName)))
- .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(outPort)))
- .build();
- ncRefList.add(new NodeConnectorRef(outPortId));
+ LOG.debug("transmitRouterAdvertisement: Transmitting RA {} for ELAN Tag {}",
+ advType, elanTag);
+ if (dpnIfaceInfo.getDpId() != null) {
+ ipv6RouterAdvert.transmitRtrAdvertisement(advType, intf, elanTag, null,
+ dpnIfaceInfo.getDpId(), intf.getIntfUUID());
}
- if (!ncRefList.isEmpty()) {
- ipv6RouterAdvert.transmitRtrAdvertisement(advType, intf, ncRefList, null);
+ }
+ }
+ }
+
+
+ private void removeAllIcmpv6NSPuntFlowForNetwork(Uuid networkId) {
+ Long elanTag = getNetworkElanTag(networkId);
+ VirtualNetwork vnet = vnetworks.get(networkId);
+ if (vnet == null) {
+ return;
+ }
+
+ Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
+
+ for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
+ for (Ipv6Address ipv6Address : dpnIfaceInfo.ndTargetFlowsPunted) {
+ if (ipv6ServiceEosHandler.isClusterOwner()) {
+ ipv6ServiceUtils.installIcmpv6NsPuntFlow(NwConstants.IPV6_TABLE, dpnIfaceInfo.getDpId(),
+ elanTag, ipv6Address.getValue(), Ipv6ServiceConstants.DEL_FLOW);
}
+ dpnIfaceInfo.updateNDTargetAddress(ipv6Address, Ipv6ServiceConstants.DEL_ENTRY);
}
}
}
+
public void transmitUnsolicitedRA(Uuid portId) {
VirtualPort port = getPort(portId);
LOG.debug("in transmitUnsolicitedRA for {}, port {}", portId, port);
/* Only the Cluster Owner would be sending out the Periodic RAs.
However, the timer is configured on all the nodes to handle cluster fail-over scenarios.
*/
- transmitRouterAdvertisement(port, Ipv6RtrAdvertType.UNSOLICITED_ADVERTISEMENT);
+ transmitRouterAdvertisement(port, Ipv6RouterAdvertisementType.UNSOLICITED_ADVERTISEMENT);
}
Timeout portTimeout = timer.setPeriodicTransmissionTimeout(port.getPeriodicTimer(),
- Ipv6Constants.PERIODIC_RA_INTERVAL,
- TimeUnit.SECONDS);
+ Ipv6ServiceConstants.PERIODIC_RA_INTERVAL,
+ TimeUnit.SECONDS);
port.setPeriodicTimeout(portTimeout);
LOG.debug("re-started periodic RA Timer for routerIntf {}, int {}s", port.getIntfUUID(),
- Ipv6Constants.PERIODIC_RA_INTERVAL);
+ Ipv6ServiceConstants.PERIODIC_RA_INTERVAL);
}
@Override
}
return virtualRouter;
}
+
+ public List<Action> getEgressAction(String interfaceName) {
+ List<Action> actions = null;
+ try {
+ GetEgressActionsForInterfaceInputBuilder egressAction =
+ new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName);
+ Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
+ interfaceManagerRpc.getEgressActionsForInterface(egressAction.build());
+ RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
+ if (!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
+ interfaceName, rpcResult.getErrors());
+ } else {
+ actions = rpcResult.getResult().getAction();
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when egress actions for interface {}", interfaceName, e);
+ }
+ return actions;
+ }
}