diff --git a/perl-xCAT/xCAT/SLP.pm b/perl-xCAT/xCAT/SLP.pm index 095327467..da18d4012 100644 --- a/perl-xCAT/xCAT/SLP.pm +++ b/perl-xCAT/xCAT/SLP.pm @@ -14,6 +14,7 @@ unless ($ip6support) { #TODO: somehow get at system headers to get the value, put in linux's for now use constant IPV6_MULTICAST_IF => 17; +use constant IP_MULTICAST_IF => 32; my %xid_to_srvtype_map; my $xid; @@ -50,7 +51,7 @@ sub dodiscover { } my $interfaces = get_interfaces(%args); foreach my $srvtype (@srvtypes) { - send_attribute_request_single(%args,ifacemap=>$interfaces,SrvType=>$srvtype); + send_service_request_single(%args,ifacemap=>$interfaces,SrvType=>$srvtype); } unless ($args{NoWait}) { #in nowait, caller owns the responsibility.. #by default, report all respondants within 3 seconds: @@ -69,10 +70,17 @@ sub dodiscover { } my $result = process_slp_packet(packet=>$slppacket,sockaddr=>$peer,'socket'=>$args{'socket'}); if ($result) { + if ($peername =~ /\./) { #ipv4 + $peername =~ s/::ffff://; + } $result->{peername} = $peername; $result->{scopeid} = $scope; $result->{sockaddr} = $peer; - $rethash{$peername.'%'.$scope} = $result; + my $hashkey; + if ($peername =~ /fe80/) { + $peername .= '%'.$scope; + } + $rethash{$peername} = $result; if ($args{Callback}) { $args{Callback}->($result); } @@ -89,15 +97,17 @@ sub process_slp_packet { my $socket = $args{'socket'}; my $packet = $args{packet}; my $parsedpacket = removeslpheader($packet); -# if ($parsedpacket->{FunctionId} == 2) {#Service Reply -# $parsedpacket->{service_urls} = parse_service_reply($parsedpacket->{payload}); -# unless (scalar @{$parsedpacket->{service_urls}}) { return undef; } -# send_attribute_request('socket'=>$socket,url=>$parsedpacket->{service_urls}->[0],sockaddr=>$sockaddy); -# return undef; -# } elsif ($parsedpacket->{FunctionId} == 7) { #attribute reply - if ($parsedpacket->{FunctionId} == 7) { #attribute reply - $parsedpacket->{attributes} = parse_attribute_reply($parsedpacket->{payload}); + if ($parsedpacket->{FunctionId} == 2) {#Service Reply + $parsedpacket->{service_urls} = parse_service_reply($parsedpacket->{payload}); + unless (scalar @{$parsedpacket->{service_urls}}) { return undef; } + #send_attribute_request('socket'=>$socket,url=>$parsedpacket->{service_urls}->[0],sockaddr=>$sockaddy); + my $srvtype = $xid_to_srvtype_map{$parsedpacket->{Xid}}; + my $packet = generate_attribute_request(%args,SrvType=>$srvtype); + $socket->send($packet,0,$sockaddy); + return undef; + } elsif ($parsedpacket->{FunctionId} == 7) { #attribute reply $parsedpacket->{SrvType} = $xid_to_srvtype_map{$parsedpacket->{Xid}}; + $parsedpacket->{attributes} = parse_attribute_reply($parsedpacket->{payload}); delete $parsedpacket->{payload}; return $parsedpacket; } else { @@ -109,7 +119,7 @@ sub parse_attribute_reply { my $contents = shift; my @payload = unpack("C*",$contents); if ($payload[0] != 0 or $payload[1] != 0) { - return []; + return {}; } my $attrlength = ($payload[2]<<8)+$payload[3]; splice(@payload,0,4); @@ -164,36 +174,36 @@ sub generate_attribute_request { } -#sub parse_service_reply { -# my $packet = shift; -# my @reply = unpack("C*",$packet); -# if ($reply[0] != 0 or $reply[1] != 0) { -# return (); -# } -# my @urls; -# my $numurls = ($reply[2]<<8)+$reply[3]; -# splice (@reply,0,4); -# while ($numurls--) { -# push @urls,extract_next_url(\@reply); -# } -# return \@urls; -#} +sub parse_service_reply { + my $packet = shift; + my @reply = unpack("C*",$packet); + if ($reply[0] != 0 or $reply[1] != 0) { + return (); + } + my @urls; + my $numurls = ($reply[2]<<8)+$reply[3]; + splice (@reply,0,4); + while ($numurls--) { + push @urls,extract_next_url(\@reply); + } + return \@urls; +} -#sub extract_next_url { #section 4.3 url entries -# my $payload = shift; -# splice (@$payload,0,3); # discard reserved and lifetime which we will not bother using -# my $urllength = ((shift @$payload)<<8)+(shift @$payload); -# my @url = splice(@$payload,0,$urllength); -# my $authblocks = shift @$payload; -# unless ($authblocks == 0) { -# $payload = []; #TODO: skip/use auth blocks if needed to get at more URLs -# } -# return pack("C*",@url); -#} +sub extract_next_url { #section 4.3 url entries + my $payload = shift; + splice (@$payload,0,3); # discard reserved and lifetime which we will not bother using + my $urllength = ((shift @$payload)<<8)+(shift @$payload); + my @url = splice(@$payload,0,$urllength); + my $authblocks = shift @$payload; + unless ($authblocks == 0) { + $payload = []; #TODO: skip/use auth blocks if needed to get at more URLs + } + return pack("C*",@url); +} -sub send_attribute_request_single { +sub send_service_request_single { my %args = @_; - my $packet = generate_attribute_request(%args); + my $packet = generate_service_request(%args); my $interfaces = $args{ifacemap}; #get_interfaces(%args); my $socket = $args{'socket'}; my $v6addr; @@ -204,14 +214,19 @@ sub send_attribute_request_single { ($fam, $type, $proto, $v6addr, $name) = Socket6::getaddrinfo($target,"svrloc",Socket6::AF_INET6(),SOCK_DGRAM,0); } + my $ipv4mcastaddr = inet_aton("239.255.255.253"); #per rfc 2608 + my $ipv4sockaddr = sockaddr_in(427,$ipv4mcastaddr); foreach my $iface (keys %{$interfaces}) { if ($ip6support) { setsockopt($socket,Socket6::IPPROTO_IPV6(),IPV6_MULTICAST_IF,pack("I",$interfaces->{$iface}->{scopeidx})); $socket->send($packet,0,$v6addr); } - #setsockopt($socket,IPPROTO_IP,IP_MULTICAST_IF, - #TODO: IPv4 support -# setsockopt($socket,IPPROTO_IP,IP_MULTICAST_IF, + foreach my $ip (@{$interfaces->{$iface}->{ipv4addrs}}) { + $ip =~ s/\/.*//; + my $ipn = inet_aton($ip); #we are ipv4 only, this is ok + setsockopt($socket,0,IP_MULTICAST_IF,pack("NNI",$ipv4mcastaddr,$ipn,$interfaces->{$iface}->{scopeidx})); + $socket->send($packet,0,$ipv4sockaddr); + } } } @@ -255,24 +270,25 @@ sub get_interfaces { # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | length of string | String \ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -#sub gendiscover { -# my %args = @_; -# my $srvtype = $args{SrvType}; -# my $scope = "DEFAULT"; -# if ($args{Scopes}) { $scope = $args{Scopes}; } -# my $packet = pack("C*",0,0); #start with PRList, we have no prlist so zero -# #TODO: actually accumulate PRList, particularly between IPv4 and IPv6 runs -# my $length = length($srvtype); -# $packet .= pack("C*",($length>>8),($length&0xff)); -# $packet .= $srvtype; -# $length = length($scope); -# $packet .= pack("C*",($length>>8),($length&0xff)); -# $packet .= $scope; +sub generate_service_request { + my %args = @_; + my $srvtype = $args{SrvType}; + my $scope = "DEFAULT"; + if ($args{Scopes}) { $scope = $args{Scopes}; } + my $packet = pack("C*",0,0); #start with PRList, we have no prlist so zero + #TODO: actually accumulate PRList, particularly between IPv4 and IPv6 runs + my $length = length($srvtype); + $packet .= pack("C*",($length>>8),($length&0xff)); + $packet .= $srvtype; + $length = length($scope); + $packet .= pack("C*",($length>>8),($length&0xff)); + $packet .= $scope; #no ldap predicates, and no auth, so zeroes.. -# $packet .= pack("C*",0,0,0,0); -# my $header = genslpheader($packet,Multicast=>1,FunctionId=>1); -# return $packet = $header.$packet; -#} + $packet .= pack("C*",0,0,0,0); + my $header = genslpheader($packet,Multicast=>1,FunctionId=>1); + $xid_to_srvtype_map{$xid++}=$srvtype; + return $packet = $header.$packet; +} # SLP header from RFC 2608 # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -320,7 +336,7 @@ unless (caller) { #results on-the-fly require Data::Dumper; Data::Dumper->import(); - my $srvtypes = ["service:management-hardware.IBM:chassis-management-module","service:management-hardware.IBM:integrated-management-module2"]; + my $srvtypes = ["service:management-hardware.IBM:chassis-management-module","service:management-hardware.IBM:integrated-management-module2","service:management-hardware.IBM:management-module"]; xCAT::SLP::dodiscover(SrvTypes=>$srvtypes,Callback=>sub { print Dumper(@_) }); #example 2: simple invocation of a single service type $srvtypes = "service:management-hardware.IBM:chassis-management-module";