|
| 1 | +''' |
| 2 | +Owner: Dor Marcus <[email protected]> |
| 3 | +Created on: 12/09/2017 |
| 4 | +Description: This file contains the Decapasulation test for SONIC, to test Decapsulation of IPv4 with double and triple encapsulated packets |
| 5 | + |
| 6 | + Design is available in https://github.com/Azure/SONiC/wiki/IPv4-Decapsulation-test |
| 7 | + |
| 8 | +Precondition: Before the test start, all routes need to be defined as in the route_info.txt file, in addition to the decap rule that need to be set as the dspc_mode |
| 9 | +topology: The test need to run on non-lag systems with at least 31 active ports |
| 10 | + |
| 11 | +Usage: Examples of how to start the test |
| 12 | + ptf --test-dir /root/dor/ ip_decap_test_red --platform remote -t "verbose=True;route_info='/tmp/route_info.txt';lo_ip='10.1.0.32';router_mac='00:02:03:04:05:00';dscp_mode='pipe'" --log-dir /tmp/logs --verbose |
| 13 | +Parameters: route_info - The route_info file location |
| 14 | + lo_ip - The loop_back IP that is configured in the decap rule |
| 15 | + router_mac - The mac of the router_mac |
| 16 | + dscp_mode - The rule for the dscp parameter in the decap packet that is configured in the JSON file ('pipe' for inner and 'uniform' for outer) |
| 17 | + |
| 18 | +''' |
| 19 | + |
| 20 | +#--------------------------------------------------------------------- |
| 21 | +# Global imports |
| 22 | +#--------------------------------------------------------------------- |
| 23 | +import random |
| 24 | +import time |
| 25 | +import logging |
| 26 | +import ptf.packet as scapy |
| 27 | +import socket |
| 28 | +import ptf.dataplane as dataplane |
| 29 | + |
| 30 | +from ptf.testutils import * |
| 31 | +from ptf.mask import Mask |
| 32 | +import ipaddress |
| 33 | + |
| 34 | +import os |
| 35 | +import unittest |
| 36 | + |
| 37 | +import ptf |
| 38 | +from ptf.base_tests import BaseTest |
| 39 | +from ptf import config |
| 40 | +import ptf.dataplane as dataplane |
| 41 | +import ptf.testutils as testutils |
| 42 | + |
| 43 | +import pprint |
| 44 | +from router_utils import * |
| 45 | + |
| 46 | + |
| 47 | +#--------------------------------------------------------------------- |
| 48 | +# Global variables |
| 49 | +#--------------------------------------------------------------------- |
| 50 | +PREFIX_AND_PORT_SPLITTER=" " |
| 51 | +PORT_LIST_SPLITTER="," |
| 52 | +PORT_COUNT = 31 |
| 53 | + |
| 54 | +class DecapPacketTest(BaseTest, RouterUtility): |
| 55 | + def __init__(self): |
| 56 | + BaseTest.__init__(self) |
| 57 | + self.test_params = testutils.test_params_get() |
| 58 | + #----------------------------------------------------------------- |
| 59 | + def setUp(self): |
| 60 | + ''' |
| 61 | + @summary: Setup for the test |
| 62 | + ''' |
| 63 | + self.dataplane = ptf.dataplane_instance |
| 64 | + self.router_mac = self.test_params['router_mac'] |
| 65 | + #----------------------------------------------------------------- |
| 66 | + |
| 67 | + def send_and_verify(self, dst_ip, expected_ports, src_port, triple_encap = False): |
| 68 | + ''' |
| 69 | + @summary: This function builds encap packet, send and verify their arrival, When a packet will not arrived as expected an exeption will be throwen |
| 70 | + @dst_ip: the destination ip for the inner IP header |
| 71 | + @expected_ports: list of ports that a packet can arrived from |
| 72 | + @src_port: the physical port that the packet will be sent from |
| 73 | + @triple_encap: Bool if to send triple encapsulated packet |
| 74 | + ''' |
| 75 | + #setting parameters |
| 76 | + src_mac = self.dataplane.get_mac(0, 0) |
| 77 | + dst_mac = '00:11:22:33:44:55' |
| 78 | + inner_src_ip = '2.2.2.2' |
| 79 | + router_mac = self.test_params['router_mac'] |
| 80 | + dscp_in = random.randint(0, 32) |
| 81 | + tos_in = dscp_in << 2 |
| 82 | + dscp_out = random.randint(0, 32) |
| 83 | + tos_out = dscp_out << 2 |
| 84 | + if ("pipe" == self.test_params['dscp_mode']): |
| 85 | + exp_tos = tos_in |
| 86 | + elif("uniform" == self.test_params['dscp_mode']): |
| 87 | + exp_tos = tos_out |
| 88 | + else: |
| 89 | + print("ERROR: no dscp is configured") |
| 90 | + exit() |
| 91 | + |
| 92 | + #building the packets and the expected packets |
| 93 | + if (not triple_encap): |
| 94 | + #for the double encap packet we will use IP header with TCP header without mac |
| 95 | + inner_pkt = simple_ip_only_packet(ip_dst=dst_ip, ip_src=inner_src_ip, ip_ttl=64) |
| 96 | + #after the decap process the retuning packet will be normal tcp packet, The TTL is taked from the inner layer and redused by one |
| 97 | + exp_pkt = simple_tcp_packet(pktlen=114, |
| 98 | + eth_dst=dst_mac, |
| 99 | + eth_src=router_mac, |
| 100 | + ip_dst=dst_ip, |
| 101 | + ip_src=inner_src_ip, |
| 102 | + ip_tos=exp_tos, |
| 103 | + ip_ttl=63) |
| 104 | + else: |
| 105 | + #Building triple encap packet with SCAPY, because there is no PTF function for it, I use the defualt values for the TCP header |
| 106 | + tcp_hdr = scapy.TCP(sport=1234, dport=80, flags="S", chksum=0) |
| 107 | + inner_pkt2 = scapy.IP(src='4.4.4.4', dst='3.3.3.3', tos=0, ttl=64, id=1, ihl=None) / tcp_hdr |
| 108 | + inner_pkt = scapy.IP(src=inner_src_ip, dst=dst_ip, tos=tos_in, ttl=64, id=1, ihl=None,proto =4) / inner_pkt2 |
| 109 | + inner_pkt = inner_pkt/("".join([chr(x) for x in xrange(100 - len(inner_pkt))])) |
| 110 | + #The expected packet is also built by scapy, and the TTL is taked from the inner layer and redused by one |
| 111 | + exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac)/inner_pkt |
| 112 | + exp_pkt['IP'].tos = exp_tos #this parameter is taken by the decap rule configuration |
| 113 | + exp_pkt['IP'].ttl = 63 |
| 114 | + |
| 115 | + pkt = simple_ipv4ip_packet( |
| 116 | + eth_dst=router_mac, |
| 117 | + eth_src=src_mac, |
| 118 | + ip_src='1.1.1.1', |
| 119 | + ip_dst=self.test_params['lo_ip'], |
| 120 | + ip_tos=tos_out, |
| 121 | + ip_ttl=random.randint(2, 63), |
| 122 | + inner_frame=inner_pkt) |
| 123 | + |
| 124 | + #send and verify the return packets |
| 125 | + masked_exp_pkt = Mask(exp_pkt) |
| 126 | + masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") |
| 127 | + masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") |
| 128 | + send_packet(self, src_port, pkt) |
| 129 | + (match_index, rcv_pkt) = verify_packet_any_port(self, masked_exp_pkt, expected_ports) |
| 130 | + #----------------------------------------------------------------- |
| 131 | + |
| 132 | + def runTest(self): |
| 133 | + test_result = True |
| 134 | + random.seed(1) |
| 135 | + self.load_route_info(self.test_params["route_info"]) |
| 136 | + default_route_ports =[] |
| 137 | + unicast_ip = 'none' |
| 138 | + unicast_dst_port = [] |
| 139 | + print self.route_info.iteritems() |
| 140 | + #running on the routes_info file and extractin ECMP route and unicast route |
| 141 | + for prefix, port_index_list in self.route_info.iteritems(): |
| 142 | + dest_ip_addr = prefix.split("/")[0] |
| 143 | + |
| 144 | + if (self.is_ipv6_address(dest_ip_addr)): |
| 145 | + continue |
| 146 | + |
| 147 | + if (len(port_index_list) > 1): |
| 148 | + for port_index in port_index_list: |
| 149 | + if (len(port_index)> 0): |
| 150 | + default_route_ports.append(int(port_index)) |
| 151 | + default_route_dst_ip = dest_ip_addr |
| 152 | + elif (len(port_index_list) == 1): |
| 153 | + unicast_ip = dest_ip_addr |
| 154 | + unicast_dst_port = [int(port_index_list[0])] |
| 155 | + #when found unicast and ECMP routes stop |
| 156 | + if ((unicast_ip != 'none') and (len(default_route_ports) != 0)): |
| 157 | + break |
| 158 | + |
| 159 | + #Sending double and triple encapsulated packets from all ports with unicast and ECMP IP routes |
| 160 | + for src_port in range(PORT_COUNT): |
| 161 | + |
| 162 | + try: |
| 163 | + self.send_and_verify(default_route_dst_ip, default_route_ports, src_port) |
| 164 | + except: |
| 165 | + print("ERROR: failed to send encap packet with default route from port: " + str(src_port)) |
| 166 | + test_result = False |
| 167 | + |
| 168 | + try: |
| 169 | + self.send_and_verify(default_route_dst_ip, default_route_ports, src_port, True) |
| 170 | + except: |
| 171 | + print("ERROR: failed to send triple encap packet with default route from port: " + str(src_port)) |
| 172 | + test_result = False |
| 173 | + |
| 174 | + try: |
| 175 | + self.send_and_verify(unicast_ip, unicast_dst_port, src_port) |
| 176 | + except: |
| 177 | + print("ERROR: failed to send encap packet with unicast route from port: " + str(src_port)) |
| 178 | + test_result = False |
| 179 | + |
| 180 | + try: |
| 181 | + self.send_and_verify(unicast_ip, unicast_dst_port, src_port, True) |
| 182 | + except: |
| 183 | + print("ERROR: faield to send triple encap packet with unicast route from port: " + str(src_port)) |
| 184 | + test_result = False |
| 185 | + |
| 186 | + assert(test_result) |
| 187 | +#--------------------------------------------------------------------- |
| 188 | + |
| 189 | + |
0 commit comments