TNSM_Latency_Prediction / code / control / test_scripts / send.py
send.py
Raw
#!/usr/bin/env python
import sys, os , socket, random, struct, time
import argparse

from scapy.all import sendp, send, get_if_list, get_if_hwaddr, bind_layers
from scapy.all import Packet
from scapy.all import Ether, IP, UDP, TCP, Raw, IPv6, Dot1Q
from scapy.fields import *

"""
sudo python3.7 send.py \
 --interface <intf> \
 --packets 1000 \
 --ethernet AA:BB:CC:DD:EE:FF,00:11:22:33:44:55 \
 --mpls 1,1000 \
 --ip 192.168.1.1,192.168.2.2,0x17 \
 --udp 1000 \
 --intshim \
 --intmeta \
 --imstack 1,123456 \
 --bytes 1000

sudo python3.8 send.py \
 --interface eno3 \
 --packets 1 \
 --ethernet AA:BB:CC:DD:EE:FF,00:11:22:33:44:55 \
 --mpls 1,1000 \
 --ip 192.168.1.1,192.168.2.2,0x17 \
 --udp 1000 \
 --bytes 1000
"""

#Eth, IPv4, IPv6
SRC = 0
DST = 1

#Eth
ETHTYPE = 2

#IPv4
DSCP = 2
VER = 3

#IPv6
VER_IP6 = 2

#VLAN
VLANTYPE = 0
VLAN1 = 1
VLAN2 = 2
VLAN3 = 3
VLAN4 = 4

#MPLS
LABEL1 = 0
LABEL2 = 1
LABEL3 = 2
LABEL4 = 3
LABEL5 = 4

SWITCH_ID = 0
TIMESTAMP = 1

TYPE_RND = 0x1234

parser = argparse.ArgumentParser(description='Process some integers.')

parser.add_argument('-e', '--ethernet', type=str, help='Ethernet src/dst addresses')
parser.add_argument('-w', '--rnd', type=str, action='store', help='Random n size using k headers')
parser.add_argument('-v', '--vlan', type=str, help='VLAN headers and IDs')
parser.add_argument('-m', '--mpls', type=str, help='Enable MPLS header and add parameters')
parser.add_argument('-i', '--ip', type=str, help='Add IPv4 parameters')
parser.add_argument('-6', '--ip6', type=str, help='Add IPv6 parameters')
parser.add_argument('-t', '--tcp', type=int, action='store', help='Enable TCP header and add parameters')
parser.add_argument('-u', '--udp', type=int, action='store', help='Enable UDP header and add parameters')
parser.add_argument('-l', '--intshim', const=True, action='store_const', help='Enable INT Shim header')
parser.add_argument('-n', '--intmeta', const=True, action='store_const', help='Enable INT Metadata header')
parser.add_argument('-s', '--imstack', type=str, help='Enable INT metadata stack using Switch ID and Timestamp')
parser.add_argument('-p', '--packets', type=int, action='store', help='Number of packets to send')
parser.add_argument('-b', '--bytes', type=int, action='store', help='Bytes for the payload')
parser.add_argument('-r', '--randbytes', const=True, action='store_const',  help='Add random bytes to the payload')
parser.add_argument('-f', '--filename', type=str, help='Path for the filename')
parser.add_argument('-c', '--interface', type=str, help='Name of the interface to send the packet to')
parser.add_argument('-z', '--custom', type=str, action='store', help='Adds a test that is custom')

args = parser.parse_args()

CUSTOM_TESTS = {
    "test1" : [1,2,4,8,16,32,50,64,100,128],
    "test2" : [128,100,64,50,32,16,8,4,2,1]
}


class Rnd_1b(Packet):
    name = "Rnd_1b"
    fields_desc = [
        BitField("f4", 0, 8)
    ]

class Rnd_2b(Packet):
    name = "Rnd_2b"
    fields_desc = [
        BitField("f1", 0, 1),
        BitField("f2", 0, 3),
        BitField("f3", 0, 4),
        BitField("f4", 0, 8)
    ]

