Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ansible/README.test.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ ansible-playbook test_sonic.yml -i {INVENTORY} --limit {DUT_NAME} -e testcase_na
```
- Requires switch connected to a VM set or PTF testbed

##### Network fuzz test
```
ansible-playbook test_sonic.yml -i {INVENTORY} --limit {DUT_NAME} -e testcase_name=network_fuzz -e testbed_name={TESTBED_NAME}
```
- Requires the switch connected to a PTF testbed

##### NTP test
```
ansible-playbook test_sonic.yml -i {INVENTORY} --limit {DUT_NAME} -e testcase_name=ntp -e testbed_name={TESTBED_NAME}
Expand Down
89 changes: 89 additions & 0 deletions ansible/roles/test/files/ptftests/network_fuzz_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import logging
import ptf

import random
from scapy.all import fuzz, RandIP, Raw
from scapy.layers.inet import IP, UDP, TCP
from ptf.base_tests import BaseTest
from ptf.testutils import *
from pprint import pformat


class NetworkFuzzTest(BaseTest):
def __init__(self):
BaseTest.__init__(self)

def log(self, message):
logging.info(message)

def setUp(self):
BaseTest.setUp(self)
self.dataplane = ptf.dataplane_instance
self.test_params = test_params_get()
self.dataplane.flush()

def build_fuzz_ip_packet(self, src_ip, dest_ip):
return fuzz(IP(src=src_ip, dst=dest_ip, version=4))

def build_fuzz_tcp_packet(self, src_ip, dest_ip, dport=None):
self.log("Building TCP packet for {}->{} with dport={}".format(
src_ip, dest_ip, dport
))
if dport:
layer4 = fuzz(TCP(dport=int(dport)))
else:
layer4 = fuzz(TCP())
return IP(src=src_ip, dst=dest_ip)/layer4/fuzz(Raw())

def build_fuzz_udp_packet(self, src_ip, dest_ip, dport=None):
self.log("Building UDP packet for {}->{} with dport={}".format(
src_ip, dest_ip, dport
))
if dport:
layer4 = fuzz(UDP(dport=int(dport)))
else:
layer4 = fuzz(UDP())
return IP(src=src_ip, dst=dest_ip)/layer4/fuzz(Raw())

def check_param(self, param, default, required):
if param not in self.test_params:
if required:
raise Exception("Test parameter '%s' is required" % param)
self.test_params[param] = default

def runTest(self):
self.log('test_params:\n' + pformat(self.test_params))
self.check_param('port_list', '', required=True)
self.test_params['port_list'] = self.test_params['port_list'].split(',')
self.check_param('packet_type', 'ip', required=False)
self.check_param('packet_count', 1, required=False)
self.check_param('src_ip', None, required=False)
self.check_param('dest_ip', None, required=False)
self.check_param('dest_port', None, required=False)

if not self.test_params['src_ip']:
self.test_params['src_ip'] = RandIP()
if not self.test_params['dest_ip']:
self.test_params['dest_ip'] = RandIP()

common_params = {
'src_ip': self.test_params['src_ip'],
'dest_ip': self.test_params['dest_ip'],
}
if self.test_params['packet_type'] == 'ip':
pkt = self.build_fuzz_ip_packet(**common_params)
elif self.test_params['packet_type'] == 'tcp':
pkt = self.build_fuzz_tcp_packet(dport=self.test_params['dest_port'],
**common_params)
elif self.test_params['packet_type'] == 'udp':
pkt = self.build_fuzz_udp_packet(dport=self.test_params['dest_port'],
**common_params)
else:
raise ValueError('Unknown packet type: ' + self.test_params['packet_type'])

for i in range(int(self.test_params['packet_count'])):
# Choose randomly from the port list
port = random.choice(self.test_params['port_list'])
self.log("Sending test packet #{} to device port {}: {}".format(i, port, pkt.summary()))
send(self, port, pkt)
self.dataplane.flush()
77 changes: 77 additions & 0 deletions ansible/roles/test/tasks/network_fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
- block:
- name: Gather interface information if not available
interface_facts:
when: ansible_interface_facts is not defined

