diff options
author | Deepak S <deepak.s@linux.intel.com> | 2017-07-13 21:26:50 -0700 |
---|---|---|
committer | Deepak S <deepak.s@linux.intel.com> | 2017-07-14 04:58:47 -0700 |
commit | 7286b2518ec8e4398b512ce95def9166a7af2e4a (patch) | |
tree | c93ef65d9e73e8893ccecb720152e16aae96a8b6 /VNFs/DPPD-PROX/helper-scripts/ipv6_tun | |
parent | adcb79da90176b27224eeb1d00aa0e611ef85a9b (diff) |
Adding PROX(Packet pROcessing eXecution engine) VNF to sampleVNF
JIRA: SAMPLEVNF-55
PROX is a DPDK-based application implementing Telco use-cases such as
a simplified BRAS/BNG, light-weight AFTR... It also allows configuring
finer grained network functions like QoS, Routing, load-balancing...
(We are moving PROX version v039 to sampleVNF
https://01.org/intel-data-plane-performance-demonstrators/prox-overview)
Change-Id: Ia3cb02cf0e49ac5596e922c197ff7e010293d033
Signed-off-by: Deepak S <deepak.s@linux.intel.com>
Diffstat (limited to 'VNFs/DPPD-PROX/helper-scripts/ipv6_tun')
-rwxr-xr-x | VNFs/DPPD-PROX/helper-scripts/ipv6_tun/gen_4over6.pl | 271 | ||||
-rwxr-xr-x | VNFs/DPPD-PROX/helper-scripts/ipv6_tun/ipv6_tun_bindings.pl | 266 |
2 files changed, 537 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/helper-scripts/ipv6_tun/gen_4over6.pl b/VNFs/DPPD-PROX/helper-scripts/ipv6_tun/gen_4over6.pl new file mode 100755 index 00000000..8e42eeba --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/ipv6_tun/gen_4over6.pl @@ -0,0 +1,271 @@ +#!/usr/bin/perl + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## 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 vars; +use Getopt::Long; +use Pod::Usage; +use Net::Pcap; +use Net::Frame::Layer; +use Net::Frame::Layer::ETH qw(:consts); +use Net::Frame::Layer::IPv6 qw(:consts); +use Net::Frame::Layer::IPv4 qw(:consts); +use Net::Frame::Layer::UDP; +use Socket qw(AF_INET AF_INET6 inet_ntop inet_pton); + +use constant NUM_PACKETS => 30000; + +use constant ETHER_ADDR_LEN => 6; +use constant ETHER_TYPE_LEN => 2; +use constant ETHER_HDR_LEN => ( 2 * ETHER_ADDR_LEN ) + ETHER_TYPE_LEN; +use constant ETHER_STATIC_MAC => "78acdddddddd"; + +use constant UDP_HDR_LEN => 8; +use constant UDP_STATIC_PORT => 0x6666; + +use constant IPv6_HOP_LIMIT => 4; +use constant IPv6_STATIC_IP => "2222:2222:2222:2222:2222:2222:2222:2222"; + +use constant IPv4_TIME_TO_LIVE => 32; +use constant IPv4_STATIC_IP => "68.68.68.68"; + +srand; + +my $type = 'tun'; +my $pkt_count = NUM_PACKETS; + +GetOptions( + 'inet' => sub { $type = 'inet'}, + 'tun' => sub { $type = 'tun'}, + 'count=i' => \$pkt_count, + 'in=s' => \(my $in = 'ip6_tun_bind.lua'), + 'out=s' => \(my $out = 'output.pcap'), + 'size=s' => \(my $size = 0) +) or exit; + +my $pcap = pcap_open_dead( DLT_EN10MB, 65535 ); +my $dumper = pcap_dump_open($pcap, $out ) or die 'Could not create output file: ' . $out; + +if( $type eq 'inet' ) { + gen_inet_pcap( $in, $pkt_count ); +} +if( $type eq 'tun' ) { + gen_tun_pcap( $in, $pkt_count ); +} + +pcap_close( $pcap ); + +# Trim string +sub trim { + my ( $str ) = @_; + + $str =~ s/^\s+|\s+$//g; + + return $str; +} + +# Generate random port based on $port and $port_mask +sub rand_port { + my ( $port, $port_mask ) = @_; + + return ( $port | int( rand( 0xFFFF ) & $port_mask ) ); +} + +# Generate packet originating from CPE +sub gen_tun_packet { + my ( $sz, $ether, $ipv6, $ipv4, $udp ) = @_; + + my $hdr_ether = Net::Frame::Layer::ETH->new( + src => $ether->{'src'}, + dst => $ether->{'dst'}, + type => NF_ETH_TYPE_IPv6 + )->pack; + + my $hdr_ipv6 = Net::Frame::Layer::IPv6->new( + nextHeader => NF_IPv6_PROTOCOL_IPIP, + hopLimit => IPv6_HOP_LIMIT, + src => $ipv6->{'src'}, + dst => $ipv6->{'dst'}, + payloadLength => $sz + NF_IPv4_HDR_LEN + UDP_HDR_LEN + )->pack; + + my $hdr_ipv4 = Net::Frame::Layer::IPv4->new( + length => $sz + UDP_HDR_LEN + NF_IPv4_HDR_LEN, + ttl => IPv4_TIME_TO_LIVE, + protocol => NF_IPv4_PROTOCOL_UDP, + src => $ipv4->{'src'}, + dst => $ipv4->{'dst'} + )->pack; + + my $hdr_udp = Net::Frame::Layer::UDP->new( + src => $udp->{'src'}, + dst => $udp->{'dst'}, + length => $sz + UDP_HDR_LEN + )->pack; + + my $pkt = pack( "H*", "de" x $sz ); + $pkt = $hdr_ether . $hdr_ipv6 . $hdr_ipv4 . $hdr_udp . $pkt; + + my $pkt_size = length( $pkt ); + + my $hdr = { + tv_sec => 0, + tv_usec => 0, + len => $pkt_size, + caplen => $pkt_size + }; + + return ( $hdr, $pkt ); +} + +# Generate packet originating from the internet +sub gen_inet_packet { + my ( $sz, $ether, $ipv4, $udp ) = @_; + + my $hdr_ether = Net::Frame::Layer::ETH->new( + src => $ether->{'src'}, + dst => $ether->{'dst'}, + type => NF_ETH_TYPE_IPv4 + )->pack; + + my $hdr_ipv4 = Net::Frame::Layer::IPv4->new( + length => $sz + UDP_HDR_LEN + NF_IPv4_HDR_LEN, + ttl => IPv4_TIME_TO_LIVE, + protocol => NF_IPv4_PROTOCOL_UDP, + src => $ipv4->{'src'}, + dst => $ipv4->{'dst'} + )->pack; + + my $hdr_udp = Net::Frame::Layer::UDP->new( + src => $udp->{'src'}, + dst => $udp->{'dst'}, + length => $sz + UDP_HDR_LEN + )->pack; + + my $pkt = pack( "H*", "de" x $sz ); + $pkt = $hdr_ether . $hdr_ipv4 . $hdr_udp . $pkt; + + my $pkt_size = length( $pkt ); + + my $hdr = { + tv_sec => 0, + tv_usec => 0, + len => $pkt_size, + caplen => $pkt_size + }; + + return ( $hdr, $pkt ); +} + +# Read bindings file +sub read_bindings { + my ( $file ) = @_; + + print "Reading bindings file...\n"; + + my @rows; + + open my $fh, "<:encoding(utf8)", $file or die $file . ": $!"; +LINE: while ( my $line = <$fh> ) { + next if ($line =~ /^--.*/); # Skip comments + + my ($ip6, $mac, $ip4, $port); + if ($line =~ /\s*\{.*\},\s*$/) { # Weak check for a data line... + + $line =~ /ip6\s*=\s*ip6\("([^\)]*)"\)/ && do { $ip6 = trim($1); }; + unless ( inet_pton( AF_INET6, $ip6 ) ) { print "ERROR - Invalid ipv6: $ip6\n"; next LINE; } + + $line =~ /ip\s*=\s*ip\("([^\)]*)"\)/ && do { $ip4 = trim($1); }; + unless ( inet_pton( AF_INET, $ip4 ) ) { print "ERROR - Invalid ipv4: $ip4\n"; next LINE; } + + $line =~ /mac\s*=\s*mac\("([^\)]*)"\)/ && do { $mac = trim($1); }; + unless ( $mac =~ /^([0-9a-f]{2}([:-]|$)){6}$/i ) { print "ERROR - Invalid mac: $mac\n"; next LINE; } + + $line =~ /port\s*=\s*([0-9]*)/ && do { $port = trim($1); }; + unless ( int($port) ) { print "ERROR - Invalid port number: $port\n"; next LINE; } + + push @rows, { + ipv6 => $ip6, + mac => $mac, + ipv4 => $ip4, + port => $port + } + } + } + close $fh; + + return @rows; +} + +# Generate packets originating from CPE +sub gen_tun_pcap { + my ( $binding_file, $pkt_count ) = @_; + my @bind = read_bindings($binding_file); + my $idx = 0; + my $row; + my $public_port = 0; + + print "Generating $pkt_count Tunnel packets...\n"; + + my $max = @bind; + for( my $i=0; $i<$pkt_count; $i++ ) { + + $idx = rand $max; + $row = @bind[$idx]; + + $public_port = rand_port( $row->{port}, 0x3f ); + + my ( $hdr, $pkt ) = gen_tun_packet( + $size, + { src => $row->{mac}, dst => ETHER_STATIC_MAC }, + { src => $row->{ipv6}, dst => IPv6_STATIC_IP }, + { src => $row->{ipv4}, dst => IPv4_STATIC_IP }, + { src => $public_port, dst => UDP_STATIC_PORT } + ); + + pcap_dump( $dumper, $hdr, $pkt ); + } +} + +# Generate packets originating from the internet +sub gen_inet_pcap { + my ( $binding_file, $pkt_count ) = @_; + my @bind = read_bindings($binding_file); + my $idx = 0; + my $row; + my $public_port = 0; + + print "Generating $pkt_count Internet packets...\n"; + + my $max = @bind; + for( my $i=0; $i<$pkt_count; $i++ ) { + + $idx = rand $max; + $row = @bind[$idx]; + + $public_port = rand_port( $row->{port}, 0x3f ); + + my ( $hdr, $pkt ) = gen_inet_packet( + $size, + { src => ETHER_STATIC_MAC, dst => $row->{mac} }, + { src => IPv4_STATIC_IP, dst => $row->{ipv4} }, + { src => UDP_STATIC_PORT, dst => $public_port } + ); + + pcap_dump( $dumper, $hdr, $pkt ); + } +} diff --git a/VNFs/DPPD-PROX/helper-scripts/ipv6_tun/ipv6_tun_bindings.pl b/VNFs/DPPD-PROX/helper-scripts/ipv6_tun/ipv6_tun_bindings.pl new file mode 100755 index 00000000..02af5103 --- /dev/null +++ b/VNFs/DPPD-PROX/helper-scripts/ipv6_tun/ipv6_tun_bindings.pl @@ -0,0 +1,266 @@ +#!/usr/bin/perl + +## +## Copyright (c) 2010-2017 Intel Corporation +## +## 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. +## + +=head1 NAME + +ipv6_tun_bindings.pl + +=head1 SYNOPSIS + + ipv6_tun_bindings.pl [-n <num_entries>] [-tun_ip <ipv6>] [-mac <next_hop_mac>] + [-pub_ip <ipv4>] [-port <begin>-<end>] [-set <num_ports>] + [-suffix <suffix>] [-test <num_entries>] [-sym|-nosym] + [-help] + +=head1 DESCRIPTION + +This script can be used to generate a binding table for the IPv6 Tunnel +task implemented in PROX (ipv6_encap and ipv6_decap). +The entries in this table bind a specific tunnel endpoint (lwB4 in lw4over6 +architecture) to a public IPv4 address and port set. +The port set is actually derived from the port specified in the table +and a port bitmask in the PROX task configuration ("lookup port mask"). + +The ipv6_encap task uses the binding table to know where to tunnel IPv4 +traffic to. The ipv6_decap task uses the table to verify tunnel packets +have a valid public IPv4 and port combination for the originating tunnel. + +The table uses the Lua syntax so it can be loaded into PROX. Example: +return { + {ip6 = ip6("fe80:0000:0000:0000:0200:00ff:fe00:0000"), mac = mac("fe:80:00:00:00:00"), ip = ip("171.205.239.1"), port = 4608}, + {ip6 = ip6("fe80:0000:0000:0000:0200:00ff:fe00:0001"), mac = mac("fe:80:00:00:00:00"), ip = ip("171.205.239.1"), port = 4672}, + {ip6 = ip6("fe80:0000:0000:0000:0200:00ff:fe00:0002"), mac = mac("fe:80:00:00:00:00"), ip = ip("171.205.239.1"), port = 4736}, + {ip6 = ip6("fe80:0000:0000:0000:0200:00ff:fe00:0003"), mac = mac("fe:80:00:00:00:00"), ip = ip("171.205.239.1"), port = 4800}, +} + +The script generates consecutive entries, starting from a given IP address +and assigning ports within a given range, increasing the port number by a +fixed amount which should correspond to the port lookup mask being used. + +UDF table: In addition to the binding table itself, the script can optionally +generate accompanying UDF tables for generating test traffic matching the +binding table. Such UDF tables can then be used in a traffic generation tool. + +=head1 OPTIONS + +=over 22 + +=item -n <num_entries> + +How many entries in the binding table + +=item -tun_ip <ipv6> + +Starting tunnel endpoint IPv6 address (will be incremented) + +=item -mac <next_hop_mac> + +MAC address of the next hop to reach the tunnel endpoints + +=item -pub_ip <ipv4> + +Starting public IPv4 address + +=item -port <begin>-<end> + +Range of ports where to assign Port Sets + +=item -set <num_ports> + +Number of ports in set (should be a power of 2 because bitmasking is used +in lwAFTR) + +=item -suffix <suffix> + +Filename suffix to use for the generated file(s) + +=item -test <num_entries> + +Number of random entries to put into test UDF table + +=item -sym + +Whether the same random entry from the table should be inserted into both +traffic sides or if different entries should be used + +=item -help + +Shows the full script documentation. + +=back + +=head1 AUTHOR + + Copyright(c) 2010-2017 Intel Corporation. + All rights reserved. + +=cut + + +use strict vars; +use Getopt::Long; +use Pod::Usage; +use Socket qw(AF_INET AF_INET6 inet_ntop inet_pton); + +sub parse_ip +{ + my ($str, $ip_ref, $family) = @_; + + my $packed = inet_pton($family, $str); + return 0 if (!defined($packed)); + + if ($family == AF_INET6) { + #print unpack("H*", $packed). "\n"; + my @w = unpack("NNNN", $packed); + my ($high, $low) = (($w[0] << 32) | $w[1], ($w[2] << 32) | $w[3]); + @$ip_ref = ($high, $low); + } + else { + $$ip_ref = unpack("N", $packed); + } + return 1; +} + +sub ntop6 +{ + my ($in) = @_; + my $packed = pack('NNNN', $in->[0] >> 32, $in->[0] & 0xffffffff, + $in->[1] >> 32, $in->[1] & 0xffffffff); + return inet_ntop(AF_INET6, $packed); +} + +sub ntop6_expanded +{ + my ($in) = @_; + return sprintf('%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x', + ($in->[0] >> 48) & 0xffff, ($in->[0] >> 32) & 0xffff, + ($in->[0] >> 16) & 0xffff, ($in->[0] ) & 0xffff, + ($in->[1] >> 48) & 0xffff, ($in->[1] >> 32) & 0xffff, + ($in->[1] >> 16) & 0xffff, ($in->[1] ) & 0xffff); +} + +my ($tun_ip_str, $pub_ip_str, $ports_str); + +GetOptions( + 'help' => sub () { Pod::Usage::pod2usage( -verbose => 2 ); exit; }, + 'n=i' => \(my $num_B4s = 10), + 'tun_ip=s' => \(my $tun_ip_str = 'fe80:0000:0000:0000:0200:00ff:0000:0000'), + 'pub_ip=s' => \(my $pub_ip_str = '171.205.239.1'), + 'mac=s' => \(my $next_hop_mac = 'fe:80:00:00:00:00'), + 'port=s' => \(my $ports_str='4608-11968'), + 'set=n' => \(my $port_set_sz = 64), + 'suffix=s' => \(my $suffix = ''), + 'test=n' => \(my $num_test_lines = 200000), + 'sym!' => \(my $symmetric_traffic = TRUE), +) or pod2usage(-verbose => 1) && exit; + +my @tun_ip; +parse_ip($tun_ip_str, \@tun_ip, AF_INET6) or print("Invalid starting tunnel IP: $tun_ip_str\n") && pod2usage(-verbose => 1) && exit; +parse_ip($pub_ip_str, \(my $pub_ip), AF_INET) or print("Invalid starting public IP: $pub_ip_str\n") && pod2usage(-verbose => 1) && exit; +my @port_range; +if ($ports_str =~ /^([^d]+)\s*\-\s*([^d]+)$/) { + @port_range = ($1, $2); +} +else { print "Invalid port range: $ports_str\n"; pod2usage(-verbose => 1); exit } + +# Summary of input data +print "File suffix: $suffix\n" if ($suffix); +print "Starting Tunnel IP: " . ntop6(\@tun_ip) . "\n"; +print "Starting Public IP: ".inet_ntop(AF_INET, pack("N", $pub_ip)) . "\n"; +print "Public Port Range: $port_range[0]-$port_range[1] by blocks of $port_set_sz\n"; + +my @data; # Holds generated binding table, so we can later generate test traffic for it + +# Binding table for PROX IPv6 Tunnel +my $filename = 'ip6_tun_bind'.$suffix.'.lua'; +print "\nGenerating binding table with $num_B4s entries into $filename ... "; +open(my $fh, '>', $filename) or die "Could not open file '$filename' $!"; +print $fh "-- Bindings for lwaftr: lwB4 IPv6 address, next hop MAC address\n"; +print $fh "-- towards lwB4, IPv4 Public address, IPv4 Public Port Set\n"; +print $fh "\n"; +print $fh "return {" . "\n"; +my $port = $port_range[0]; +for (my $B4_id = 0; $B4_id < $num_B4s; $B4_id++) { + $data[$B4_id]{'b4_ipv6'} = ntop6_expanded(\@tun_ip); + $data[$B4_id]{'pub_ipv4'} = "" . (($pub_ip >> 24) & 0xff) . "." . (($pub_ip >> 16) & 0xff) . "." . (($pub_ip >> 8) & 0xff) . "." . ($pub_ip & 0xff); + $data[$B4_id]{'pub_port'} = $port; + $data[$B4_id]{'next_hop_mac'} = $next_hop_mac; + + print $fh " {"; + print $fh "ip6 = ip6(\"" . $data[$B4_id]{'b4_ipv6'} . "\")"; + print $fh ", mac = mac(\"" . $data[$B4_id]{'next_hop_mac'} . "\")"; + print $fh ", ip = ip(\"" . $data[$B4_id]{'pub_ipv4'} . "\")"; + print $fh ", port = " . $data[$B4_id]{'pub_port'}; + print $fh "},\n"; + + $port += $port_set_sz; + if ($port > $port_range[1]) { + $pub_ip++; + $port = $port_range[0]; + } + + # Move to next Tunnel address + if (@tun_ip[1] < 0xffffffffffffffff) { + @tun_ip[1]++; + } else { + @tun_ip[0]++; + @tun_ip[1] = 0; + } +} +print $fh "}" . "\n"; +close $fh; +print "[DONE]\n"; + +# Test traffic "UDF Tables" +if ($num_test_lines) { + print "Generating $num_test_lines lines of test UDF table into lwAFTR_tun|inet".$suffix.".csv ... "; + + # Tunnel Packets from B4 to lwAFTR + my $filename = 'lwAFTR_tun' . $suffix . '.csv'; + open(my $fh_tun, '>', $filename) or die "Could not open file '$filename' $!"; + print $fh_tun "b4_ip,pub_ip,pub_port\n"; + print $fh_tun "22,66,74\n"; # Offsets + print $fh_tun "16,4,2\n"; # Sizes + print $fh_tun "6,5,3\n"; # Format (IPv6, IPv4, Decimal) + print $fh_tun ",,\n"; + + # Internet Packets towards the lwAFTR, to be sent to corresp lwB4 over tunnel + my $filename = 'lwAFTR_inet' . $suffix . '.csv'; + open(my $fh_inet, '>', $filename) or die "Could not open file '$filename' $!"; + print $fh_inet "pub_ip,pub_port\n"; + print $fh_inet "30,36\n"; # Offsets + print $fh_inet "4,2\n"; # Sizes + print $fh_inet "5,3\n"; # Format (IPv6, IPv4, Decimal) + print $fh_inet ",,\n"; + + for (my $i = 0; $i < $num_test_lines; $i++) { + my $B4_id = int(rand($num_B4s)); + my $port = $data[$B4_id]{'pub_port'} + int(rand($port_set_sz)); + printf $fh_tun $data[$B4_id]{'b4_ipv6'} . "," . $data[$B4_id]{'pub_ipv4'} . "," . $port . "\n"; + + if (! $symmetric_traffic) { + $B4_id = int(rand($num_B4s)); + $port = $data[$B4_id]{'pub_port'} + int(rand($port_set_sz)); + } + printf $fh_inet $data[$B4_id]{'pub_ipv4'} . "," . $port . "\n"; + } + + close $fh_tun; + close $fh_inet; + print "[DONE]\n"; +} |