-# $OpenBSD: Client.pm,v 1.3 2014/08/18 22:58:19 bluhm Exp $
+# $OpenBSD: Client.pm,v 1.4 2015/01/16 17:06:43 bluhm Exp $
-# Copyright (c) 2010-2014 Alexander Bluhm <bluhm@openbsd.org>
-# Copyright (c) 2014 Florian Riehm <mail@friehm.de>
+# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2014-2015 Florian Riehm <mail@friehm.de>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
use strict;
use warnings;
+use feature "state";
package Client;
use parent 'Proc';
"ospfd area is $ospf{area_id_str}: expected $area");
if ($ospf{type} == 1) {
handle_hello();
+ } elsif ($ospf{type} == 2) {
+ handle_dd();
} else {
warn "ospf type is not supported: $ospf{type}";
}
}
if ($reason) {
print "wait for hello because of: $reason\n";
- } else {
+ } elsif (!$wait || $wait->{dr} || $wait->{bdr} || $wait->{nbrs}) {
+ $cv->send();
+ }
+}
+
+sub handle_dd {
+ my %dd = consume_dd(\$handle->{rbuf});
+
+ my $compare = sub {
+ my $expect = shift;
+ foreach my $key (qw(options bits)) {
+ if ($expect->{"dd_$key"}) {
+ $dd{$key} == $expect->{"dd_$key"} or
+ return sprintf("dd key '%s' is 0x%x: expected 0x%x\n",
+ $key, $dd{$key}, $expect->{"dd_$key"});
+ }
+ }
+ if ($expect->{dd_seq}) {
+ $dd{dd_sequence_number} == $expect->{dd_seq} or
+ return sprintf("dd_sequence_number is 0x%x: expected 0x%x\n",
+ $dd{dd_sequence_number}, $expect->{dd_seq});
+ }
+ return "";
+ };
+
+ my $error = $compare->($check);
+ return $cv->croak("check: $error") if $error;
+ print "check dd successful\n";
+
+ my $reason;
+ if ($wait) {
+ $reason = $compare->($wait);
+ }
+ if ($reason) {
+ print "wait for dd because of: $reason\n";
+ } elsif (!$wait || $wait->{dd_bits} || $wait->{dd_options} ||
+ $wait->{dd_seq}) {
$cv->send();
}
}
return \%state;
}
+sub send_dd {
+ my $state = shift;
+ my $ip_number = unpack("N", pack("C4", split(/\./, $ism_ip)));
+ my $ip = join(".", unpack("C4", pack("N", $ip_number)));
+ my $rtrid_number = unpack("N", pack("C4", split(/\./, $ism_rtrid)));
+ my $rtrid = join(".", unpack("C4", pack("N", $rtrid_number)));
+ state $dd_count = 0;
+
+ my %ether = (
+ src_str => $ism_mac,
+ dst_str => "01:00:5e:00:00:05", # don't know the real dst mac
+ type => 0x0800, # ipv4
+ );
+ my %ip = (
+ v => 4, # ipv4
+ hlen => 20,
+ tos => 0xc0,
+ id => $dd_count++, # increment for debugging
+ off => 0, # no fragment
+ ttl => 1, # only for direct connected
+ p => 89, # protocol ospf
+ src_str => $ip,
+ dst_str => $ospfd_ip,
+ );
+ my %ospf = (
+ version => 2, # ospf v2
+ type => 2, # dd
+ router_id_str => $rtrid,
+ area_id_str => $area,
+ autype => 0, # no authentication
+ );
+ my %dd = (
+ interface_mtu => 1500,
+ options => 0x02,
+ bits => $state->{dd_bits},
+ dd_sequence_number => 999, # some value
+ );
+ $handle->push_write(
+ construct_ether(\%ether,
+ construct_ip(\%ip,
+ construct_ospf(\%ospf,
+ construct_dd(\%dd))))
+ );
+}
+
sub ism_set_state {
my $state = shift;
for (my $i = 0; $i < @states; $i++) {
$isms[$i] ||= interface_state_machine();
%{$isms[$i]} = (%{$isms[$i]}, %{$states[$i]});
+ if ($states[$i]{dd_bits}) {
+ send_dd($states[$i]);
+ delete $states[$i]{dd_bits};
+ }
}
}
-# $OpenBSD: Packet.pm,v 1.2 2014/07/11 22:28:51 bluhm Exp $
+# $OpenBSD: Packet.pm,v 1.3 2015/01/16 17:06:43 bluhm Exp $
-# Copyright (c) 2014 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2014-2015 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2015 Florian Riehm <mail@friehm.de>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
consume_ip
consume_ospf
consume_hello
+ consume_dd
construct_ether
construct_arp
construct_ip
construct_ospf
construct_hello
+ construct_dd
);
sub ip_checksum {
return %fields;
}
+sub consume_dd {
+ my $packet = shift;
+
+ length($$packet) >= 8
+ or croak "dd packet too short: ". length($$packet);
+ my $dd = substr($$packet, 0, 8, "");
+ my %fields;
+ @fields{qw(interface_mtu options bits dd_sequence_number)} =
+ unpack("n C C N", $dd);
+ $fields{bits} <= 7
+ or croak "All bits except of I-, M- and MS-bit must be zero";
+
+ return %fields;
+}
+
sub construct_hello {
my $fields = shift;
return $packet;
}
+sub construct_dd {
+ my $fields = shift;
+
+ my $packet = pack("n C C N",
+ @$fields{qw(interface_mtu options bits dd_sequence_number)});
+
+ return $packet;
+}
+
1;
--- /dev/null
+use strict;
+use warnings;
+use Default qw($ospfd_ip $ospfd_rtrid);
+
+our %tst_args = (
+ client => {
+ tasks => [
+ {
+ name => "receive hello with dr 0.0.0.0 bdr 0.0.0.0, ".
+ "enter $ospfd_rtrid as our neighbor",
+ check => {
+ dr => "0.0.0.0",
+ bdr => "0.0.0.0",
+ nbrs => [],
+ },
+ state => {
+ nbrs => [ $ospfd_rtrid ],
+ },
+ },
+ {
+ name => "neighbor asserting itself as master. " .
+ "We proclaim to be master, because of higher router id.",
+ wait => {
+ dd_bits => 7, # I|M|MS
+ },
+ state => {
+ dd_bits => 7,
+ },
+ timeout => 10, # not specified in rfc
+ },
+ {
+ name => "check if neighbor is slave, initialization is done ".
+ "and neighbour has applied our dd sequence number.",
+ wait => {
+ dd_bits => 0x2, # M
+ dd_seq => 999,
+ },
+ timeout => 10, # not specified in rfc
+ },
+ ],
+ },
+);
+
+1;