class Rnd_4b(Packet):
    name = "Rnd_4b"
    fields_desc = [
        BitField("f1", 0, 8),
        BitField("f2", 0, 8),
        BitField("f3", 0, 8),
        BitField("f4", 0, 8)
    ]

class Rnd_5b(Packet):
    name = "Rnd_5b"
    fields_desc = [
        BitField("f1", 0, 4),
        BitField("f2", 0, 3),
        BitField("f3", 0, 1),
        BitField("f4", 0, 8),
        BitField("f5", 0, 8),
        BitField("f6", 0, 8),
        BitField("f7", 0, 2),
        BitField("f8", 0, 6)
    ]

class Rnd_8b(Packet):
    name = "Rnd_8b"
    fields_desc = [
        BitField("f1", 0, 16),
        BitField("f2", 0, 16),
        BitField("f3", 0, 16),
        BitField("f4", 0, 8),
        BitField("f5", 0, 8)
    ]

class Rnd_10b(Packet):
    name = "Rnd_10b"
    fields_desc = [
        BitField("f1", 0, 4),
        BitField("f2", 0, 3),
        BitField("f3", 0, 1),
        BitField("f4", 0, 8),
        BitField("f5", 0, 4),
        BitField("f6", 0, 16),
        BitField("f7", 0, 16),
        BitField("f8", 0, 4),
        BitField("f9", 0, 8),
        BitField("f10", 0, 16)
    ]

class Rnd_15b(Packet):
    name = "Rnd_15b"
    fields_desc = [
        BitField("f1", 0, 4),
        BitField("f2", 0, 3),
        BitField("f3", 0, 1),
        BitField("f4", 0, 8),
        BitField("f5", 0, 4),
        BitField("f6", 0, 4),
        BitField("f7", 0, 32),
        BitField("f8", 0, 32),
        BitField("f9", 0, 8),
        BitField("f10", 0, 8),
        BitField("f11", 0, 16)
    ]

class Rnd_16b(Packet):
    name = "Rnd_16b"
    fields_desc = [
        BitField("f1", 0, 4),
        BitField("f2", 0, 3),
        BitField("f3", 0, 1),
        BitField("f4", 0, 8),
        BitField("f5", 0, 4),
        BitField("f6", 0, 4),
        BitField("f7", 0, 32),
        BitField("f8", 0, 32),
        BitField("f9", 0, 8),
        BitField("f10", 0, 16),
        BitField("f11", 0, 16)
    ]

class Rnd_20b(Packet):
    name = "Rnd_20b"
    fields_desc = [
        BitField("f1", 0, 16),
        BitField("f2", 0, 16),
        BitField("f3", 0, 8),
        BitField("f4", 0, 8),
        BitField("f5", 0, 1),
        BitField("f6", 0, 3),
        BitField("f7", 0, 4),
        BitField("f8", 0, 16),
        BitField("f9", 0, 16),
        BitField("f10", 0, 32),
        BitField("f11", 0, 8),
        BitField("f12", 0, 32)
    ]

class Rnd_32b(Packet):
    name = "Rnd_32b"
    fields_desc = [
        BitField("f1", 0, 32),
        BitField("f2", 0, 32),
        BitField("f3", 0, 64),
        BitField("f4", 0, 8),
        BitField("f5", 0, 16),
        BitField("f6", 0, 8),
        BitField("f7", 0, 8),
        BitField("f8", 0, 8),
        BitField("f9", 0, 8),
        BitField("f10", 0, 8),
        BitField("f11", 0, 64)
    ]