- name: Read the current interfaces status
shell: show interfaces status | head
register: show_interface_status

- name: Store the indices for the ports that operationally 'up'
set_fact: candidate_ports="{{ candidate_ports|default([]) + [minigraph_port_indices[item.device]] }}"
with_items: ansible_interface_facts.values()
when: item.active and (item.device | search('Ethernet'))

- name: Get the interface name that is connect to the first BGP neighbor
set_fact:
bgp_neighbor_iface: "{{ item['attachto'] }}"
with_items: "{{ minigraph_interfaces + minigraph_portchannel_interfaces}}"
when: minigraph_bgp[0]['peer_addr'] == item['addr']

- name: If bgp_neighbor_iface is a portchannel, get the port index of the first member
set_fact:
bgp_neighbor_port: "{{ minigraph_port_indices[minigraph_portchannels[bgp_neighbor_iface]['members'][0]] }}"
when: "'PortChannel' in bgp_neighbor_iface"

- name: If bgp_neighbor_iface is not a portchannel, get the port index
set_fact:
bgp_neighbor_port: "{{ minigraph_port_indices[bgp_neighbor_iface] }}"
when: "'PortChannel' not in bgp_neighbor_iface"

- name: Copy tests to the PTF container
copy: src=roles/test/files/ptftests dest=/root
delegate_to: "{{ ptf_host }}"

- name: Spoof random TCP packets from the BGP neighbor to the BGP port on the SONiC switch
include: roles/test/tasks/network_fuzz/tcp_fuzz_random_port.yml
vars:
test_ports: "{{ [bgp_neighbor_port] }}"
src_ip: "{{ minigraph_bgp[0]['addr'] }}"
dest_ip: "{{ minigraph_bgp[0]['peer_addr'] }}"
dest_port: 179
packet_count: 1000

- name: Run IP packet fuzz test to random ports
include: roles/test/tasks/network_fuzz/ip_fuzz_random_port.yml
vars:
packet_count: 10000
test_ports: "{{ candidate_ports }}"

- name: Run TCP packet fuzz test to random ports
include: roles/test/tasks/network_fuzz/tcp_fuzz_random_port.yml
vars:
packet_count: 10000
test_ports: "{{ candidate_ports }}"

- name: Run UDP packet fuzz test to random ports
include: roles/test/tasks/network_fuzz/udp_fuzz_random_port.yml
vars:
packet_count: 10000
test_ports: "{{ candidate_ports }}"

- name: Run IP packet fuzz test to a single port
include: roles/test/tasks/network_fuzz/ip_fuzz_random_port.yml
vars:
packet_count: 30000
test_ports: "{{ candidate_ports[0] }}"

rescue:
- name: Do basic sanity check after a failure and allow recovery
include: base_sanity.yml
vars:
recover: "{{ allow_recover }}"

- name: Validate all interfaces are up and allow recovery
include: interface.yml
vars:
recover: "{{ allow_recover }}"
34 changes: 34 additions & 0 deletions ansible/roles/test/tasks/network_fuzz/ip_fuzz_random_port.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
- block:
- set_fact:
testname: ip_fuzz_random_port
run_dir: /tmp
out_dir: /tmp/ansible-loganalyzer-results
tests_location: "{{ 'roles/test/tasks' }}"

- name: Initialize loganalyzer
include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml

- include: roles/test/tasks/ptf_runner.yml
vars:
ptf_test_name: IP packet fuzz test
ptf_test_dir: ptftests
ptf_test_path: network_fuzz_test.NetworkFuzzTest
ptf_platform: remote
ptf_platform_dir: ptftests
ptf_test_params:
- port_list='{{ test_ports | join(",") }}'
- packet_type='ip'
- packet_count='{{ packet_count | default(1) }}'
- src_ip='{{ src_ip | default(None) }}'
- dest_ip='{{ dest_ip | default(None) }}'
ptf_extra_options: "--relax --debug info --log-file /tmp/network_fuzz.NetworkFuzzTest.IP.{{lookup('pipe','date +%Y-%m-%d-%H:%M:%S')}}.log"

