This patch supports NA for router interface (including LLA).
Change-Id: I4d3d4c41dec12abef3b1d04c067a2e21930ed021
Signed-off-by: Sridhar Gaddam <sgaddam@redhat.com>
Signed-off-by: kalaiselvik <Kalaiselvi_K@Dell.com>
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
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;
public class IfMgr {
static final Logger logger = LoggerFactory.getLogger(IfMgr.class);
- public static final String NETWORK_ROUTER_INTERFACE = "network:router_interface";
private HashMap<Uuid, VirtualRouter> vrouters;
private HashMap<Uuid, VirtualSubnet> vsubnets;
VirtualPort intf = vintfs.get(portId);
if (intf != null) {
intf.removeSelf();
- if (intf.getDeviceOwner().equalsIgnoreCase(NETWORK_ROUTER_INTERFACE)) {
+ if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
MacAddress ifaceMac = MacAddress.getDefaultInstance(intf.getMacAddress());
Ipv6Address llAddr = ipv6Utils.getIpv6LinkLocalAddressFromMac(ifaceMac);
vrouterv6IntfMap.remove(intf.getNetworkID(), intf);
}
for (IpAddress ipAddr : intf.getIpAddresses()) {
if (ipAddr.getIpv6Address() != null) {
- if (intf.getDeviceOwner().equalsIgnoreCase(NETWORK_ROUTER_INTERFACE)) {
+ if (intf.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
programNSFlowForAddress(intf, ipAddr.getIpv6Address(), false);
}
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
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.netvirt.ipv6service.nd.packet.rev160620.NeighborAdvertisePacket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborAdvertisePacketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborSolicitationPacket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborSolicitationPacketBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacket;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacketBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterSolicitationPacket;
public void run() {
if (type == Ipv6Constants.ICMPv6_NS_CODE) {
LOG.info("Received Neighbor Solicitation request");
+ processNeighborSolicitationRequest();
} else if (type == Ipv6Constants.ICMPv6_RS_CODE) {
LOG.info("Received Router Solicitation request");
processRouterSolicitationRequest();
}
}
+ private void processNeighborSolicitationRequest() {
+ byte[] data = packet.getPayload();
+ NeighborSolicitationPacket nsPdu = deserializeNSPacket(data);
+ Ipv6Header ipv6Header = (Ipv6Header) nsPdu;
+ if (ipv6Utils.validateChecksum(data, ipv6Header, nsPdu.getIcmp6Chksum()) == false) {
+ pktProccessedCounter++;
+ LOG.warn("Received Neighbor Solicitation with invalid checksum on {}. Ignoring the packet.",
+ packet.getIngress());
+ return;
+ }
+
+ BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
+ long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+ String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
+ VirtualPort port = ifMgr.obtainV6Interface(new Uuid(interfaceName));
+ if (port == null) {
+ pktProccessedCounter++;
+ LOG.warn("Port {} not found, skipping.", port);
+ return;
+ }
+
+ VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
+ if (routerPort == null) {
+ pktProccessedCounter++;
+ LOG.warn("Port {} is not associated to a Router, skipping NS request.", routerPort);
+ return;
+ }
+
+ if (!routerPort.getIpv6Addresses().contains(nsPdu.getTargetIpAddress())) {
+ pktProccessedCounter++;
+ LOG.warn("No Router interface with address {} on the network {}, skipping NS request.",
+ nsPdu.getTargetIpAddress(), port.getNetworkID());
+ return;
+ }
+
+ //formulate the NA response
+ NeighborAdvertisePacketBuilder naPacket = new NeighborAdvertisePacketBuilder();
+ updateNAResponse(nsPdu, routerPort, naPacket);
+ // serialize the response packet
+ byte[] txPayload = fillNeighborAdvertisementPacket(naPacket.build());
+ InstanceIdentifier<Node> outNode = packet.getIngress().getValue().firstIdentifierOf(Node.class);
+ TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
+ .setNode(new NodeRef(outNode))
+ .setEgress(packet.getIngress()).build();
+ // Tx the packet out of the controller.
+ if (pktService != null) {
+ LOG.debug("Transmitting the Neighbor Advt packet out on {}", packet.getIngress());
+ pktService.transmitPacket(input);
+ pktProccessedCounter++;
+ }
+ }
+
+ private NeighborSolicitationPacket deserializeNSPacket(byte[] data) {
+ NeighborSolicitationPacketBuilder nsPdu = new NeighborSolicitationPacketBuilder();
+ int bitOffset = 0;
+
+ try {
+ nsPdu.setDestinationMac(new MacAddress(
+ ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
+ bitOffset = bitOffset + 48;
+ nsPdu.setSourceMac(new MacAddress(
+ ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
+ bitOffset = bitOffset + 48;
+ nsPdu.setEthertype(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
+
+ bitOffset = Ipv6Constants.IPv6_HDR_START;
+ nsPdu.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
+ bitOffset = bitOffset + 4;
+ nsPdu.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset, 28)));
+ bitOffset = bitOffset + 28;
+ nsPdu.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
+ bitOffset = bitOffset + 16;
+ nsPdu.setNextHeader(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
+ bitOffset = bitOffset + 8;
+ nsPdu.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
+ bitOffset = bitOffset + 8;
+ nsPdu.setSourceIpv6(Ipv6Address.getDefaultInstance(
+ InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
+ bitOffset = bitOffset + 128;
+ nsPdu.setDestinationIpv6(Ipv6Address.getDefaultInstance(
+ InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
+ bitOffset = bitOffset + 128;
+
+ nsPdu.setIcmp6Type(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
+ bitOffset = bitOffset + 8;
+ nsPdu.setIcmp6Code(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
+ bitOffset = bitOffset + 8;
+ nsPdu.setIcmp6Chksum(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
+ bitOffset = bitOffset + 16;
+ nsPdu.setReserved(Long.valueOf(0));
+ bitOffset = bitOffset + 32;
+ nsPdu.setTargetIpAddress(Ipv6Address.getDefaultInstance(
+ InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
+ } catch (BufferException | UnknownHostException e) {
+ LOG.warn("Exception obtained when deserializing NS packet", e.toString());
+ }
+ return nsPdu.build();
+ }
+
+ private void updateNAResponse(NeighborSolicitationPacket pdu,
+ VirtualPort port, NeighborAdvertisePacketBuilder naPacket) {
+ long flag = 0;
+ if (!pdu.getSourceIpv6().equals(ipv6Utils.UNSPECIFIED_ADDR)) {
+ naPacket.setDestinationIpv6(pdu.getSourceIpv6());
+ flag = 0xE0; // Set Router, Solicited and Override Flag.
+ } else {
+ naPacket.setDestinationIpv6(ipv6Utils.ALL_NODES_MCAST_ADDR);
+ flag = 0xA0; // Set Router and Override Flag.
+ }
+ naPacket.setDestinationMac(pdu.getSourceMac());
+ naPacket.setEthertype(pdu.getEthertype());
+ naPacket.setSourceIpv6(pdu.getTargetIpAddress());
+ naPacket.setSourceMac(new MacAddress(port.getMacAddress()));
+ naPacket.setHopLimit(Ipv6Constants.ICMPv6_MAX_HOP_LIMIT);
+ naPacket.setIcmp6Type(Ipv6Constants.ICMPv6_NA_CODE);
+ naPacket.setIcmp6Code(pdu.getIcmp6Code());
+ flag = flag << 24;
+ naPacket.setFlags(flag);
+ naPacket.setFlowLabel(pdu.getFlowLabel());
+ naPacket.setIpv6Length(32);
+ naPacket.setNextHeader(pdu.getNextHeader());
+ naPacket.setOptionType((short)2);
+ naPacket.setTargetAddrLength((short)1);
+ naPacket.setTargetAddress(pdu.getTargetIpAddress());
+ naPacket.setTargetLlAddress(new MacAddress(port.getMacAddress()));
+ naPacket.setVersion(pdu.getVersion());
+ naPacket.setIcmp6Chksum(0);
+ return;
+ }
+
+ private byte[] icmp6NAPayloadtoByte(NeighborAdvertisePacket pdu) {
+ byte[] data = new byte[36];
+ Arrays.fill(data, (byte)0);
+
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.put((byte)pdu.getIcmp6Type().shortValue());
+ buf.put((byte)pdu.getIcmp6Code().shortValue());
+ buf.putShort((short)pdu.getIcmp6Chksum().intValue());
+ buf.putInt((int)pdu.getFlags().longValue());
+ try {
+ byte[] address = null;
+ address = InetAddress.getByName(pdu.getTargetAddress().getValue()).getAddress();
+ buf.put(address);
+ } catch (UnknownHostException e) {
+ LOG.error("Serializing NA target address failed", e);
+ }
+ buf.put((byte)pdu.getOptionType().shortValue());
+ buf.put((byte)pdu.getTargetAddrLength().shortValue());
+ buf.put(ipv6Utils.bytesFromHexString(pdu.getTargetLlAddress().getValue().toString()));
+ return data;
+ }
+
+ private byte[] fillNeighborAdvertisementPacket(NeighborAdvertisePacket pdu) {
+ ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length());
+
+ buf.put(ipv6Utils.convertEthernetHeaderToByte((EthernetHeader)pdu), 0, 14);
+ buf.put(ipv6Utils.convertIpv6HeaderToByte((Ipv6Header)pdu), 0, 40);
+ buf.put(icmp6NAPayloadtoByte(pdu), 0, pdu.getIpv6Length());
+ int checksum = ipv6Utils.calcIcmpv6Checksum(buf.array(), (Ipv6Header) pdu);
+ buf.putShort((Ipv6Constants.ICMPV6_OFFSET + 2), (short)checksum);
+ return (buf.array());
+ }
+
private void processRouterSolicitationRequest() {
byte[] data = packet.getPayload();
List<String> prefixList;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
List<FixedIps> ipList = port.getFixedIps();
for (FixedIps fixedip : ipList) {
- if (port.getDeviceOwner().equalsIgnoreCase(ifMgr.NETWORK_ROUTER_INTERFACE)) {
+ if (port.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
// Add router interface
ifMgr.addRouterIntf(port.getUuid(),
@Override
protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
LOG.info("update port notification handler is invoked...");
- if (update.getDeviceOwner().equalsIgnoreCase(ifMgr.NETWORK_ROUTER_INTERFACE)) {
+ if (update.getDeviceOwner().equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
ifMgr.updateRouterIntf(update.getUuid(), new Uuid(update.getDeviceId()), update.getFixedIps());
} else {
ifMgr.updateHostIntf(update.getUuid(), update.getFixedIps());
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
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.Ipv6Address;
+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.slf4j.Logger;
import org.slf4j.LoggerFactory;
return ipAddrList;
}
+ public List<Ipv6Address> getIpv6Addresses() {
+ List<Ipv6Address> ipv6AddrList = new ArrayList<>();
+ for (SubnetInfo subnetInfo : snetInfo.values()) {
+ if (subnetInfo.getIpAddr().getIpv6Address() instanceof Ipv6Address) {
+ ipv6AddrList.add(subnetInfo.getIpAddr().getIpv6Address());
+ }
+ }
+ if (deviceOwner.equalsIgnoreCase(Ipv6Constants.NETWORK_ROUTER_INTERFACE)) {
+ Ipv6ServiceUtils ipv6Utils = Ipv6ServiceUtils.getInstance();
+ Ipv6Address llAddr = ipv6Utils.getIpv6LinkLocalAddressFromMac(new MacAddress(macAddress));
+ ipv6AddrList.add(llAddr);
+ }
+ return ipv6AddrList;
+ }
+
public String getMacAddress() {
return macAddress;
}
public static final String IP_VERSION_V4 = "IPv4";
public static final String IP_VERSION_V6 = "IPv6";
+ public static final String NETWORK_ROUTER_INTERFACE = "network:router_interface";
}
private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceUtils.class);
private ConcurrentMap<String, InstanceIdentifier<Flow>> icmpv6FlowMap;
public static final Ipv6ServiceUtils instance = new Ipv6ServiceUtils();
+ public static Ipv6Address ALL_NODES_MCAST_ADDR;
+ public static Ipv6Address UNSPECIFIED_ADDR;
public Ipv6ServiceUtils() {
icmpv6FlowMap = new ConcurrentHashMap<>();
+ try {
+ UNSPECIFIED_ADDR = Ipv6Address.getDefaultInstance(
+ InetAddress.getByName("0:0:0:0:0:0:0:0").getHostAddress());
+ ALL_NODES_MCAST_ADDR = Ipv6Address.getDefaultInstance(InetAddress.getByName("FF02::1").getHostAddress());
+ } catch (UnknownHostException e) {
+ LOG.error("Ipv6ServiceUtils: Failed to instantiate the ipv6 address", e);
+ }
}
public static Ipv6ServiceUtils getInstance() {
StringBuffer interfaceID = new StringBuffer();
short u8byte = (short) (octets[0] & 0xff);
u8byte ^= 1 << 1;
- interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & u8byte), 2, "0"));
+ interfaceID.append(Integer.toHexString(0xFF & u8byte));
interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[1]), 2, "0"));
interfaceID.append(":");
- interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[2]), 2, "0"));
+ 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(StringUtils.leftPad(Integer.toHexString(0xFF & octets[4]), 2, "0"));
+ interfaceID.append(Integer.toHexString(0xFF & octets[4]));
interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[5]), 2, "0"));
Ipv6Address ipv6LLA = new Ipv6Address("fe80:0:0:0:" + interfaceID.toString());
import org.junit.Test;
import org.mockito.Mockito;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
+import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
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.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.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
}
+ @Test
+ public void testonPacketReceivedNeighborSolicitationWithInvalidPayload() throws Exception {
+ //incorrect checksum
+ pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(buildPacket(
+ "33 33 FF F5 00 00", // Destination MAC
+ "00 01 02 03 04 05", // Source MAC
+ "86 DD", // IPv6
+ "6E 00 00 00", // Version 6, traffic class E0, no flowlabel
+ "00 18", // Payload length
+ "3A", // Next header is ICMPv6
+ "FF", // Hop limit
+ "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // Source IP
+ "FF 02 00 00 00 00 00 00 00 00 00 01 FF F5 00 00", // Destination IP
+ "87", // ICMPv6 neighbor solicitation
+ "00", // Code
+ "67 3E", // Checksum (invalid, should be 67 3C)
+ "00 00 00 00", // ICMPv6 message body
+ "FE 80 00 00 00 00 00 00 C0 00 54 FF FE F5 00 00" // Target
+ )).build());
+ //wait on this thread until the async job is completed in the packet handler.
+ waitForPacketProcessing();
+ verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
+
+ //unavailable ip
+ when(ifMgrInstance.obtainV6Interface(any())).thenReturn(null);
+ counter = pktHandler.getPacketProcessedCounter();
+ pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(buildPacket(
+ "33 33 FF F5 00 00", // Destination MAC
+ "00 01 02 03 04 05", // Source MAC
+ "86 DD", // IPv6
+ "6E 00 00 00", // Version 6, traffic class E0, no flowlabel
+ "00 18", // Payload length
+ "3A", // Next header is ICMPv6
+ "FF", // Hop limit
+ "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", // Source IP
+ "FF 02 00 00 00 00 00 00 00 00 00 01 FF F5 00 00", // Destination IP
+ "87", // ICMPv6 neighbor solicitation
+ "00", // Code
+ "67 3C", // Checksum (valid)
+ "00 00 00 00", // ICMPv6 message body
+ "FE 80 00 00 00 00 00 00 C0 00 54 FF FE F5 00 00" // Target
+ )).build());
+ //wait on this thread until the async job is completed in the packet handler.
+ waitForPacketProcessing();
+ verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
+ }
+
@Test
public void testonPacketReceivedRouterSolicitationWithInvalidPayload() throws Exception {
// incorrect checksum in Router Solicitation
verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
}
+ @Test
+ public void testonPacketReceivedNeighborSolicitationWithValidPayload() throws Exception {
+ VirtualPort intf = Mockito.mock(VirtualPort.class);
+ when(intf.getNetworkID()).thenReturn(new Uuid("eeec9dba-d831-4ad7-84b9-00d7f65f0555"));
+ when(ifMgrInstance.getInterfaceNameFromTag(anyLong())).thenReturn("ddec9dba-d831-4ad7-84b9-00d7f65f052f");
+ when(ifMgrInstance.obtainV6Interface(any())).thenReturn(intf);
+ VirtualPort routerIntf = Mockito.mock(VirtualPort.class);
+ when(ifMgrInstance.getRouterV6InterfaceForNetwork(any())).thenReturn(routerIntf);
+ List<Ipv6Address> ipv6AddrList = new ArrayList<>();
+ when(routerIntf.getMacAddress()).thenReturn("08:00:27:FE:8F:95");
+ Ipv6ServiceUtils ipv6Utils = Ipv6ServiceUtils.getInstance();
+ Ipv6Address llAddr = ipv6Utils.getIpv6LinkLocalAddressFromMac(new MacAddress("08:00:27:FE:8F:95"));
+ ipv6AddrList.add(llAddr);
+ when(routerIntf.getIpv6Addresses()).thenReturn(ipv6AddrList);
+
+ InstanceIdentifier<Node> ncId = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, new NodeKey(new NodeId("openflow:1"))).build();
+ NodeConnectorRef ncRef = new NodeConnectorRef(ncId);
+
+ byte[] expected_payload = buildPacket(
+ "08 00 27 D4 10 BB", // Destination MAC
+ "08 00 27 FE 8F 95", // Source MAC
+ "86 DD", // Ethertype - IPv6
+ "60 00 00 00", // Version 6, traffic class 0, no flowlabel
+ "00 20", // Payload length
+ "3A", // Next header is ICMPv6
+ "FF", // Hop limit
+ "FE 80 00 00 00 00 00 00 0A 00 27 FF FE FE 8F 95", // Source IP
+ "FE 80 00 00 00 00 00 00 0A 00 27 FF FE D4 10 BB", // Destination IP
+ "88", // ICMPv6 neighbor advertisement.
+ "00", // Code
+ "17 D6", // Checksum (valid)
+ "E0 00 00 00", // Flags
+ "FE 80 00 00 00 00 00 00 0A 00 27 FF FE FE 8F 95", // Target Address
+ "02", // Type: Target Link-Layer Option
+ "01", // Option length
+ "08 00 27 FE 8F 95" // Target Link layer address
+ );
+
+ BigInteger mdata = new BigInteger(String.valueOf(0x1000000));
+ Metadata metadata = new MetadataBuilder().setMetadata(mdata).build();
+ MatchBuilder matchbuilder = new MatchBuilder().setMetadata(metadata);
+ pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(buildPacket(
+ "33 33 FF FE 8F 95", // Destination MAC
+ "08 00 27 D4 10 BB", // Source MAC
+ "86 DD", // IPv6
+ "60 00 00 00", // Version 6, traffic class 0, no flowlabel
+ "00 20", // Payload length
+ "3A", // Next header is ICMPv6
+ "FF", // Hop limit
+ "FE 80 00 00 00 00 00 00 0A 00 27 FF FE D4 10 BB", // Source IP
+ "FF 02 00 00 00 00 00 00 00 00 00 01 FF FE 8F 95", // Destination IP
+ "87", // ICMPv6 neighbor solicitation
+ "00", // Code
+ "A9 57", // Checksum (valid)
+ "00 00 00 00", // ICMPv6 message body
+ "FE 80 00 00 00 00 00 00 0A 00 27 FF FE FE 8F 95", // Target
+ "01", // ICMPv6 Option: Source Link Layer Address
+ "01", // Length
+ "08 00 27 D4 10 BB" // Link Layer Address
+ )).setIngress(ncRef).setMatch(matchbuilder.build()).build());
+ //wait on this thread until the async job is completed in the packet handler.
+ waitForPacketProcessing();
+ verify(pktProcessService, times(1)).transmitPacket(any(TransmitPacketInput.class));
+ verify(pktProcessService).transmitPacket(new TransmitPacketInputBuilder().setPayload(expected_payload).
+ setNode(new NodeRef(ncId)).
+ setEgress(ncRef).build());
+ }
+
@Test
public void testonPacketReceivedRouterSolicitationWithSingleSubnet() throws Exception {
VirtualPort intf = Mockito.mock(VirtualPort.class);
--- /dev/null
+/*
+ * Copyright (c) 2016 Red Hat, Inc. 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.ipv6service.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+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.MacAddress;
+
+/**
+ * Unit test fort {@link Ipv6ServiceUtilsTest}
+ */
+public class Ipv6ServiceUtilsTest {
+ private Ipv6ServiceUtils instance;
+
+ @Before
+ public void initTest() {
+ instance = Ipv6ServiceUtils.getInstance();
+ }
+
+ /**
+ * Test getIpv6LinkLocalAddressFromMac with different MACAddress values.
+ */
+ @Test
+ public void testgetIpv6LinkLocalAddressFromMac() {
+ MacAddress mac = new MacAddress("fa:16:3e:4e:18:0c");
+ Ipv6Address expectedLinkLocalAddress = new Ipv6Address("fe80:0:0:0:f816:3eff:fe4e:180c");
+ assertEquals(expectedLinkLocalAddress, instance.getIpv6LinkLocalAddressFromMac(mac));
+
+ mac = new MacAddress("fa:16:3e:4e:18:c0");
+ expectedLinkLocalAddress = new Ipv6Address("fe80:0:0:0:f816:3eff:fe4e:18c0");
+ assertEquals(expectedLinkLocalAddress, instance.getIpv6LinkLocalAddressFromMac(mac));
+
+ mac = new MacAddress("0a:16:03:04:08:0c");
+ expectedLinkLocalAddress = new Ipv6Address("fe80:0:0:0:816:3ff:fe04:80c");
+ assertEquals(expectedLinkLocalAddress, instance.getIpv6LinkLocalAddressFromMac(mac));
+
+ mac = new MacAddress("50:7B:9D:78:54:F3");
+ expectedLinkLocalAddress = new Ipv6Address("fe80:0:0:0:527b:9dff:fe78:54f3");
+ assertEquals(expectedLinkLocalAddress, instance.getIpv6LinkLocalAddressFromMac(mac));
+ }
+}
\ No newline at end of file