3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 """Traffic script - IPFIX listener."""
20 from ipaddress import IPv4Address, IPv6Address, AddressValueError
21 from scapy.layers.inet import IP, TCP, UDP
22 from scapy.layers.inet6 import IPv6
23 from scapy.layers.l2 import Ether
25 from resources.libraries.python.PacketVerifier import RxQueue, TxQueue, auto_pad
26 from resources.libraries.python.TrafficScriptArg import TrafficScriptArg
27 from resources.libraries.python.telemetry.IPFIXUtil import IPFIXHandler, \
32 """Check if IP address has the correct IPv4 address format.
34 :param ip: IP address.
36 :return: True in case of correct IPv4 address format,
37 otherwise return false.
41 IPv4Address(unicode(ip))
43 except (AttributeError, AddressValueError):
48 """Check if IP address has the correct IPv6 address format.
50 :param ip: IP address.
52 :return: True in case of correct IPv6 address format,
53 otherwise return false.
57 IPv6Address(unicode(ip))
59 except (AttributeError, AddressValueError):
64 """Send packets to VPP, then listen for IPFIX flow report. Verify that
65 the correct packet count was reported."""
66 args = TrafficScriptArg(
67 ['src_mac', 'dst_mac', 'src_ip', 'dst_ip', 'protocol', 'port', 'count']
70 dst_mac = args.get_arg('dst_mac')
71 src_mac = args.get_arg('src_mac')
72 src_ip = args.get_arg('src_ip')
73 dst_ip = args.get_arg('dst_ip')
74 tx_if = args.get_arg('tx_if')
76 protocol = args.get_arg('protocol')
77 source_port = int(args.get_arg('port'))
78 destination_port = int(args.get_arg('port'))
79 count = int(args.get_arg('count'))
84 # generate simple packet based on arguments
85 if valid_ipv4(src_ip) and valid_ipv4(dst_ip):
87 elif valid_ipv6(src_ip) and valid_ipv6(dst_ip):
90 raise ValueError("Invalid IP version!")
92 if protocol.upper() == 'TCP':
94 elif protocol.upper() == 'UDP':
97 raise ValueError("Invalid type of protocol!")
99 pkt_raw = (Ether(src=src_mac, dst=dst_mac) /
100 ip_version(src=src_ip, dst=dst_ip) /
101 protocol(sport=int(source_port),
102 dport=int(destination_port)))
104 # do not print details for sent packets when sending more than one
107 print("Sending more than one packet. Details will be filtered for "
112 pkt_pad = auto_pad(pkt_raw)
114 for _ in range(count):
115 txq.send(pkt_pad, verbose=verbose)
116 ignore.append(pkt_pad)
118 # allow scapy to recognize IPFIX headers and templates
119 ipfix = IPFIXHandler()
121 # get IPFIX template and data
123 pkt = rxq.recv(10, ignore=ignore, verbose=verbose)
125 raise RuntimeError("RX timeout")
126 if pkt.haslayer("IPFIXHeader"):
127 if pkt.haslayer("IPFIXTemplate"):
128 # create or update template for IPFIX data packets
129 ipfix.update_template(pkt)
130 elif pkt.haslayer("IPFIXData"):
131 data = pkt.getlayer(IPFIXData).fields
134 raise RuntimeError("Unable to parse IPFIX set after header.")
136 raise RuntimeError("Received non-IPFIX packet or IPFIX header "
139 # verify packet count
140 if data["packetTotalCount"] != count:
142 "IPFIX reported wrong packet count. Count was {0},"
143 " but should be {1}".format(data["packetTotalCount"], count))
144 # verify IP addresses
146 err = "{0} mismatch. Packets used {1}, but were classified as {2}."
148 if "IPv4_src" in keys:
149 if data["IPv4_src"] != src_ip:
151 err.format("Source IP", src_ip, data["IPv4_src"]))
152 if "IPv4_dst" in keys:
153 if data["IPv4_dst"] != dst_ip:
155 err.format("Destination IP", dst_ip, data["IPv4_dst"]))
157 if "IPv6_src" in keys:
158 if data["IPv6_src"] != src_ip:
160 err.format("Source IP", src_ip, data["IPv6_src"]))
161 if "IPv6_dst" in keys:
162 if data["IPv6_dst"] != dst_ip:
164 err.format("Source IP", src_ip, data["IPv6_dst"]))
165 # verify port numbers
166 for item in ("src_port", "tcp_src_port", "udp_src_port"):
168 if int(data[item]) != source_port:
170 err.format("Source port", source_port, data[item]))
173 for item in ("dst_port", "tcp_dst_port", "udp_dst_port"):
175 if int(data[item]) != destination_port:
177 err.format("Source port", destination_port, data[item]))
181 if "Protocol_ID" in keys:
182 if protocol == TCP and int(data["Protocol_ID"]) != 6:
183 raise RuntimeError("TCP Packets were classified as not TCP.")
184 if protocol == UDP and int(data["Protocol_ID"]) != 17:
185 raise RuntimeError("UDP Packets were classified as not UDP.")
189 if __name__ == "__main__":