class Rnd_40b(Packet):
    name = "Rnd_40b"
    fields_desc = [
        BitField("f1", 0, 32),
        BitField("f2", 0, 32),
        BitField("f3", 0, 32),
        BitField("f4", 0, 8),
        BitField("f5", 0, 64),
        BitField("f6", 0, 64),
        BitField("f7", 0, 16),
        BitField("f8", 0, 8),
        BitField("f9", 0, 8),
        BitField("f10", 0, 32),
        BitField("f11", 0, 8),
        BitField("f12", 0, 8),
        BitField("f13", 0, 8)
    ]

class Rnd_50b(Packet):
    name = "Rnd_50b"
    fields_desc = [
        BitField("f1", 0, 32),
        BitField("f2", 0, 32),
        BitField("f3", 0, 32),
        BitField("f4", 0, 8),        
        BitField("f5", 0, 64),
        BitField("f6", 0, 64),
        BitField("f7", 0, 16),
        BitField("f8", 0, 8),
        BitField("f9", 0, 8),
        BitField("f10", 0, 32),
        BitField("f11", 0, 8),
        BitField("f12", 0, 8),
        BitField("f13", 0, 8),
        BitField("f14", 0, 32),
        BitField("f15", 0, 8),
        BitField("f16", 0, 8),
        BitField("f17", 0, 32)
    ]

class Rnd_64b(Packet):
    name = "Rnd_64b"
    fields_desc = [
        BitField("f1", 0, 32),
        BitField("f2", 0, 32),
        BitField("f3", 0, 32),
        BitField("f4", 0, 8),        
        BitField("f5", 0, 64),
        BitField("f6", 0, 64),
        BitField("f7", 0, 16),
        BitField("f8", 0, 8),
        BitField("f9", 0, 8),
        BitField("f10", 0, 32),
        BitField("f11", 0, 8),
        BitField("f12", 0, 8),
        BitField("f13", 0, 8),
        BitField("f14", 0, 32),
        BitField("f15", 0, 32),
        BitField("f16", 0, 16),
        BitField("f17", 0, 64),
        BitField("f18", 0, 8),
        BitField("f19", 0, 8),
        BitField("f20", 0, 32)
    ]

class Rnd_100b(Packet):
    name = "Rnd_100b"
    fields_desc = [
        BitField("f1", 0, 100),
        BitField("f2", 0, 16),
        BitField("f3", 0, 10),
        BitField("f4", 0, 8),        
        BitField("f5", 0, 100),
        BitField("f6", 0, 16),
        BitField("f7", 0, 6),
        BitField("f8", 0, 128),
        BitField("f9", 0, 128),
        BitField("f10", 0, 64),
        BitField("f11", 0, 32),
        BitField("f12", 0, 16),
        BitField("f13", 0, 64),
        BitField("f14", 0, 32),
        BitField("f15", 0, 16),
        BitField("f16", 0, 32),
        BitField("f17", 0, 32)
    ]

class Rnd_128b(Packet):
    name = "Rnd_128b"
    fields_desc = [
        BitField("f1", 0, 100),
        BitField("f2", 0, 100),
        BitField("f3", 0, 50),
        BitField("f4", 0, 8),        
        BitField("f5", 0, 100),
        BitField("f6", 0, 100),
        BitField("f7", 0, 100),
        BitField("f8", 0, 100),
        BitField("f9", 0, 100),
        BitField("f10", 0, 100),
        BitField("f11", 0, 100),
        BitField("f12", 0, 50),
        BitField("f13", 0, 16)
    ]


class MPLS(Packet):
    name = "MPLS"
    fields_desc = [
        BitField("label", 1000, 20),
        BitField("exp", 0, 3),
        BitField("bos", 1, 1),
        ByteField("ttl", 0)
    ]

class INT_shim(Packet):
    oName = "INT Shim Header"

    fields_desc = [
        BitField('type', 1, 4),
        BitField('npt', 0, 2),
        BitField('res1', 0, 1),
        BitField('res2', 0, 1),
        ByteField('len', 0),
        ShortField('npt_field', 0)
    ]

