5 # Copyright IBM Corp. 2003, 2006.
6 # Author(s): Utz Bacher <utz.bacher@de.ibm.com>
8 # looks for addresses in the HiperSockets and sets them as Proxy ARP on the
9 # OSAs. Also adds routing entries towards the HiperSockets interfaces for
10 # all IP addresses in it
12 # $OPERATING_MODE="routing_only";
13 # ip_watcher just takes care of adapting the routing entries. ipv4
14 # forwarding needs to be switched on, if desired mrouted or some multicast
15 # routing daemon should run. ip_watcher also sets the proxy arp entries
16 # of all hsi addresses on the osa device.
18 # $OPERATING_MODE="full_bridging";
19 # this is like routing_only mode, plus xcec-bridge will bridge all
20 # kinds of traffic (uni-, multi-, broadcast) between the interfaces,
21 # so the stack will not do forwarding.
22 # if interfaces come and go, xcec-bridge will be sent a SIGUSR1.
24 # $OPERATING_MODE="mc_bridging";
25 # this is a mixture of the above -- ipv4 forwarding of unicast packets
26 # is done by the kernel, multi- and broadcast traffic is bridged by
29 # $OPERATING_MODE="bc_bridging";
30 # this is another mixture of the above -- ipv4 forwarding of unicast
31 # packets is done by the kernel, multicast is handled by mrouted or some
32 # multicast router, and broadcast traffic is bridged by xcec-bridge.
34 $OPERATING_MODE="mc_bridging";
36 $XCEC_BRIDGE="xcec-bridge";
37 $XCEC_BRIDGE_FULL_PARAM="also_unicast";
38 $XCEC_BRIDGE_MC_PARAM="";
39 $XCEC_BRIDGE_BC_PARAM="only_broadcast";
44 $MASK_PARAM="netmask";
46 $QETHARP="qetharp -c -q";
47 $ROUTE_ADD_CMD='route add -net ';
48 $ROUTE_DEL_CMD='route del -net ';
49 $PA_ADD_CMD='qethconf parp add -x';
50 $PA_DEL_CMD='qethconf parp del -x';
51 # $PA_ADD_CMD='echo add_rxip4';
52 # $PA_DEL_CMD='echo del_rxip4';
53 # $PA_ADD_POST_CMD='>/proc/qeth_ipa_takeover';
54 # $PA_DEL_POST_CMD='>/proc/qeth_ipa_takeover';
56 $QETH_PROC_FILE="/proc/qeth";
60 if ($#ARGV>=$nextarg) {
61 if ($ARGV[$nextarg] eq "--check") {
67 # if there is a parameter to ip_watcher.pl, the parameter will be the
68 # Proxy ARP interface (i.e. the outgoing OSA interface). In this case,
69 # xcec-bridge will not be started, so that only unicast is forwarded.
71 # eth0 is default OSA interface
72 if ($#ARGV>=$nextarg) {
73 $PA_INTERFACE=$ARGV[$nextarg];
74 $START_XCEC_BRIDGE="no";
77 $START_XCEC_BRIDGE="yes";
80 $PROXY_ARP_INTERFACE='( ((index($if_name,"eth")==0) && ($rtr eq "mc")) ||
81 ((index($if_name,"eth")==0) && ($rtr eq "mc+")) ||
82 ((index($if_name,"tr")==0) && ($rtr eq "mc")) ||
83 ((index($if_name,"tr")==0) && ($rtr eq "mc+")) )';
87 #@time_array=(time,time-1,time-2);
90 # all relevant interfaces are no routers
91 # $RELEVANT_INTERFACE='($rtr eq "no")';
92 # all interfaces start with "hsi"
93 # $RELEVANT_INTERFACE='($if_name=~/^hsi/)';
94 # all relevant interfaces are connectors
95 # $RELEVANT_INTERFACE='(($rtr eq "p.c") || ($rtr eq "s.c") ||
96 # ($rtr eq "p+c") || ($rtr eq "s+c"))';
98 $RELEVANT_INTERFACE='(($rtr eq "p.c") || ($rtr eq "s.c") ||
99 ($rtr eq "p+c") || ($rtr eq "s+c"))';
108 print "DEBUG ". $h .": ". $i ."\n";
113 # get outgoing OSA interface (connecting the CECs)
114 sub get_proxy_arp_interface
126 if (open(FD
,"<" . $QETH_PROC_FILE)) {
134 ($devnos,$chpid,$if_name,$type,
135 $port,$chksum,$prio,$rtr,$rest)=split(/\s/);
136 if (eval $PROXY_ARP_INTERFACE) {
137 $PA_INTERFACE=$if_name;
142 } elsif (opendir(SYSQETH
, "/sys/devices/qeth")) {
143 @ALLDEV = grep { /^.+\..+\..+$/ } readdir SYSQETH
;
146 foreach $DEV (@ALLDEV) {
147 open(IFNAME
, "</sys/devices/qeth/$DEV/if_name") or next;
148 chomp($if_name = readline(IFNAME
));
150 open(RTR
, "</sys/devices/qeth/$DEV/route4") or next;
151 chomp($rtr = readline(RTR
));
153 if ( $if_name =~ /^tr|eth.+/ and $rtr =~ /^multicast.+/ ) {
154 $PA_INTERFACE=$if_name;
158 die "could not get availabe qeth interfaces\n";
161 if ($PA_INTERFACE eq "") {
162 die "no multicast router defined or no " .
163 "LAN interface specified as parameter.\n";
167 # get all interfaces to poll ip addresses from
168 sub update_interface_list
181 if (open(FD
,"<" . $QETH_PROC_FILE)) {
188 ($devnos,$chpid,$if_name,$type,
189 $port,$chksum,$prio,$rtr,$rest)=split(/\s/);
190 if (eval $RELEVANT_INTERFACE) {
191 push(@if_list,$if_name);
196 } elsif (opendir(SYSQETH
, "/sys/devices/qeth")) {
197 @ALLDEV = grep { /^.+\..+\..+$/ } readdir SYSQETH
;
200 foreach $DEV (@ALLDEV) {
201 open(IFNAME
, "</sys/devices/qeth/$DEV/if_name") or next;
202 chomp($if_name = readline(IFNAME
));
204 open(RTR
, "</sys/devices/qeth/$DEV/route4") or next;
205 chomp($rtr = readline(RTR
));
207 if ( $rtr =~ /^.+connector.*/ ) {
208 push(@if_list,$if_name);
212 print STDERR
"could not get availabe qeth interfaces\n";
218 # only returns with a maximal frequency
225 # unshift(@time_array,$t_now);
226 # $t_last=pop(@time_array);
227 # $sleep_time=$TIME_LIMIT-($t_now-$t_last);
228 # if ($sleep_time>0) {
229 # sleep($sleep_time);
234 # creates a 0x01020304 out of a 1.2.3.4
235 sub convert_ip_string_to_number
($)
244 @ip=split(/\./,$ip_str);
246 # check for parsing error
251 ($ip_oct1,$ip_oct2,$ip_oct3,$ip_oct4)=@ip;
253 if ( ($ip_oct1<0) || ($ip_oct1>255) ||
254 ($ip_oct2<0) || ($ip_oct2>255) ||
255 ($ip_oct3<0) || ($ip_oct3>255) ||
256 ($ip_oct4<0) || ($ip_oct4>255) ) {
260 return ($ip_oct1<<24)+($ip_oct2<<16)+($ip_oct3<<8)+($ip_oct4);
263 # returns sorted list of ips (in integer format like __u32) of the interface
264 sub get_ips_on_interface
($)
266 my($interface)=shift;
267 my($cmdline)="$QETHARP $interface |";
272 unless (open(OUTPUT
,$cmdline)) {
273 print STDERR
"can't open $cmdline";
278 $ip=convert_ip_string_to_number
($_);
283 close(OUTPUT
) || print STDERR
"can't close $cmdline";
285 return sort @ip_list;
288 # creates a 1.2.3.4 out of a 0x1020304
289 sub convert_string_to_ip
($)
305 return "$ip_oct1.$ip_oct2.$ip_oct3.$ip_oct4";
319 # will create an array of routes in string format
320 sub get_routes_of_ip_list
(@
)
336 while ($#ip_list>=0) {
337 # ips_left is the number of ips left in the list
342 while ($ip_shifted%2==0) {
345 # 0 should never be in the list, anyway...
350 # ips_to_combine is a power of 2 and contains the max number
351 # of entries that could compressed into one route due to its
353 $end=__min
($ips_to_combine-1,$ips_left);
356 while ($ips_found<=$end) {
357 # ips_found-1, as we have shifted the first ip
359 if ($ip_list[$ips_found-1]!=$ip+$ips_found) {
363 if ($ips_found==2*$order) {
367 # ips_found is now the number of subsequent ips that we can
368 # subsum (one of which is shifted already)
369 $mask=(-$order)&0xffffffff;
371 while ($ips_fetched<$order) {
375 $mask_str=convert_string_to_ip
($mask);
376 $ip_str=convert_string_to_ip
($ip);
377 unshift(@route_list,"$ip_str $MASK_PARAM $mask_str");
383 # will create an array of rxips in string format
384 sub get_pas_of_ip_list
(@
)
389 foreach $ip (@ip_list) {
390 unshift(@pa_list,"" . sprintf("%08x",$ip));
410 sub exec_for_diff
($@@
)
413 my($new_list,$old_list)=@_;
415 foreach $line (@
$new_list) {
416 unless (is_in_list
($line,@
$old_list)) {
417 system($cmd . $line . "> /dev/null 2>&1");
422 sub wait_for_changes
()
424 # blocking ioctl to be informed on SETIP/DELIPs (once it's implemented in
425 # hardware) or sleep for X timeunits
434 my(@interface_list)=();
441 get_proxy_arp_interface
();
443 if ($CHECK_ONLY eq "yes") {
447 if ($START_XCEC_BRIDGE eq "yes") {
448 if ($OPERATING_MODE eq "full_bridging") {
449 system("$XCEC_BRIDGE $XCEC_BRIDGE_FULL_PARAM &")==0 ||
450 die "can't fork $XCEC_BRIDGE: $?";
452 if ($OPERATING_MODE eq "mc_bridging") {
453 system("$XCEC_BRIDGE $XCEC_BRIDGE_MC_PARAM &")==0 ||
454 die "can't fork $XCEC_BRIDGE: $?";
456 if ($OPERATING_MODE eq "bc_bridging") {
457 system("$XCEC_BRIDGE $XCEC_BRIDGE_BC_PARAM &")==0 ||
458 die "can't fork $XCEC_BRIDGE: $?";
463 if ( ($OPERATING_MODE eq "mc_bridging") ||
464 ($OPERATING_MODE eq "bc_bridging") ||
465 ($OPERATING_MODE eq "full_bridging") ) {
466 @old_if_list=@interface_list;
468 @interface_list=update_interface_list
();
469 if ( ($OPERATING_MODE eq "mc_bridging") ||
470 ($OPERATING_MODE eq "bc_bridging") ||
471 ($OPERATING_MODE eq "full_bridging") ) {
472 if ( join(':',@old_if_list) ne
473 join(':',@interface_list) ) {
474 if ($START_XCEC_BRIDGE eq "yes") {
475 system("$KILLALL $SIGNAL $XCEC_BRIDGE")==0 ||
476 print STDERR
"can't send signal " .
477 "to $XCEC_BRIDGE to update " .
484 foreach $interface (@interface_list) {
485 @ip_list=get_ips_on_interface
($interface);
487 @tmp_routes=get_routes_of_ip_list
(@ip_list);
488 foreach $route (@tmp_routes) {
490 "$route $DEV_PARAM $interface");
493 @tmp_pas=get_pas_of_ip_list
(@ip_list);
494 foreach $pa (@tmp_pas) {
496 "$pa $PA_INTERFACE");
500 exec_for_diff
($ROUTE_ADD_CMD,\
@new_routes,\
@routes);
501 exec_for_diff
($ROUTE_DEL_CMD,\
@routes,\
@new_routes);
504 exec_for_diff
($PA_ADD_CMD,\
@new_pas,\
@pas);
505 exec_for_diff
($PA_DEL_CMD,\
@pas,\
@new_pas);