package org.opendaylight.netvirt.ipv6service.utils;
import com.google.common.base.Optional;
-import com.google.common.net.InetAddresses;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.infra.Datastore;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+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;
import org.opendaylight.genius.mdsalutil.MatchInfo;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
+import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
+import org.opendaylight.genius.mdsalutil.actions.ActionLearn.FlowMod;
+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.MatchIcmpv6;
import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
import org.opendaylight.genius.mdsalutil.matches.MatchIpv6NdTarget;
+import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
import org.opendaylight.genius.utils.ServiceIndex;
+import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
+import org.opendaylight.netvirt.ipv6service.VirtualSubnet;
+import org.opendaylight.netvirt.ipv6service.api.IVirtualPort;
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;
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.InterfaceKey;
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.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.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.EthernetHeader;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.Ipv6Header;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.config.rev181010.Ipv6serviceConfig;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
@Singleton
public class Ipv6ServiceUtils {
private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceUtils.class);
- public static final Ipv6Address ALL_NODES_MCAST_ADDR = newIpv6Address("FF02::1");
+ public static final Ipv6Address ALL_NODES_MCAST_ADDR = newIpv6Address(Ipv6Constants.ALL_NODES_MCAST_ADDRESS);
public static final Ipv6Address UNSPECIFIED_ADDR = newIpv6Address("0:0:0:0:0:0:0:0");
+ @Nullable
private static Ipv6Address newIpv6Address(String ip) {
try {
return Ipv6Address.getDefaultInstance(InetAddress.getByName(ip).getHostAddress());
private final DataBroker broker;
private final IMdsalApiManager mdsalUtil;
+ private final ManagedNewTransactionRunner txRunner;
+ private final Ipv6serviceConfig ipv6serviceConfig;
@Inject
- public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil) {
+ public Ipv6ServiceUtils(DataBroker broker, IMdsalApiManager mdsalUtil, Ipv6serviceConfig ipv6ServiceConfig) {
this.broker = broker;
this.mdsalUtil = mdsalUtil;
+ this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
+ this.ipv6serviceConfig = ipv6ServiceConfig;
}
/**
* @return the interface.
*/
public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
- .Interface getInterface(String interfaceName) {
- Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
- .Interface> optInterface =
- read(LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
- if (optInterface.isPresent()) {
- return optInterface.get();
- }
- return null;
+ .@Nullable Interface getInterface(String interfaceName) {
+ return read(LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName)).orNull();
}
/**
* @return the interface state.
*/
public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
- .Interface getInterfaceStateFromOperDS(String interfaceName) {
- InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
- .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
- return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, ifStateId, broker).orNull();
+ .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName) {
+ return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, buildStateInterfaceId(interfaceName), broker).orNull();
}
- public static String bytesToHexString(byte[] bytes) {
- if (bytes == null) {
- return "null";
- }
- StringBuilder buf = new StringBuilder();
- for (int i = 0; i < bytes.length; i++) {
- if (i > 0) {
- buf.append(":");
- }
- short u8byte = (short) (bytes[i] & 0xff);
- String tmp = Integer.toHexString(u8byte);
- if (tmp.length() == 1) {
- buf.append("0");
- }
- buf.append(tmp);
- }
- return buf.toString();
+ private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(MatchIpProtocol.ICMPV6);
+ matches.add(new MatchIcmpv6(Icmpv6Type.ROUTER_SOLICITATION.getValue(), (short) 0));
+ matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+ return matches;
}
- public static byte[] bytesFromHexString(String values) {
- String target = "";
- if (values != null) {
- target = values;
- }
- String[] octets = target.split(":");
-
- byte[] ret = new byte[octets.length];
- for (int i = 0; i < octets.length; i++) {
- ret[i] = Integer.valueOf(octets[i], 16).byteValue();
- }
- return ret;
+ private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, Ipv6Address ipv6Address) {
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(MatchIpProtocol.ICMPV6);
+ matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_SOLICITATION.getValue(), (short) 0));
+ matches.add(new MatchIpv6NdTarget(ipv6Address));
+ matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+ return matches;
}
- public static int calcIcmpv6Checksum(byte[] packet, Ipv6Header ip6Hdr) {
- long checksum = getSummation(ip6Hdr.getSourceIpv6());
- checksum += getSummation(ip6Hdr.getDestinationIpv6());
- checksum = normalizeChecksum(checksum);
-
- checksum += ip6Hdr.getIpv6Length();
- checksum += ip6Hdr.getNextHeader();
-
- int icmp6Offset = Ipv6Constants.ICMPV6_OFFSET;
- long value = (packet[icmp6Offset] & 0xff) << 8 | packet[icmp6Offset + 1] & 0xff;
- checksum += value;
- checksum = normalizeChecksum(checksum);
- icmp6Offset += 2;
-
- //move to icmp6 payload skipping the checksum field
- icmp6Offset += 2;
- int length = packet.length - icmp6Offset;
- while (length > 1) {
- value = (packet[icmp6Offset] & 0xff) << 8 | packet[icmp6Offset + 1] & 0xff;
- checksum += value;
- checksum = normalizeChecksum(checksum);
- icmp6Offset += 2;
- length -= 2;
- }
-
- if (length > 0) {
- checksum += packet[icmp6Offset];
- checksum = normalizeChecksum(checksum);
- }
-
- int finalChecksum = (int)(~checksum & 0xffff);
- return finalChecksum;
+ private List<MatchInfo> getIcmpv6NAMatch(Long elanTag) {
+ List<MatchInfo> matches = new ArrayList<>();
+ matches.add(MatchEthernetType.IPV6);
+ matches.add(MatchIpProtocol.ICMPV6);
+ matches.add(new MatchIcmpv6(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue(), (short) 0));
+ matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+ return matches;
}
- public static boolean validateChecksum(byte[] packet, Ipv6Header ip6Hdr, int recvChecksum) {
- return calcIcmpv6Checksum(packet, ip6Hdr) == recvChecksum;
+ private static String getIPv6FlowRef(BigInteger dpId, Long elanTag, String flowType) {
+ return new StringBuffer().append(Ipv6ServiceConstants.FLOWID_PREFIX)
+ .append(dpId).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
+ .append(elanTag).append(Ipv6ServiceConstants.FLOWID_SEPARATOR)
+ .append(flowType).toString();
}
- private static long getSummation(Ipv6Address addr) {
- byte[] baddr = null;
- try {
- baddr = InetAddress.getByName(addr.getValue()).getAddress();
- } catch (UnknownHostException e) {
- LOG.error("getSummation: Failed to deserialize address {}", addr.getValue(), e);
- return 0;
- }
+ public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, Ipv6Address ipv6Address,
+ int addOrRemove) {
+ String flowId = getIPv6FlowRef(dpId, elanTag, Ipv6Util.getFormattedIpv6Address(ipv6Address));
- long sum = 0;
- int len = 0;
- long value = 0;
- while (len < baddr.length) {
- value = (baddr[len] & 0xff) << 8 | baddr[len + 1] & 0xff;
- sum += value;
- sum = normalizeChecksum(sum);
- len += 2;
- }
- return sum;
- }
+ if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
+ LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
+ LoggingFutures
+ .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+ mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
+ }), LOG, "Error while removing flow={}", flowId);
+ } else {
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ actionsInfos.add(new ActionPuntToController());
- private static long normalizeChecksum(long value) {
- if ((value & 0xffff0000) != 0) {
- value = value & 0xffff;
- value += 1;
+ int ndPuntTimeout = ipv6serviceConfig.getNeighborDiscoveryPuntTimeout();
+ if (isNdPuntProtectionEnabled(ndPuntTimeout)) {
+ actionsInfos.add(getLearnActionForNsPuntProtection(ndPuntTimeout));
+ }
+ List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
+ List<MatchInfo> nsMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
+ FlowEntity nsFlowEntity =
+ MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
+ "IPv6NS", 0, 0, NwConstants.COOKIE_IPV6_TABLE, nsMatch, instructions);
+
+ LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId={}, elanTag={} ipv6Address={}", dpId, elanTag,
+ ipv6Address.getValue());
+ LoggingFutures
+ .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+ mdsalUtil.addFlow(tx, nsFlowEntity);
+ }), LOG, "Error while adding flow={}", nsFlowEntity);
}
- return value;
}
- public static byte[] convertEthernetHeaderToByte(EthernetHeader ethPdu) {
- byte[] data = new byte[16];
- Arrays.fill(data, (byte)0);
+ private ActionLearn getLearnActionForNsPuntProtection(int ndPuntTimeout) {
+ List<FlowMod> flowMods = getFlowModsForIpv6PuntProtection(Icmpv6Type.NEIGHBOR_SOLICITATION);
+ flowMods.add(new ActionLearn.MatchFromField(NxmOfFieldType.NXM_NX_ND_TARGET.getType(),
+ NxmOfFieldType.NXM_NX_ND_TARGET.getType(), NxmOfFieldType.NXM_NX_ND_TARGET.getFlowModHeaderLenInt()));
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.put(bytesFromHexString(ethPdu.getDestinationMac().getValue()));
- buf.put(bytesFromHexString(ethPdu.getSourceMac().getValue()));
- buf.putShort((short)ethPdu.getEthertype().intValue());
- return data;
+ return new ActionLearn(0, ndPuntTimeout, Ipv6ServiceConstants.NS_PUNT_PROTECTION_FLOW_PRIORITY,
+ NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0, flowMods);
}
- public static byte[] convertIpv6HeaderToByte(Ipv6Header ip6Pdu) {
- byte[] data = new byte[128];
- Arrays.fill(data, (byte)0);
-
- ByteBuffer buf = ByteBuffer.wrap(data);
- long flowLabel = (long)(ip6Pdu.getVersion() & 0x0f) << 28
- | ip6Pdu.getFlowLabel() & 0x0fffffff;
- buf.putInt((int)flowLabel);
- buf.putShort((short)ip6Pdu.getIpv6Length().intValue());
- buf.put((byte)ip6Pdu.getNextHeader().shortValue());
- buf.put((byte)ip6Pdu.getHopLimit().shortValue());
- try {
- byte[] baddr = InetAddress.getByName(ip6Pdu.getSourceIpv6().getValue()).getAddress();
- buf.put(baddr);
- baddr = InetAddress.getByName(ip6Pdu.getDestinationIpv6().getValue()).getAddress();
- buf.put(baddr);
- } catch (UnknownHostException e) {
- LOG.error("convertIpv6HeaderToByte: Failed to serialize src, dest address", e);
+ public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, int addOrRemove) {
+ if (dpId == null || dpId.equals(Ipv6ServiceConstants.INVALID_DPID)) {
+ return;
}
- return data;
- }
-
- public static Ipv6Address getIpv6LinkLocalAddressFromMac(MacAddress mac) {
- byte[] octets = bytesFromHexString(mac.getValue());
-
- /* As per the RFC2373, steps involved to generate a LLA include
- 1. Convert the 48 bit MAC address to 64 bit value by inserting 0xFFFE
- between OUI and NIC Specific part.
- 2. Invert the Universal/Local flag in the OUI portion of the address.
- 3. Use the prefix "FE80::/10" along with the above 64 bit Interface
- identifier to generate the IPv6 LLA. */
-
- StringBuilder interfaceID = new StringBuilder();
- short u8byte = (short) (octets[0] & 0xff);
- u8byte ^= 1 << 1;
- interfaceID.append(Integer.toHexString(0xFF & u8byte));
- interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[1]), 2, "0"));
- interfaceID.append(":");
- interfaceID.append(Integer.toHexString(0xFF & octets[2]));
- interfaceID.append("ff:fe");
- interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[3]), 2, "0"));
- interfaceID.append(":");
- interfaceID.append(Integer.toHexString(0xFF & octets[4]));
- interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[5]), 2, "0"));
-
- // Return the address in its fully expanded format.
- Ipv6Address ipv6LLA = new Ipv6Address(InetAddresses.forString(
- "fe80:0:0:0:" + interfaceID.toString()).getHostAddress());
- return ipv6LLA;
- }
-
- public static Ipv6Address getIpv6SolicitedNodeMcastAddress(Ipv6Address ipv6Address) {
+ String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6RS");
+ if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
+ LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
+ LoggingFutures
+ .addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+ mdsalUtil.removeFlow(tx, dpId, flowId, tableId);
+ }), LOG, "Error while removing flow={}", flowId);
+ } else {
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ // Punt to controller
+ actionsInfos.add(new ActionPuntToController());
- /* According to RFC 4291, a Solicited Node Multicast Address is derived by adding the 24
- lower order bits with the Solicited Node multicast prefix (i.e., FF02::1:FF00:0/104).
- Example: For IPv6Address of FE80::2AA:FF:FE28:9C5A, the corresponding solicited node
- multicast address would be FF02::1:FF28:9C5A
- */
+ int rdPuntTimeout = ipv6serviceConfig.getRouterDiscoveryPuntTimeout();
+ if (isRdPuntProtectionEnabled(rdPuntTimeout)) {
+ actionsInfos.add(getLearnActionForRsPuntProtection(rdPuntTimeout));
+ }
+ List<InstructionInfo> instructions = Arrays.asList(new InstructionApplyActions(actionsInfos));
+ List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
+ FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
+ flowId,Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
+ NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
- byte[] octets;
- try {
- octets = InetAddress.getByName(ipv6Address.getValue()).getAddress();
- } catch (UnknownHostException e) {
- LOG.error("getIpv6SolicitedNodeMcastAddress: Failed to serialize ipv6Address ", e);
- return null;
+ LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
+ LoggingFutures
+ .addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+ mdsalUtil.addFlow(tx, rsFlowEntity);
+ }), LOG, "Error while adding flow={}", rsFlowEntity);
}
-
- // Return the address in its fully expanded format.
- Ipv6Address solictedV6Address = new Ipv6Address(InetAddresses.forString("ff02::1:ff"
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[13]), 2, "0") + ":"
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[14]), 2, "0")
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[15]), 2, "0")).getHostAddress());
-
- return solictedV6Address;
}
- public static MacAddress getIpv6MulticastMacAddress(Ipv6Address ipv6Address) {
-
- /* According to RFC 2464, a Multicast MAC address is derived by concatenating 32 lower
- order bits of IPv6 Multicast Address with the multicast prefix (i.e., 33:33).
- Example: For Multicast IPv6Address of FF02::1:FF28:9C5A, the corresponding L2 multicast
- address would be 33:33:28:9C:5A
- */
- byte[] octets;
- try {
- octets = InetAddress.getByName(ipv6Address.getValue()).getAddress();
- } catch (UnknownHostException e) {
- LOG.error("getIpv6MulticastMacAddress: Failed to serialize ipv6Address ", e);
- return null;
- }
-
- String macAddress = "33:33:"
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[12]), 2, "0") + ":"
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[13]), 2, "0") + ":"
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[14]), 2, "0") + ":"
- + StringUtils.leftPad(Integer.toHexString(0xFF & octets[15]), 2, "0");
-
- return new MacAddress(macAddress);
+ private ActionLearn getLearnActionForRsPuntProtection(int rdPuntTimeout) {
+ return new ActionLearn(0, rdPuntTimeout, Ipv6ServiceConstants.RS_PUNT_PROTECTION_FLOW_PRIORITY,
+ NwConstants.COOKIE_IPV6_TABLE, 0, NwConstants.IPV6_TABLE, 0, 0,
+ getFlowModsForIpv6PuntProtection(Icmpv6Type.ROUTER_SOLICITATION));
}
- private static List<MatchInfo> getIcmpv6RSMatch(Long elanTag) {
- List<MatchInfo> matches = new ArrayList<>();
- matches.add(MatchEthernetType.IPV6);
- matches.add(MatchIpProtocol.ICMPV6);
- matches.add(new MatchIcmpv6(Ipv6Constants.ICMP_V6_RS_CODE, (short) 0));
- matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
- return matches;
+ private List<FlowMod> getFlowModsForIpv6PuntProtection(Icmpv6Type icmpv6Type) {
+ return new ArrayList<>(Arrays.asList(
+ new ActionLearn.MatchFromValue(NwConstants.ETHTYPE_IPV6, NxmOfFieldType.NXM_OF_ETH_TYPE.getType(),
+ NxmOfFieldType.NXM_OF_ETH_TYPE.getFlowModHeaderLenInt()),
+ new ActionLearn.MatchFromValue(IPProtocols.IPV6ICMP.shortValue(),
+ NxmOfFieldType.NXM_OF_IP_PROTO.getType(),
+ NxmOfFieldType.NXM_OF_IP_PROTO.getFlowModHeaderLenInt()),
+ new ActionLearn.MatchFromValue(icmpv6Type.getValue(), NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getType(),
+ NxmOfFieldType.NXM_OF_ICMPv6_TYPE.getFlowModHeaderLenInt()),
+ new ActionLearn.MatchFromField(NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
+ NxmOfFieldType.NXM_OF_ICMPv6_CODE.getType(),
+ NxmOfFieldType.NXM_OF_ICMPv6_CODE.getFlowModHeaderLenInt()),
+ new ActionLearn.MatchFromField(NxmOfFieldType.OXM_OF_METADATA.getType(),
+ MetaDataUtil.METADATA_LPORT_TAG_OFFSET, NxmOfFieldType.OXM_OF_METADATA.getType(),
+ MetaDataUtil.METADATA_LPORT_TAG_OFFSET, MetaDataUtil.METADATA_LPORT_TAG_BITLEN)));
}
- private List<MatchInfo> getIcmpv6NSMatch(Long elanTag, String ndTarget) {
- List<MatchInfo> matches = new ArrayList<>();
- matches.add(MatchEthernetType.IPV6);
- matches.add(MatchIpProtocol.ICMPV6);
- matches.add(new MatchIcmpv6(Ipv6Constants.ICMP_V6_NS_CODE, (short) 0));
- matches.add(new MatchIpv6NdTarget(new Ipv6Address(ndTarget)));
- matches.add(new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
- return matches;
+ private boolean isRdPuntProtectionEnabled(int rdPuntTimeout) {
+ return rdPuntTimeout != 0;
}
- private static String getIPv6FlowRef(BigInteger dpId, Long elanTag, String flowType) {
- return new StringBuffer().append(Ipv6Constants.FLOWID_PREFIX)
- .append(dpId).append(Ipv6Constants.FLOWID_SEPARATOR)
- .append(elanTag).append(Ipv6Constants.FLOWID_SEPARATOR)
- .append(flowType).toString();
+ private boolean isNdPuntProtectionEnabled(int ndPuntTimeout) {
+ return ndPuntTimeout != 0;
}
- public void installIcmpv6NsPuntFlow(short tableId, BigInteger dpId, Long elanTag, String ipv6Address,
+ public void installIcmpv6NaForwardFlow(short tableId, IVirtualPort vmPort, BigInteger dpId, Long elanTag,
int addOrRemove) {
- List<MatchInfo> neighborSolicitationMatch = getIcmpv6NSMatch(elanTag, ipv6Address);
+ List<MatchInfo> matches = getIcmpv6NAMatch(elanTag);
List<InstructionInfo> instructions = new ArrayList<>();
List<ActionInfo> actionsInfos = new ArrayList<>();
- actionsInfos.add(new ActionPuntToController());
+ actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
instructions.add(new InstructionApplyActions(actionsInfos));
- FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
- getIPv6FlowRef(dpId, elanTag, ipv6Address),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6NS",
- 0, 0, NwConstants.COOKIE_IPV6_TABLE, neighborSolicitationMatch, instructions);
- if (addOrRemove == Ipv6Constants.DEL_FLOW) {
- LOG.trace("Removing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
- mdsalUtil.removeFlow(rsFlowEntity);
- } else {
- LOG.trace("Installing IPv6 Neighbor Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
- mdsalUtil.installFlow(rsFlowEntity);
+
+ for (Ipv6Address ipv6Address : vmPort.getIpv6Addresses()) {
+ matches.add(new MatchIpv6Source(ipv6Address.getValue() + NwConstants.IPV6PREFIX));
+ String flowId = getIPv6FlowRef(dpId, elanTag,
+ vmPort.getIntfUUID().getValue() + Ipv6ServiceConstants.FLOWID_SEPARATOR + ipv6Address.getValue());
+ FlowEntity rsFlowEntity =
+ MDSALUtil.buildFlowEntity(dpId, tableId, flowId, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
+ "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, matches, instructions);
+ if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
+ LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
+ elanTag, ipv6Address.getValue());
+ mdsalUtil.removeFlow(rsFlowEntity);
+ } else {
+ LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}, ipv6Address {}", dpId,
+ elanTag, ipv6Address.getValue());
+ mdsalUtil.installFlow(rsFlowEntity);
+ }
}
}
- public void installIcmpv6RsPuntFlow(short tableId, BigInteger dpId, Long elanTag, int addOrRemove) {
- if (dpId == null || dpId.equals(Ipv6Constants.INVALID_DPID)) {
- return;
- }
- List<MatchInfo> routerSolicitationMatch = getIcmpv6RSMatch(elanTag);
+ public void installIcmpv6NaPuntFlow(short tableId, Ipv6Prefix ipv6Prefix, BigInteger dpId, Long elanTag,
+ int addOrRemove) {
+ List<MatchInfo> naMatch = getIcmpv6NAMatch(elanTag);
+ naMatch.add(new MatchIpv6Source(ipv6Prefix));
+
List<InstructionInfo> instructions = new ArrayList<>();
List<ActionInfo> actionsInfos = new ArrayList<>();
- // Punt to controller
actionsInfos.add(new ActionPuntToController());
+ actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
instructions.add(new InstructionApplyActions(actionsInfos));
+
+ String flowId = getIPv6FlowRef(dpId, elanTag, "IPv6NA." + ipv6Prefix.getValue());
FlowEntity rsFlowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
- getIPv6FlowRef(dpId, elanTag, "IPv6RS"),Ipv6Constants.DEFAULT_FLOW_PRIORITY, "IPv6RS", 0, 0,
- NwConstants.COOKIE_IPV6_TABLE, routerSolicitationMatch, instructions);
- if (addOrRemove == Ipv6Constants.DEL_FLOW) {
- LOG.trace("Removing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
+ flowId, Ipv6ServiceConstants.PUNT_NA_FLOW_PRIORITY,
+ "IPv6NA", 0, 0, NwConstants.COOKIE_IPV6_TABLE, naMatch, instructions);
+ if (addOrRemove == Ipv6ServiceConstants.DEL_FLOW) {
+ LOG.trace("Removing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
mdsalUtil.removeFlow(rsFlowEntity);
} else {
- LOG.trace("Installing IPv6 Router Solicitation Flow DpId {}, elanTag {}", dpId, elanTag);
+ LOG.trace("Installing IPv6 Neighbor Advertisement Flow DpId {}, elanTag {}", dpId, elanTag);
mdsalUtil.installFlow(rsFlowEntity);
}
}
BoundServices
serviceInfo =
getBoundServices(String.format("%s.%s", "ipv6", interfaceName),
- serviceIndex, Ipv6Constants.DEFAULT_FLOW_PRIORITY,
+ serviceIndex, Ipv6ServiceConstants.DEFAULT_FLOW_PRIORITY,
NwConstants.COOKIE_IPV6_TABLE, instructions);
MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
buildServiceId(interfaceName, serviceIndex), serviceInfo);
NwConstants.IPV6_SERVICE_INDEX)));
}
+ @Nullable
+ public BigInteger getDpIdFromInterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
+ .interfaces.rev140508.interfaces.state.Interface interfaceState) {
+ BigInteger dpId = null;
+ List<String> ofportIds = interfaceState.getLowerLayerIf();
+ if (ofportIds != null && !ofportIds.isEmpty()) {
+ NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
+ dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
+ }
+ return dpId;
+ }
+
public static long getRemoteBCGroup(long elanTag) {
- return Ipv6Constants.ELAN_GID_MIN + elanTag % Ipv6Constants.ELAN_GID_MIN * 2;
+ return Ipv6ServiceConstants.ELAN_GID_MIN + elanTag % Ipv6ServiceConstants.ELAN_GID_MIN * 2;
+ }
+
+ public static boolean isVmPort(String deviceOwner) {
+ // FIXME: Currently for VM ports, Neutron is sending deviceOwner as empty instead of "compute:nova".
+ // return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner);
+ return Ipv6ServiceConstants.DEVICE_OWNER_COMPUTE_NOVA.equalsIgnoreCase(deviceOwner)
+ || StringUtils.isEmpty(deviceOwner);
+ }
+
+ public static boolean isIpv6Subnet(VirtualSubnet subnet) {
+ if (subnet == null) {
+ return false;
+ }
+ return subnet.getIpVersion().equals(Ipv6ServiceConstants.IP_VERSION_V6) ? true : false;
}
}