class INT_meta(Packet):
    name = "INT Meta Header"

    fields_desc = [
        BitField('ver', 2, 4),
        BitField('d', 0, 1),
        BitField('e', 0, 1),
        BitField('m', 0, 1),
        BitField('rsvd1', 0, 12),
        BitField('hop_metadata_len', 2, 5),
        ByteField('remaining_hop_cnt', 0),
        BitField('instruction_mask_0003', 3, 4),
        BitField('instruction_mask_0407', 0, 4),
        BitField('instruction_mask_0811', 0, 4),
        BitField('instruction_mask_1215', 0, 4),
        ShortField('domain_sp_id', 0),
        ShortField('ds_inst', 0),
        ShortField('ds_flags', 0)
    ]

class INT_rep_grp(Packet):
    oName = "INT Report Group Header"

    fields_desc = [
        BitField('ver', 0, 4),
        BitField('f', 0, 6),
        BitField('i', 0, 22),
        BitField('rsvd', 0, 4)
    ]

class INT_rep_ind(Packet):
    oName = "INT Report Individual Header"

    fields_desc = [
        BitField('rep_type', 0, 4),
        BitField('in_type', 0, 4),
        ByteField('rep_len', 0),
        ByteField('md_len', 0),
        BitField('d', 0, 1),
        BitField('q', 0, 1),
        BitField('f', 0, 1),
        BitField('i', 0, 1),
        BitField('rsvd', 0, 4)
    ]

class INT_switch_id(Packet):
    name = "Switch ID"

    fields_desc = [
        IntField('switch_id', 0),
    ]

class INT_ingress_tstamp(Packet):
    name = "Ingress Timestamp"

    fields_desc = [
        IntField('ingress_global_timestamp', 0),
    ]

bind_layers(Ether, MPLS, type=0x8847)
bind_layers(MPLS, MPLS, bos=0)
bind_layers(MPLS, IP, bos=1)
bind_layers(INT_shim, INT_meta)

#bind_layers(UDP,INT_shim)
#bind_layers(TCP,INT_shim)


