2 # Copyright (c) 2016 Cisco and/or its affiliates.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 """Router advertisement check script."""
20 from resources.libraries.python.PacketVerifier import RxQueue
21 from resources.libraries.python.TrafficScriptArg import TrafficScriptArg
24 def mac_to_ipv6_linklocal(mac):
25 """Transfer MAC address into specific link-local IPv6 address.
27 :param mac: MAC address to be transferred.
29 :return: IPv6 link-local address.
32 # Remove the most common delimiters: dots, dashes, etc.
33 mac_value = int(mac.translate(None, ' .:-'), 16)
35 # Split out the bytes that slot into the IPv6 address
36 # XOR the most significant byte with 0x02, inverting the
37 # Universal / Local bit
38 high2 = mac_value >> 32 & 0xffff ^ 0x0200
39 high1 = mac_value >> 24 & 0xff
40 low1 = mac_value >> 16 & 0xff
41 low2 = mac_value & 0xffff
43 return 'fe80::{:04x}:{:02x}ff:fe{:02x}:{:04x}'.format(
44 high2, high1, low1, low2)
48 """Check packets on specific port and look for the Router Advertisement
52 args = TrafficScriptArg(['src_mac'])
54 rx_if = args.get_arg('rx_if')
55 src_mac = args.get_arg('src_mac')
60 # Check whether received packet contains layer RA and check other values
62 raise RuntimeError('ICMP echo Rx timeout')
64 if not ether.haslayer('ICMPv6ND_RA'):
65 raise RuntimeError('Not an RA packet received {0}'
66 .format(ether.__repr__()))
68 address = ipaddress.IPv6Address(unicode(ether['IPv6'].src))
69 link_local = ipaddress.IPv6Address(unicode(mac_to_ipv6_linklocal(src_mac)))
71 if address != link_local:
73 'Source address ({0}) not matching link local address({1})'.format(
76 if ether['IPv6'].hlim != 255:
77 raise RuntimeError('Hop limit not correct: {0}!=255'.format(
80 ra_code = ether['ICMPv6 Neighbor Discovery - Router Advertisement'].code
82 raise RuntimeError('ICMP code: {0} not correct. '.format(ra_code))
86 if __name__ == "__main__":