1010import com .cisco .trex .stateless .model .StreamRxStats ;
1111import com .cisco .trex .stateless .model .StreamVM ;
1212import com .cisco .trex .stateless .model .TRexClientResult ;
13+ import com .cisco .trex .stateless .model .port .PortVlan ;
14+ import com .google .common .collect .Lists ;
1315import com .google .common .net .InetAddresses ;
1416import java .net .Inet6Address ;
1517import java .net .UnknownHostException ;
18+ import java .util .AbstractMap ;
1619import java .util .ArrayList ;
1720import java .util .Arrays ;
1821import java .util .Collections ;
1922import java .util .HashMap ;
23+ import java .util .LinkedList ;
2024import java .util .List ;
2125import java .util .Map ;
2226import java .util .Optional ;
27+ import java .util .Queue ;
2328import java .util .function .Predicate ;
2429import java .util .stream .Collectors ;
2530import java .util .stream .Stream ;
2631import org .apache .commons .lang3 .StringUtils ;
32+ import org .pcap4j .packet .Dot1qVlanTagPacket ;
2733import org .pcap4j .packet .EthernetPacket ;
2834import org .pcap4j .packet .IcmpV6CommonPacket ;
2935import org .pcap4j .packet .IcmpV6CommonPacket .IpV6NeighborDiscoveryOption ;
4854
4955public class IPv6NeighborDiscoveryService {
5056
57+ private static final EtherType QInQ =
58+ new EtherType ((short ) 0x88a8 , "802.1Q Provider Bridge (Q-in-Q)" );
5159 private TRexClient tRexClient ;
5260
5361 public IPv6NeighborDiscoveryService (TRexClient tRexClient ) {
@@ -67,6 +75,7 @@ public Map<String, Ipv6Node> scan(int portIdx, int timeDuration, String dstIP, S
6775 }
6876
6977 String srcMac = portStatus .getAttr ().getLayerConiguration ().getL2Configuration ().getSrc ();
78+ PortVlan vlan = portStatus .getAttr ().getVlan ();
7079
7180 Packet pingPkt =
7281 buildICMPV6EchoReq (
@@ -91,8 +100,10 @@ public Map<String, Ipv6Node> scan(int portIdx, int timeDuration, String dstIP, S
91100 String nodeIp = ipV6Packet .getHeader ().getSrcAddr ().toString ().substring (1 );
92101 String nodeMac = getLinkLayerAddress (ipV6Packet );
93102
94- nsNaStreams .add (buildStream (buildICMPV6NSPkt (srcMac , nodeMac , nodeIp , srcIP )));
95- nsNaStreams .add (buildStream (buildICMPV6NAPkt (srcMac , nodeMac , nodeIp , srcIP )));
103+ nsNaStreams .add (
104+ buildStream (buildICMPV6NSPkt (vlan , srcMac , nodeMac , nodeIp , srcIP )));
105+ nsNaStreams .add (
106+ buildStream (buildICMPV6NAPkt (vlan , srcMac , nodeMac , nodeIp , srcIP )));
96107 });
97108 }
98109
@@ -183,15 +194,16 @@ public EthernetPacket sendNeighborSolicitation(int portIdx, int timeout, String
183194 throw new ServiceModeRequiredException ();
184195 }
185196 String srcMac = portStatus .getAttr ().getLayerConiguration ().getL2Configuration ().getSrc ();
186- return sendNeighborSolicitation (portIdx , timeout , srcMac , dstIp );
197+ PortVlan vlan = portStatus .getAttr ().getVlan ();
198+ return sendNeighborSolicitation (vlan , portIdx , timeout , srcMac , null , dstIp );
187199 }
188200
189201 public EthernetPacket sendNeighborSolicitation (
190- int portIdx , int timeout , String srcMac , String dstIp ) {
202+ PortVlan vlan , int portIdx , int timeout , String srcMac , String srcIp , String dstIp ) {
191203 long endTs = System .currentTimeMillis () + timeout * 1000 ;
192204
193205 Packet icmpv6NSPkt =
194- buildICMPV6NSPkt (srcMac , multicastMacFromIPv6 (dstIp ).toString (), dstIp , null );
206+ buildICMPV6NSPkt (vlan , srcMac , multicastMacFromIPv6 (dstIp ).toString (), dstIp , srcIp );
195207
196208 tRexClient .startStreamsIntermediate (portIdx , Arrays .asList (buildStream (icmpv6NSPkt )));
197209
@@ -239,14 +251,45 @@ public EthernetPacket sendNeighborSolicitation(
239251 return na ;
240252 }
241253
254+ private static AbstractMap .SimpleEntry <EtherType , Packet .Builder > buildVlan (
255+ IpV6Packet .Builder ipv6Builder , PortVlan vlan ) {
256+ Queue <Integer > vlanTags = new LinkedList <>(Lists .reverse (vlan .getTags ()));
257+ Packet .Builder resultPayloadBuilder = ipv6Builder ;
258+ EtherType resultEtherType = EtherType .IPV6 ;
259+
260+ if (vlanTags .peek () != null ) {
261+ Dot1qVlanTagPacket .Builder vlanInsideBuilder = new Dot1qVlanTagPacket .Builder ();
262+ vlanInsideBuilder
263+ .type (EtherType .IPV6 )
264+ .vid (vlanTags .poll ().shortValue ())
265+ .payloadBuilder (ipv6Builder );
266+
267+ resultPayloadBuilder = vlanInsideBuilder ;
268+ resultEtherType = EtherType .DOT1Q_VLAN_TAGGED_FRAMES ;
269+
270+ if (vlanTags .peek () != null ) {
271+ Dot1qVlanTagPacket .Builder vlanOutsideBuilder = new Dot1qVlanTagPacket .Builder ();
272+ vlanOutsideBuilder
273+ .type (EtherType .DOT1Q_VLAN_TAGGED_FRAMES )
274+ .vid (vlanTags .poll ().shortValue ())
275+ .payloadBuilder (vlanInsideBuilder );
276+ resultPayloadBuilder = vlanOutsideBuilder ;
277+ resultEtherType = QInQ ;
278+ }
279+ }
280+
281+ return new AbstractMap .SimpleEntry <>(resultEtherType , resultPayloadBuilder );
282+ }
283+
242284 private Map <String , EthernetPacket > sendNSandIcmpV6Req (
243285 int portIdx , int timeDuration , String srcMac , String dstIp ) {
244286 long endTs = System .currentTimeMillis () + timeDuration * 1000 ;
245287 TRexClientResult <PortStatus > portStatusResult = tRexClient .getPortStatus (portIdx );
288+ PortVlan vlan = portStatusResult .get ().getAttr ().getVlan ();
246289
247290 Packet pingPkt = buildICMPV6EchoReq (null , srcMac , null , dstIp );
248291 Packet icmpv6NSPkt =
249- buildICMPV6NSPkt (srcMac , multicastMacFromIPv6 (dstIp ).toString (), dstIp , null );
292+ buildICMPV6NSPkt (vlan , srcMac , multicastMacFromIPv6 (dstIp ).toString (), dstIp , null );
250293
251294 List <com .cisco .trex .stateless .model .Stream > stlStreams =
252295 Stream .of (buildStream (pingPkt ), buildStream (icmpv6NSPkt )).collect (Collectors .toList ());
@@ -317,7 +360,8 @@ private com.cisco.trex.stateless.model.Stream buildStream(Packet pkt) {
317360 null );
318361 }
319362
320- private Packet buildICMPV6NSPkt (String srcMac , String dstMac , String dstIp , String srcIp ) {
363+ private Packet buildICMPV6NSPkt (
364+ PortVlan vlan , String srcMac , String dstMac , String dstIp , String srcIp ) {
321365 EthernetPacket .Builder ethBuilder = new EthernetPacket .Builder ();
322366 try {
323367
@@ -356,12 +400,19 @@ private Packet buildICMPV6NSPkt(String srcMac, String dstMac, String dstIp, Stri
356400 .payloadBuilder (icmpCommonPktBuilder )
357401 .correctLengthAtBuild (true );
358402
403+ AbstractMap .SimpleEntry <EtherType , Packet .Builder > payload =
404+ new AbstractMap .SimpleEntry <>(EtherType .IPV6 , ipV6Builder );
405+ if (!vlan .getTags ().isEmpty ()) {
406+ payload = buildVlan (ipV6Builder , vlan );
407+ }
408+
359409 ethBuilder
360- .type (EtherType .IPV6 )
361410 .srcAddr (MacAddress .getByName (srcMac ))
362411 .dstAddr (MacAddress .getByName (dstMac ))
363- .payloadBuilder (ipV6Builder )
412+ .type (payload .getKey ())
413+ .payloadBuilder (payload .getValue ())
364414 .paddingAtBuild (true );
415+
365416 } catch (UnknownHostException ignored ) {
366417 // Do nothing
367418 }
@@ -396,7 +447,8 @@ private static String getLinkLayerAddress(IpV6Packet pkt) {
396447 return ByteArrays .toHexString (linkLayerAddress , ":" );
397448 }
398449
399- private Packet buildICMPV6NAPkt (String srcMac , String dstMac , String dstIp , String srcIP ) {
450+ private Packet buildICMPV6NAPkt (
451+ PortVlan vlan , String srcMac , String dstMac , String dstIp , String srcIP ) {
400452 final String specifiedSrcIP = srcIP != null ? srcIP : generateIPv6AddrFromMAC (srcMac );
401453
402454 EthernetPacket .Builder ethBuilder = new EthernetPacket .Builder ();
@@ -438,12 +490,19 @@ private Packet buildICMPV6NAPkt(String srcMac, String dstMac, String dstIp, Stri
438490 .payloadBuilder (icmpCommonPktBuilder )
439491 .correctLengthAtBuild (true );
440492
493+ AbstractMap .SimpleEntry <EtherType , Packet .Builder > payload =
494+ new AbstractMap .SimpleEntry <>(EtherType .IPV6 , ipV6Builder );
495+ if (!vlan .getTags ().isEmpty ()) {
496+ payload = buildVlan (ipV6Builder , vlan );
497+ }
498+
441499 ethBuilder
442- .type (EtherType .IPV6 )
443500 .srcAddr (MacAddress .getByName (srcMac ))
444501 .dstAddr (MacAddress .getByName ("33:33:00:00:00:01" ))
445- .payloadBuilder (ipV6Builder )
502+ .type (payload .getKey ())
503+ .payloadBuilder (payload .getValue ())
446504 .paddingAtBuild (true );
505+
447506 } catch (UnknownHostException ignored ) {
448507 // Do nothing
449508 }
0 commit comments