- name: Check if logs contain any error messages
include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
- include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml

- name: Do a basic sanity check
include: roles/test/tasks/base_sanity.yml

- name: Validate all interfaces are still up
include: roles/test/tasks/interface.yml
35 changes: 35 additions & 0 deletions ansible/roles/test/tasks/network_fuzz/tcp_fuzz_random_port.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
- block:
- set_fact:
testname: tcp_fuzz_random_port
run_dir: /tmp
out_dir: /tmp/ansible-loganalyzer-results
tests_location: "{{ 'roles/test/tasks' }}"

- name: Initialize loganalyzer
include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml

- include: roles/test/tasks/ptf_runner.yml
vars:
ptf_test_name: TCP packet fuzz test
ptf_test_dir: ptftests
ptf_test_path: network_fuzz_test.NetworkFuzzTest
ptf_platform: remote
ptf_platform_dir: ptftests
ptf_test_params:
- port_list='{{ test_ports | join(",") }}'
- packet_type='tcp'
- packet_count='{{ packet_count | default(1) }}'
- src_ip='{{ src_ip | default(None) }}'
- dest_ip='{{ dest_ip | default(None) }}'
- dest_port='{{ dest_port | default(None) }}'
ptf_extra_options: "--relax --debug info --log-file /tmp/network_fuzz.NetworkFuzzTest.TCP.{{lookup('pipe','date +%Y-%m-%d-%H:%M:%S')}}.log"

- name: Check if logs contain any error messages
include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
- include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml

- name: Do a basic sanity check
include: roles/test/tasks/base_sanity.yml

- name: Validate all interfaces are still up
include: roles/test/tasks/interface.yml
35 changes: 35 additions & 0 deletions ansible/roles/test/tasks/network_fuzz/udp_fuzz_random_port.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
- block:
- set_fact:
testname: udp_fuzz_random_port
run_dir: /tmp
out_dir: /tmp/ansible-loganalyzer-results
tests_location: "{{ 'roles/test/tasks' }}"

- name: Initialize loganalyzer
include: roles/test/files/tools/loganalyzer/loganalyzer_init.yml

- include: roles/test/tasks/ptf_runner.yml
vars:
ptf_test_name: UDP packet fuzz test
ptf_test_dir: ptftests
ptf_test_path: network_fuzz_test.NetworkFuzzTest
ptf_platform: remote
ptf_platform_dir: ptftests
ptf_test_params:
- port_list='{{ test_ports | join(",") }}'
- packet_type='udp'
- packet_count='{{ packet_count | default(1) }}'
- src_ip='{{ src_ip | default(None) }}'
- dest_ip='{{ dest_ip | default(None) }}'
- dest_port='{{ dest_port | default(None) }}'
ptf_extra_options: "--relax --debug info --log-file /tmp/network_fuzz.NetworkFuzzTest.UDP.{{lookup('pipe','date +%Y-%m-%d-%H:%M:%S')}}.log"

- name: Check if logs contain any error messages
include: roles/test/files/tools/loganalyzer/loganalyzer_analyze.yml
- include: roles/test/files/tools/loganalyzer/loganalyzer_end.yml

- name: Do a basic sanity check
include: roles/test/tasks/base_sanity.yml

- name: Validate all interfaces are still up
include: roles/test/tasks/interface.yml
4 changes: 4 additions & 0 deletions ansible/roles/test/vars/testcases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ testcases:
filename: neighbour-mac-noptf.yml
topologies: [t0, t0-64, t0-64-32, t0-116, t1, t1-lag, t1-64-lag, ptf32, ptf64]

network_fuzz:
filename: network_fuzz.yml
topologies: [t0, t0-16, t0-56, t0-64, t0-116, t1]

ntp:
filename: ntp.yml
topologies: [t0, t0-56, t0-64, t0-64-32, t0-116, t1, t1-lag, t1-64-lag, ptf32, ptf64]
Expand Down