2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-21 14:49:41 +00:00
Files
openvswitch/tests/flowgen.pl
Ben Pfaff 053df7bda6 ofp-util: For OF1.0, don't wildcard PCP field when 802.1Q header absent.
OpenFlow 1.0.1 says:

    The dl_vlan_pcp field must be ignored when the OFPFW_DL_VLAN wildcard
    bit is set or when the dl_vlan value is set to OFP_VLAN_NONE.  Fields
    that are ignored don’t need to be wildcarded and should be set to 0.

Previously, OVS wildcarded the PCP field when dl_vlan was OFP_VLAN_NONE,
but this commit changes the behavior to that suggested above: the PCP
field should not be wildcarded (and should be set to 0, but the code
already did that).

This commit only changes the translation from OVS's internal flow format
to the OpenFlow 1.0 wire format.  Translation in the other direction and
to other formats is unaffected.

Found by OFTest.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jarno Rajahalme <jrajahalme@nicira.com>
2015-08-24 11:01:00 -07:00

254 lines
9.6 KiB
Perl
Executable File

#! /usr/bin/perl
# Copyright (c) 2009, 2010, 2011, 2012, 2015 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.
use strict;
use warnings;
open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n";
open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n";
# Print pcap file header.
print PACKETS pack('NnnNNNN',
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 my $dl_header (qw(802.2+SNAP Ethernet)) {
my %a = (DL_HEADER => $dl_header);
for my $dl_vlan (qw(none zero nonzero)) {
my %b = (%a, DL_VLAN => $dl_vlan);
# Non-IP case.
output(%b, DL_TYPE => 'non-ip');
for my $ip_options (qw(no yes)) {
my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options);
for my $ip_fragment (qw(no first middle last)) {
my %d = (%c, IP_FRAGMENT => $ip_fragment);
for my $tp_proto (qw(TCP TCP+options UDP ICMP other)) {
output(%d, TP_PROTO => $tp_proto);
}
}
}
}
}
sub output {
my (%attrs) = @_;
# Compose flow.
my (%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 (defined($attrs{DL_VLAN})) {
my (%vlan_map) = ('none' => 0xffff,
'zero' => 0,
'nonzero' => 0x0123);
$flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}};
} else {
$flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE
}
if ($attrs{DL_HEADER} eq '802.2') {
$flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE
} elsif ($attrs{DL_TYPE} eq '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} eq 'other') {
$flow{NW_PROTO} = 42;
} elsif ($attrs{TP_PROTO} eq 'TCP' ||
$attrs{TP_PROTO} eq 'TCP+options') {
$flow{NW_PROTO} = 6; # IPPROTO_TCP
$flow{TP_SRC} = 6667;
$flow{TP_DST} = 9998;
} elsif ($attrs{TP_PROTO} eq 'UDP') {
$flow{NW_PROTO} = 17; # IPPROTO_UDP
$flow{TP_SRC} = 1112;
$flow{TP_DST} = 2223;
} elsif ($attrs{TP_PROTO} eq 'ICMP') {
$flow{NW_PROTO} = 1; # IPPROTO_ICMP
$flow{TP_SRC} = 8; # echo request
$flow{TP_DST} = 0; # code
} else {
die;
}
if ($attrs{IP_FRAGMENT} ne 'no' && $attrs{IP_FRAGMENT} ne 'first') {
$flow{TP_SRC} = $flow{TP_DST} = 0;
}
} elsif ($attrs{DL_TYPE} eq 'non-ip') {
$flow{DL_TYPE} = 0x5678;
} else {
die;
}
# Compose packet.
my $packet = '';
my $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 .= pack('nn', 0x8100, $flow{DL_VLAN});
}
my $len_ofs = length($packet);
$packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/;
if ($attrs{DL_HEADER} eq '802.2') {
$packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP.
} else {
if ($attrs{DL_HEADER} eq '802.2+SNAP') {
$packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP.
$packet .= pack('CCC', 0, 0, 0); # SNAP OUI.
}
$packet .= pack('n', $flow{DL_TYPE});
if ($attrs{DL_TYPE} eq 'ip') {
my $ip = pack('CCnnnCCnNN',
(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} eq 'yes') {
substr($ip, 0, 1) = pack('C', (4 << 4) | 8);
$ip .= pack('CCnnnCCCx',
130, # type
11, # length
0x6bc5, # top secret
0xabcd,
0x1234,
1,
2,
3);
}
if ($attrs{IP_FRAGMENT} ne 'no') {
my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0
'middle' => 0x2111, # more frags, ofs 0x888
'last' => 0x0222); # last frag, ofs 0x1110
substr($ip, 6, 2)
= pack('n', $frag_map{$attrs{IP_FRAGMENT}});
}
if ($attrs{IP_FRAGMENT} eq 'no' || $attrs{IP_FRAGMENT} eq 'first') {
if ($attrs{TP_PROTO} =~ '^TCP') {
my $tcp = pack('nnNNnnnn',
$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} eq 'TCP+options') {
substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10);
$tcp .= pack('CCn', 2, 4, 1975); # MSS option
}
$tcp .= 'payload';
$ip .= $tcp;
$wildcards &= ~(1 << 6 | 1 << 7);
} elsif ($attrs{TP_PROTO} eq 'UDP') {
my $len = 15;
my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0);
$udp .= chr($len) while length($udp) < $len;
$ip .= $udp;
$wildcards &= ~(1 << 6 | 1 << 7);
} elsif ($attrs{TP_PROTO} eq 'ICMP') {
$ip .= pack('CCnnn',
8, # echo request
0, # code
0, # checksum
736, # identifier
931); # sequence number
$wildcards &= ~(1 << 6 | 1 << 7);
} elsif ($attrs{TP_PROTO} eq 'other') {
$ip .= 'other header';
} else {
die;
}
}
substr($ip, 2, 2) = pack('n', length($ip));
$packet .= $ip;
}
}
if ($attrs{DL_HEADER} =~ /^802.2/) {
my $len = length ($packet);
$len -= 4 if $flow{DL_VLAN} != 0xffff;
substr($packet, $len_ofs, 2) = pack('n', $len);
}
print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n";
print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n";
print "\n";
print FLOWS pack('Nn',
$wildcards, # wildcards
1); # in_port
print FLOWS pack_ethaddr($flow{DL_SRC});
print FLOWS pack_ethaddr($flow{DL_DST});
print FLOWS pack('nCxnCCxxNNnn',
$flow{DL_VLAN},
0, # DL_VLAN_PCP
$flow{DL_TYPE},
$flow{NW_TOS},
$flow{NW_PROTO},
inet_aton($flow{NW_SRC}),
inet_aton($flow{NW_DST}),
$flow{TP_SRC},
$flow{TP_DST});
print PACKETS pack('NNNN',
0, # timestamp seconds
0, # timestamp microseconds
length($packet), # bytes saved
length($packet)), # total length
$packet;
}
sub pack_ethaddr {
local ($_) = @_;
my $xx = '([0-9a-fA-F][0-9a-fA-F])';
my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/;
@octets == 6 or die $_;
my ($out) = '';
$out .= pack('C', hex($_)) foreach @octets;
return $out;
}
sub inet_aton {
local ($_) = @_;
my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
defined $d or die $_;
return ($a << 24) | ($b << 16) | ($c << 8) | $d;
}