2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 18:07:40 +00:00
ovs/tests/flowgen.py

240 lines
9.7 KiB
Python
Raw Normal View History

#! /usr/bin/env python3
# Copyright (c) 2009, 2010, 2011, 2012, 2015, 2017 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import socket
import struct
def pack_ethaddr(ea):
octets = ea.split(':')
assert len(octets) == 6
return b''.join([struct.pack('B', int(octet, 16)) for octet in octets])
def output(attrs):
# Compose flow.
flow = {}
flow['DL_SRC'] = "00:02:e3:0f:80:a4"
flow['DL_DST'] = "00:1a:92:40:ac:05"
flow['NW_PROTO'] = 0
flow['NW_TOS'] = 0
flow['NW_SRC'] = '0.0.0.0'
flow['NW_DST'] = '0.0.0.0'
flow['TP_SRC'] = 0
flow['TP_DST'] = 0
if 'DL_VLAN' in attrs:
flow['DL_VLAN'] = {'none': 0xffff,
'zero': 0,
'nonzero': 0x0123}[attrs['DL_VLAN']]
else:
flow['DL_VLAN'] = 0xffff # OFP_VLAN_NONE
if attrs['DL_HEADER'] == '802.2':
flow['DL_TYPE'] = 0x5ff # OFP_DL_TYPE_NOT_ETH_TYPE
elif attrs['DL_TYPE'] == 'ip':
flow['DL_TYPE'] = 0x0800 # ETH_TYPE_IP
flow['NW_SRC'] = '10.0.2.15'
flow['NW_DST'] = '192.168.1.20'
flow['NW_TOS'] = 44
if attrs['TP_PROTO'] == 'other':
flow['NW_PROTO'] = 42
elif attrs['TP_PROTO'] in ('TCP', 'TCP+options'):
flow['NW_PROTO'] = 6 # IPPROTO_TCP
flow['TP_SRC'] = 6667
flow['TP_DST'] = 9998
elif attrs['TP_PROTO'] == 'UDP':
flow['NW_PROTO'] = 17 # IPPROTO_UDP
flow['TP_SRC'] = 1112
flow['TP_DST'] = 2223
elif attrs['TP_PROTO'] == 'ICMP':
flow['NW_PROTO'] = 1 # IPPROTO_ICMP
flow['TP_SRC'] = 8 # echo request
flow['TP_DST'] = 0 # code
else:
assert False
if attrs['IP_FRAGMENT'] not in ('no', 'first'):
flow['TP_SRC'] = flow['TP_DST'] = 0
elif attrs['DL_TYPE'] == 'non-ip':
flow['DL_TYPE'] = 0x5678
else:
assert False
# Compose packet
packet = b''
wildcards = 1 << 5 | 1 << 6 | 1 << 7 | 32 << 8 | 32 << 14 | 1 << 21
packet += pack_ethaddr(flow['DL_DST'])
packet += pack_ethaddr(flow['DL_SRC'])
if flow['DL_VLAN'] != 0xffff:
packet += struct.pack('>HH', 0x8100, flow['DL_VLAN'])
len_ofs = len(packet)
if attrs['DL_HEADER'].startswith('802.2'):
packet += struct.pack('>H', 0)
if attrs['DL_HEADER'] == '802.2':
packet += struct.pack('BBB', 0x42, 0x42, 0x03) # LLC for 802.1D STP
else:
if attrs['DL_HEADER'] == '802.2+SNAP':
packet += struct.pack('BBB', 0xaa, 0xaa, 0x03) # LLC for SNAP
packet += struct.pack('BBB', 0, 0, 0) # SNAP OUI
packet += struct.pack('>H', flow['DL_TYPE'])
if attrs['DL_TYPE'] == 'ip':
ip = struct.pack('>BBHHHBBHLL',
(4 << 4) | 5, # version, hdrlen
flow['NW_TOS'], # type of service
0, # total length, filled in later
65432, # id
0, # frag offset
64, # ttl
flow['NW_PROTO'], # protocol
0, # checksum
0x0a00020f, # source
0xc0a80114) # dest
wildcards &= ~(1 << 5 | 63 << 8 | 63 << 14 | 1 << 21)
if attrs['IP_OPTIONS'] == 'yes':
ip = struct.pack('B', (4 << 4) | 8) + ip[1:]
ip += struct.pack('>BBHHHBBBx',
130, # type
11, # length
0x6bc5, # top secret
0xabcd,
0x1234,
1,
2,
3)
if attrs['IP_FRAGMENT'] != 'no':
frag_map = {'first': 0x2000, # more frags, ofs 0
'middle': 0x2111, # more frags, ofs 0x888
'last': 0x0222} # last frag, ofs 0x1110
ip = (ip[:6]
+ struct.pack('>H', frag_map[attrs['IP_FRAGMENT']])
+ ip[8:])
if attrs['IP_FRAGMENT'] in ('no', 'first'):
if attrs['TP_PROTO'].startswith('TCP'):
tcp = struct.pack('>HHLLHHHH',
flow['TP_SRC'], # source port
flow['TP_DST'], # dest port
87123455, # seqno
712378912, # ackno
(5 << 12) | 0x02 | 0x10,
# hdrlen, SYN, ACK
5823, # window size
18923, # checksum
12893) # urgent pointer
if attrs['TP_PROTO'] == 'TCP+options':
tcp = (tcp[:12]
+ struct.pack('>H', (6 << 12) | 0x02 | 0x10)
+ tcp[14:])
tcp += struct.pack('>BBH', 2, 4, 1975) # MSS option
tcp += b'payload'
ip += tcp
wildcards &= ~(1 << 6 | 1 << 7)
elif attrs['TP_PROTO'] == 'UDP':
udp_len = 15
udp = struct.pack('>HHHH',
flow['TP_SRC'],
flow['TP_DST'],
udp_len, 0)
while len(udp) < udp_len:
udp += struct.pack('B', udp_len)
ip += udp
wildcards &= ~(1 << 6 | 1 << 7)
elif attrs['TP_PROTO'] == 'ICMP':
ip += struct.pack('>BBHHH',
8, # echo request
0, # code
0, # checksum
736, # identifier
931) # sequence number
wildcards &= ~(1 << 6 | 1 << 7)
elif attrs['TP_PROTO'] == 'other':
ip += b'other header'
else:
assert False
ip = ip[:2] + struct.pack('>H', len(ip)) + ip[4:]
packet += ip
if attrs['DL_HEADER'].startswith('802.2'):
packet_len = len(packet) - 14
if flow['DL_VLAN'] != 0xffff:
packet_len -= 4
packet = (packet[:len_ofs]
+ struct.pack('>H', packet_len)
+ packet[len_ofs + 2:])
print(' '.join(['%s=%s' % (k, v) for k, v in attrs.items()]))
print(' '.join(['%s=%s' % (k, v) for k, v in flow.items()]))
print()
flows.write(struct.pack('>LH',
wildcards, # wildcards
1)) # in_port
flows.write(pack_ethaddr(flow['DL_SRC']))
flows.write(pack_ethaddr(flow['DL_DST']))
flows.write(struct.pack('>HBxHBBxx',
flow['DL_VLAN'],
0, # DL_VLAN_PCP
flow['DL_TYPE'],
flow['NW_TOS'],
flow['NW_PROTO']))
flows.write(socket.inet_aton(flow['NW_SRC']))
flows.write(socket.inet_aton(flow['NW_DST']))
flows.write(struct.pack('>HH', flow['TP_SRC'], flow['TP_DST']))
packets.write(struct.pack('>LLLL',
0, # timestamp seconds
0, # timestamp microseconds
len(packet), # bytes saved
len(packet))) # total length
packets.write(packet)
flows = open('flows', 'wb')
packets = open('pcap', 'wb')
# Print pcap file header.
packets.write(struct.pack('>LHHLLLL',
0xa1b2c3d4, # magic number
2, # major version
4, # minor version
0, # time zone offset
0, # time stamp accuracy
1518, # snaplen
1)) # Ethernet
output({'DL_HEADER': '802.2'})
for dl_header in ('802.2+SNAP', 'Ethernet'):
a = {'DL_HEADER': dl_header}
for dl_vlan in ('none', 'zero', 'nonzero'):
b = a.copy()
b['DL_VLAN'] = dl_vlan
# Non-IP case.
c = b.copy()
c['DL_TYPE'] = 'non-ip'
output(c)
for ip_options in ('no', 'yes'):
c = b.copy()
c['DL_TYPE'] = 'ip'
c['IP_OPTIONS'] = ip_options
for ip_fragment in ('no', 'first', 'middle', 'last'):
d = c.copy()
d['IP_FRAGMENT'] = ip_fragment
for tp_proto in ('TCP', 'TCP+options', 'UDP', 'ICMP', 'other'):
e = d.copy()
e['TP_PROTO'] = tp_proto
output(e)