def main():

    if args.ethernet:
        ethernetParams = [p for p in args.ethernet.split(',')]

    if args.rnd:
        rndParams = [p for p in args.rnd.split(',')]

    if args.vlan:
        vlanParams = [p for p in args.vlan.split(',')]

    if args.mpls:
        mplsParams = [int(p) for p in args.mpls.split(',')]

    if args.ip:
        ipParams = [p for p in args.ip.split(',')]
    
    if args.ip6:
        ip6Params = [p for p in args.ip6.split(',')]

    if args.imstack:
        imstackParams = [p for p in args.imstack.split(',')]

    payloadBytes = args.bytes

    print ("Sending packets on interface %s" % (args.interface))

    pkt = None
    if len(ethernetParams) > 2:
        pkt = Ether(type=int(ethernetParams[ETHTYPE], 0), src=ethernetParams[SRC], dst=ethernetParams[DST])
    else:
        pkt = Ether(src=ethernetParams[SRC], dst=ethernetParams[DST])
    
    if args.rnd:            
        numHeaders = int(rndParams[1])           
        for i in range(1, numHeaders+1):
            typeHeader = rndParams[0] if not args.custom else str(CUSTOM_TESTS[args.custom][i-1])+"B"
            typeHeaderNum = int(typeHeader[:-1]) if not args.custom else CUSTOM_TESTS[args.custom][i-1]
            payloadBytes-=typeHeaderNum
            #print("Adding header byte: {}, num: {} and bytesToRemove".format(typeHeader, str(typeHeaderNum), str(payloadBytes)))

            rndtype = 0xAB
            if i == numHeaders:
                rndtype = 0x08

            if typeHeader == "1B":
                pkt = pkt / Rnd_1b(f4=rndtype)
            elif typeHeader == "2B":
                pkt = pkt / Rnd_2b(f1=i,  f4=rndtype)
            elif typeHeader == "4B":
                pkt = pkt / Rnd_4b(f1=i,  f4=rndtype)
            elif typeHeader == "5B":
                pkt = pkt / Rnd_5b(f1=i,  f4=rndtype)
            elif typeHeader == "8B":
                pkt = pkt / Rnd_8b(f1=i,  f4=rndtype)
            elif typeHeader == "10B":
                pkt = pkt / Rnd_10b(f1=i, f4=rndtype)
            elif typeHeader == "15B":
                pkt = pkt / Rnd_15b(f1=i, f4=rndtype)
            elif typeHeader == "16B":
                pkt = pkt / Rnd_16b(f1=i, f4=rndtype)
            elif typeHeader == "20B":
                pkt = pkt / Rnd_20b(f1=i, f4=rndtype)
            elif typeHeader == "32B":
                pkt = pkt / Rnd_32b(f1=i, f4=rndtype)
            elif typeHeader == "40B":
                pkt = pkt / Rnd_40b(f1=i, f4=rndtype)
            elif typeHeader == "50B":
                pkt = pkt / Rnd_50b(f1=i, f4=rndtype)
            elif typeHeader == "64B":
                pkt = pkt / Rnd_64b(f1=i, f4=rndtype)
            elif typeHeader == "100B":
                pkt = pkt / Rnd_100b(f1=i, f4=rndtype)
            elif typeHeader == "128B":
                pkt = pkt / Rnd_128b(f1=i, f4=rndtype)
    
    if args.vlan:
        payloadBytes-=len(vlanParams)*4
        for i, vlaninfo in enumerate(vlanParams):
            items = vlaninfo.split("/")
            vlanid = int(items[0])
            
            vlanh = None
            if len(items) > 1:
                vType = items[1]
                vlanh = Dot1Q(vlan=vlanid, type=int(vType,0))
            else:
                vlanh = Dot1Q(vlan=vlanid)
               
            pkt = pkt / vlanh

    if args.mpls:
        payloadBytes-=len(mplsParams)*4
        for i, mplslabel in enumerate(mplsParams):
            b = 0
            if i == len(mplsParams) - 1:
                b = 1
            pkt = pkt / MPLS(label=mplslabel, bos=b)

    if args.ip:
        payloadBytes-=20
        pkt = pkt / IP(version=int(ipParams[VER]), src=ipParams[SRC], dst=ipParams[DST], tos=int(ipParams[DSCP], 0) << 2)

    elif args.ip6:
        payloadBytes-=40
        pkt = pkt / IPv6(version=int(ip6Params[VER_IP6]),src=ip6Params[SRC], dst=ip6Params[DST])

    if args.udp:
        payloadBytes-=8
        pkt = pkt / UDP(sport=5555, dport=args.udp)
    
    if args.tcp:
        payloadBytes-=20
        pkt = pkt / TCP(sport=0, dport=args.tcp)
    
    if args.intshim:
        pkt = pkt / INT_shim(len=5)
        if args.intmeta:
            pkt = pkt / INT_meta()
            if args.imstack:
                pkt = pkt / \
                        INT_switch_id(switch_id=int(imstackParams[SWITCH_ID])) / \
                        INT_ingress_tstamp(ingress_global_timestamp=int(imstackParams[TIMESTAMP]))

    if args.bytes:
        if args.randbytes:
            pkt = pkt / Raw(load=bytearray(os.urandom(payloadBytes)))
        else:
            pkt = pkt / Raw(load=bytearray([0] * payloadBytes) )

    for i in range(args.packets):    
        #pkt.show()
        #t = time.time_ns()
        if args.udp:
            pkt[UDP].sport = 5555
            #pkt[UDP].sport = i+1
            
        if args.tcp:
            pkt[TCP].sport = i+1
        
        sendp(pkt, iface=args.interface, verbose=False)
        print("Sent packet: "+str(i+1))
        time.sleep(0.3)


if __name__ == '__main__':
    main()