ipMore.tcl

Go to the documentation of this file.
00001 /* temporary home until this gets cleaned up for export to tcllib ip module*/
00002 /*  $Id: ipMore.tcl,v 1.4 2006/01/22 00:27:22 andreas_kupries Exp $*/
00003 
00004 
00005 /* Library Header*/
00006 /* */
00007 /*  Copyright (c) 2005 Cisco Systems, Inc.*/
00008 /* */
00009 /*  Name:*/
00010 /*        ipMore*/
00011 /* */
00012 /*  Purpose:*/
00013 /*        Additional commands for the tcllib ip package.*/
00014 /* */
00015 /*  Author:*/
00016 /*         Aamer Akhter / aakhter@cisco.com*/
00017 /* */
00018 /*  Support Alias:*/
00019 /*        aakhter@cisco.com*/
00020 /* */
00021 /*  Usage:*/
00022 /*        package require ip*/
00023 /*        (The command are loaded from the regular package).*/
00024 /* */
00025 /*  Description:*/
00026 /*        A detailed description of the functionality provided by the library.*/
00027 /*       */
00028 /*  Requirements:*/
00029 /* */
00030 /*  Variables:*/
00031 /*        namespace   ::ip*/
00032 /* */
00033 /*  Notes:*/
00034 /*        1.*/
00035 /* */
00036 /*  Keywords:*/
00037 /* */
00038 /* */
00039 /*  Category: */
00040 /*        */
00041 /* */
00042 /*  End of Header*/
00043 
00044 package require msgcat
00045 
00046 /*  Try to load various C based accelerato packages for two of the*/
00047 /*  commands.*/
00048 
00049 if {[catch {package require ipMorec}]} {
00050     catch {package require tcllibc}
00051 }
00052 
00053 if {[llength [info commands ::ip::prefixToNativec]]} {
00054     /*  An accelerator is present, providing the C variants*/
00055     interp alias {} ::ip::prefixToNative  {} ::ip::prefixToNativec
00056     interp alias {} ::ip::isOverlapNative {} ::ip::isOverlapNativec
00057 } else {
00058     /*  Link API to the Tcl variants, no accelerators are available.*/
00059     interp alias {} ::ip::prefixToNative  {} ::ip::prefixToNativeTcl
00060     interp alias {} ::ip::isOverlapNative {} ::ip::isOverlapNativeTcl
00061 }
00062 
00063 namespace ::ip {
00064     ::msgcat::mc
00065 }
00066 
00067 if {![llength [info commands lassign]]} {
00068     /*  Either an older tcl version, or tclx not loaded; have to use our*/
00069     /*  internal lassign from http://wiki.tcl.tk/1530 by Schelte Bron*/
00070 
00071     ret  ::ip::lassign (type values , type args) {
00072         uplevel 1 [list foreach $args $values break]
00073         lrange $values [llength $args] end
00074     }
00075 }
00076 if {![llength [info commands lvarpop]]} {
00077     /*  Define an emulation of Tclx's lvarpop if the command*/
00078     /*  is not present already.*/
00079 
00080     ret  ::ip::lvarpop (type upVar , optional index =0) {
00081     upvar $upVar list;
00082     set top [lindex $list $index];
00083     set list [concat [lrange $list 0 [expr $index - 1]] \
00084               [lrange $list [expr $index +1] end]];
00085     return $top;
00086     }
00087 }
00088 
00089 /*  Some additional aliases for backward compatability. Not*/
00090 /*  documented. The old names ar from previous versions while at Cisco.*/
00091 /* */
00092 /*                Old command name -->      Documented command name*/
00093 interp alias {} ::ip::ToInteger           {} ::ip::toInteger
00094 interp alias {} ::ip::ToHex               {} ::ip::toHex
00095 interp alias {} ::ip::MaskToInt           {} ::ip::maskToInt
00096 interp alias {} ::ip::MaskToLength        {} ::ip::maskToLength
00097 interp alias {} ::ip::LengthToMask        {} ::ip::lengthToMask
00098 interp alias {} ::ip::IpToLayer2Multicast {} ::ip::ipToLayer2Multicast
00099 interp alias {} ::ip::IpHostFromPrefix    {} ::ip::ipHostFromPrefix
00100 
00101 
00102 /* Procedure Header*/
00103 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00104 /* */
00105 /*  Name:*/
00106 /*        ::ip::prefixToNative*/
00107 /* */
00108 /*  Purpose:*/
00109 /*         convert from dotted from to native (hex) form*/
00110 /* */
00111 /*  Synopsis:*/
00112 /*        prefixToNative <prefix>*/
00113 /* */
00114 /*  Arguments:*/
00115 /*         <prefix>*/
00116 /*             string in the <ipaddr>/<mask> format*/
00117 /* */
00118 /*  Return Values:*/
00119 /*         <prefix> in native format {<hexip> <hexmask>}*/
00120 /* */
00121 /*  Description:*/
00122 /*        */
00123 /*  Examples:*/
00124 /*    % ip::prefixToNative 1.1.1.0/24*/
00125 /*    0x01010100 0xffffff00*/
00126 /* */
00127 /*  Sample Input:*/
00128 /* */
00129 /*  Sample Output:*/
00130 /*  Notes:*/
00131 /*    fixed bug in C extension that modified */
00132 /*     calling context variable*/
00133 /*  See Also:*/
00134 /* */
00135 /*  End of Header*/
00136 
00137 ret  ip::prefixToNativeTcl (type prefix) {
00138     set plist {}
00139     foreach p $prefix {
00140     set newPrefix [ip::toHex [ip::prefix $p]]
00141     if {[string equal [set mask [ip::mask $p]] ""]} {
00142         set newMask 0xffffffff
00143     } else {
00144         set newMask [format "0x%08x" [ip::maskToInt $mask]]
00145     }
00146     lappend plist [list $newPrefix $newMask]
00147     }
00148     if {[llength $plist]==1} {return [lindex $plist 0]}
00149     return $plist
00150 }
00151 
00152 /* Procedure Header*/
00153 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00154 /* */
00155 /*  Name:*/
00156 /*        ::ip::nativeToPrefix*/
00157 /* */
00158 /*  Purpose:*/
00159 /*         convert from native (hex) form to dotted form*/
00160 /* */
00161 /*  Synopsis:*/
00162 /*        nativeToPrefix <nativeList>|<native> [-ipv4]*/
00163 /* */
00164 /*  Arguments:*/
00165 /*         <nativeList> */
00166 /*             list of native form ip addresses native form is:*/
00167 /*         <native>*/
00168 /*             tcllist in format {<hexip> <hexmask>}*/
00169 /*         -ipv4*/
00170 /*             the provided native format addresses are in ipv4 format (default)*/
00171 /* */
00172 /*  Return Values:*/
00173 /*         if nativeToPrefix is called with <native> a single (non-listified) address*/
00174 /*             is returned*/
00175 /*         if nativeToPrefix is called with a <nativeList> address list, then */
00176 /*             a list of addresses is returned*/
00177 /* */
00178 /*         return form is: <ipaddr>/<mask>*/
00179 /* */
00180 /*  Description:*/
00181 /*        */
00182 /*  Examples:*/
00183 /*    % ip::nativeToPrefix {0x01010100 0xffffff00} -ipv4*/
00184 /*    1.1.1.0/24*/
00185 /* */
00186 /*  Sample Input:*/
00187 /* */
00188 /*  Sample Output:*/
00189 
00190 /*  Notes:*/
00191 /* */
00192 /*  See Also:*/
00193 /* */
00194 /*  End of Header*/
00195 
00196 ret  ::ip::nativeToPrefix (type nativeList , type args) {
00197     set pList 1
00198     set ipv4 1
00199     while {[llength $args]} {
00200     switch -- [lindex $args 0] {
00201         -ipv4 {set args [lrange $args 1 end]}
00202         default {
00203         return -code error [msgcat::mc "option %s not supported" [lindex $args 0]]
00204         }
00205     }
00206     }
00207 
00208     # if a single native element is passed eg {0x01010100 0xffffff00}
00209     # instead of {{0x01010100 0xffffff00} {0x01010100 0xffffff00}...}
00210     # then return a (non-list) single entry
00211     if {[llength [lindex $nativeList 0]]==1} {set pList 0; set nativeList [list $nativeList]}
00212     foreach native $nativeList {
00213     lassign $native ip mask
00214     if {[string equal $mask ""]} {set mask 32}
00215     set pString ""
00216     append pString [ip::ToString [binary format I [expr {$ip}]]]
00217     append pString  "/"
00218     append pString [ip::maskToLength $mask]
00219     lappend rList $pString
00220     }
00221     # a multi (listified) entry was given
00222     # return the listified entry
00223     if {$pList} { return $rList }
00224     return $pString
00225 }
00226 
00227 /* Procedure Header*/
00228 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00229 /* */
00230 /*  Name:*/
00231 /*        ::ip::intToString*/
00232 /* */
00233 /*  Purpose:*/
00234 /*         convert from an integer/hex to dotted form*/
00235 /* */
00236 /*  Synopsis:*/
00237 /*        intToString <integer/hex> [-ipv4]*/
00238 /* */
00239 /*  Arguments:*/
00240 /*         <integer>*/
00241 /*             ip address in integer form*/
00242 /*         -ipv4*/
00243 /*             the provided integer addresses is ipv4 (default)*/
00244 /* */
00245 /*  Return Values:*/
00246 /*         ip address in dotted form*/
00247 /* */
00248 /*  Description:*/
00249 /*        */
00250 /*  Examples:*/
00251 /*        ip::intToString 4294967295*/
00252 /*        255.255.255.255*/
00253 /* */
00254 /*  Sample Input:*/
00255 /* */
00256 /*  Sample Output:*/
00257 
00258 /*  Notes:*/
00259 /* */
00260 /*  See Also:*/
00261 /* */
00262 /*  End of Header*/
00263 
00264 ret  ::ip::intToString (type int , type args) {
00265     set ipv4 1
00266     while {[llength $args]} {
00267     switch -- [lindex $args 0] {
00268         -ipv4 {set args [lrange $args 1 end]}
00269         default {
00270         return -code error [msgcat::mc "option %s not supported" [lindex $args 0]]
00271         }
00272     }
00273     }
00274     return [ip::ToString [binary format I [expr {$int}]]]
00275 }
00276 
00277 
00278 /* Procedure Header*/
00279 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00280 /* */
00281 /*  Name:*/
00282 /*        ::ip::toInteger*/
00283 /* */
00284 /*  Purpose:*/
00285 /*         convert dotted form ip to integer*/
00286 /* */
00287 /*  Synopsis:*/
00288 /*        toInteger <ipaddr>*/
00289 /* */
00290 /*  Arguments:*/
00291 /*         <ipaddr>*/
00292 /*             decimal dotted from ip address*/
00293 /* */
00294 /*  Return Values:*/
00295 /*         integer form of <ipaddr>*/
00296 /* */
00297 /*  Description:*/
00298 /*        */
00299 /*  Examples:*/
00300 /*    % ::ip::toInteger 1.1.1.0*/
00301 /*    16843008*/
00302 /* */
00303 /*  Sample Input:*/
00304 /* */
00305 /*  Sample Output:*/
00306 
00307 /*  Notes:*/
00308 /* */
00309 /*  See Also:*/
00310 /* */
00311 /*  End of Header*/
00312 
00313 ret  ::ip::toInteger (type ip) {
00314     binary scan [ip::Normalize4 $ip] I out
00315     return $out
00316 }
00317 
00318 /* Procedure Header*/
00319 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00320 /* */
00321 /*  Name:*/
00322 /*        ::ip::toHex*/
00323 /* */
00324 /*  Purpose:*/
00325 /*         convert dotted form ip to hex*/
00326 /* */
00327 /*  Synopsis:*/
00328 /*        toHex <ipaddr>*/
00329 /* */
00330 /*  Arguments:*/
00331 /*         <ipaddr>*/
00332 /*             decimal dotted from ip address*/
00333 /* */
00334 /*  Return Values:*/
00335 /*         hex form of <ipaddr>*/
00336 /* */
00337 /*  Description:*/
00338 /*        */
00339 /*  Examples:*/
00340 /*    % ::ip::toHex 1.1.1.0*/
00341 /*    0x01010100*/
00342 /* */
00343 /*  Sample Input:*/
00344 /* */
00345 /*  Sample Output:*/
00346 
00347 /*  Notes:*/
00348 /* */
00349 /*  See Also:*/
00350 /* */
00351 /*  End of Header*/
00352 
00353 ret  ::ip::toHex (type ip) {
00354     binary scan [ip::Normalize4 $ip] H8 out
00355     return "0x$out"
00356 }
00357 
00358 /* Procedure Header*/
00359 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00360 /* */
00361 /*  Name:*/
00362 /*        ::ip::maskToInt*/
00363 /* */
00364 /*  Purpose:*/
00365 /*         convert mask to integer*/
00366 /* */
00367 /*  Synopsis:*/
00368 /*        maskToInt <mask>*/
00369 /* */
00370 /*  Arguments:*/
00371 /*         <mask>*/
00372 /*             mask in either dotted form or mask length form (255.255.255.0 or 24)*/
00373 /* */
00374 /*  Return Values:*/
00375 /*         integer form of mask*/
00376 /* */
00377 /*  Description:*/
00378 /*        */
00379 /*  Examples:*/
00380 /*    ::ip::maskToInt 24*/
00381 /*    4294967040*/
00382 /* */
00383 /*    */
00384 /*  Sample Input:*/
00385 /* */
00386 /*  Sample Output:*/
00387 
00388 /*  Notes:*/
00389 /* */
00390 /*  See Also:*/
00391 /* */
00392 /*  End of Header*/
00393 
00394 ret  ::ip::maskToInt (type mask) {
00395     if {[string is integer -strict $mask]} {
00396         set maskInt [expr {(0xFFFFFFFF << (32 - $mask))}]
00397     } else {
00398         binary scan [Normalize4 $mask] I maskInt
00399     }
00400     set maskInt [expr {$maskInt & 0xFFFFFFFF}]
00401     return [format %u $maskInt]
00402 }
00403 
00404 /* Procedure Header*/
00405 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00406 /* */
00407 /*  Name:*/
00408 /*        ::ip::broadcastAddress*/
00409 /* */
00410 /*  Purpose:*/
00411 /*         return broadcast address given prefix*/
00412 /* */
00413 /*  Synopsis:*/
00414 /*        broadcastAddress <prefix> [-ipv4]*/
00415 /* */
00416 /*  Arguments:*/
00417 /*         <prefix>*/
00418 /*             route in the form of <ipaddr>/<mask> or native form {<hexip> <hexmask>}*/
00419 /*         -ipv4*/
00420 /*             the provided native format addresses are in ipv4 format (default)*/
00421 /*             note: broadcast addresses are not valid in ipv6*/
00422 /*             */
00423 /* */
00424 /*  Return Values:*/
00425 /*         ipaddress of broadcast*/
00426 /* */
00427 /*  Description:*/
00428 /*        */
00429 /*  Examples:*/
00430 /*    ::ip::broadcastAddress 1.1.1.0/24*/
00431 /*    1.1.1.255*/
00432 /*    */
00433 /*    ::ip::broadcastAddress {0x01010100 0xffffff00}*/
00434 /*    0x010101ff*/
00435 /* */
00436 /*  Sample Input:*/
00437 /* */
00438 /*  Sample Output:*/
00439 
00440 /*  Notes:*/
00441 /* */
00442 /*  See Also:*/
00443 /* */
00444 /*  End of Header*/
00445 
00446 ret  ::ip::broadcastAddress (type prefix , type args) {
00447     set ipv4 1
00448     while {[llength $args]} {
00449     switch -- [lindex $args 0] {
00450         -ipv4 {set args [lrange $args 1 end]}
00451         default {
00452         return -code error [msgcat::mc "option %s not supported" [lindex $args 0]]
00453         }
00454     }
00455     }
00456     if {[llength $prefix] == 2} {
00457     lassign $prefix net mask
00458     } else {
00459     set net [maskToInt [ip::prefix $prefix]]
00460     set mask [maskToInt [ip::mask $prefix]]
00461     }
00462     set ba [expr {$net  | ((~$mask)&0xffffffff)}]
00463     
00464     if {[llength $prefix]==2} {
00465     return [format "0x%08x" $ba]
00466     }
00467     return [ToString [binary format I $ba]]
00468 }
00469 
00470 /* Procedure Header*/
00471 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00472 /* */
00473 /*  Name:*/
00474 /*        ::ip::maskToLength*/
00475 /* */
00476 /*  Purpose:*/
00477 /*         converts dotted or integer form of mask to length*/
00478 /* */
00479 /*  Synopsis:*/
00480 /*        maskToLength <dottedMask>|<integerMask>|<hexMask> [-ipv4]*/
00481 /* */
00482 /*  Arguments:*/
00483 /*         <dottedMask>*/
00484 /*         <integerMask>*/
00485 /*         <hexMask>*/
00486 /*             mask to convert to prefix length format (eg /24)*/
00487 /*          -ipv4*/
00488 /*             the provided integer/hex format masks are ipv4 (default)*/
00489 /* */
00490 /*  Return Values:*/
00491 /*         prefix length*/
00492 /* */
00493 /*  Description:*/
00494 /*        */
00495 /*  Examples:*/
00496 /*    ::ip::maskToLength 0xffffff00 -ipv4*/
00497 /*    24*/
00498 /* */
00499 /*    % ::ip::maskToLength 255.255.255.0*/
00500 /*    24*/
00501 /* */
00502 /*  Sample Input:*/
00503 /* */
00504 /*  Sample Output:*/
00505 /*  Notes:*/
00506 /* */
00507 /*  See Also:*/
00508 /* */
00509 /*  End of Header*/
00510 
00511 ret  ::ip::maskToLength (type mask , type args) {
00512     set ipv4 1
00513     while {[llength $args]} {
00514     switch -- [lindex $args 0] {
00515         -ipv4 {set args [lrange $args 1 end]}
00516         default {
00517         return -code error [msgcat::mc "option %s not supported" [lindex $args 0]]
00518         }
00519     }
00520     }
00521     #pick the fastest method for either format
00522     if {[string is integer -strict $mask]} {
00523     binary scan [binary format I [expr {$mask}]] B32 maskB
00524     if {[regexp -all {^1+} $maskB ones]} {
00525         return [string length $ones]
00526     } else {
00527         return 0
00528     }
00529     } else {
00530     regexp {\/(.+)} $mask dumb mask
00531     set prefix 0
00532     foreach ipByte [split $mask {.}] {
00533         switch $ipByte {
00534         255 {incr prefix 8; continue}
00535         254 {incr prefix 7}
00536         252 {incr prefix 6}
00537         248 {incr prefix 5}
00538         240 {incr prefix 4}
00539         224 {incr prefix 3}
00540         192 {incr prefix 2}
00541         128 {incr prefix 1}
00542         0   {}
00543         default { 
00544             return -code error [msgcat::mc "not an ip mask: %s" $mask]
00545         }
00546         }
00547         break
00548     }
00549     return $prefix
00550     }
00551 }
00552 
00553 
00554 /* Procedure Header*/
00555 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00556 /* */
00557 /*  Name:*/
00558 /*        ::ip::lengthToMask*/
00559 /* */
00560 /*  Purpose:*/
00561 /*         converts mask length to dotted mask form*/
00562 /* */
00563 /*  Synopsis:*/
00564 /*        lengthToMask <maskLength> [-ipv4]*/
00565 /* */
00566 /*  Arguments:*/
00567 /*         <maskLength>*/
00568 /*             mask length   */
00569 /*         -ipv4*/
00570 /*             the provided mask length is ipv4 (default)  */
00571 /* */
00572 /*  Return Values:*/
00573 /*         mask in dotted form*/
00574 /* */
00575 /*  Description:*/
00576 /*        */
00577 /*  Examples:*/
00578 /*    ::ip::lengthToMask 24*/
00579 /*    255.255.255.0*/
00580 /* */
00581 /*  Sample Input:*/
00582 /* */
00583 /*  Sample Output:*/
00584 /*  Notes:*/
00585 /* */
00586 /*  See Also:*/
00587 /* */
00588 /*  End of Header*/
00589 
00590 ret  ::ip::lengthToMask (type masklen , type args) {
00591     while {[llength $args]} {
00592     switch -- [lindex $args 0] {
00593         -ipv4 {set args [lrange $args 1 end]}
00594         default {
00595         return -code error [msgcat::mc "option %s not supported" [lindex $args 0]]
00596         }
00597     }
00598     }
00599     # the fastest method is just to look
00600     # thru an array
00601     return $::ip::maskLenToDotted($masklen)
00602 }
00603 
00604 /* Procedure Header*/
00605 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00606 /* */
00607 /*  Name:*/
00608 /*        ::ip::nextNet*/
00609 /* */
00610 /*  Purpose:*/
00611 /*         returns next an ipaddress in same position in next network*/
00612 /* */
00613 /*  Synopsis:*/
00614 /*        nextNet <ipaddr> <mask> [<count>] [-ipv4]*/
00615 /* */
00616 /*  Arguments:*/
00617 /*         <ipaddress>*/
00618 /*             in hex/integer/dotted format*/
00619 /*         <mask>*/
00620 /*             mask in hex/integer/dotted/maskLen format*/
00621 /*         <count>*/
00622 /*             number of nets to skip over (default is 1)*/
00623 /*         -ipv4*/
00624 /*             the provided hex/integer addresses are in ipv4 format (default)*/
00625 /* */
00626 /*  Return Values:*/
00627 /*         ipaddress in same position in next network in hex*/
00628 /* */
00629 /*  Description:*/
00630 /*        */
00631 /*  Examples:*/
00632 /* */
00633 /*  Sample Input:*/
00634 /* */
00635 /*  Sample Output:*/
00636 /*  Notes:*/
00637 /* */
00638 /*  See Also:*/
00639 /* */
00640 /*  End of Header*/
00641 
00642 ret  ::ip::nextNet (type prefix , type mask , type args) {
00643     set count 1
00644     while {[llength $args]} {
00645     switch -- [lindex $args 0] {
00646         -ipv4 {set args [lrange $args 1 end]}
00647         default {
00648         set count [lindex $args 0]
00649         set args [lrange $args 1 end]
00650         }
00651     }
00652     }
00653     if {![string is integer -strict $prefix]} { 
00654     set prefix [toInteger $prefix]
00655     }
00656     if {![string is integer -strict $mask] || ($mask < 33 && $mask > 0)} {
00657     set mask [maskToInt $mask]
00658     } 
00659     
00660     set prefix [expr $prefix + ($mask ^ 0xFFffFFff) + $count ]
00661     return [format "0x%08x" $prefix]
00662 }
00663 
00664 
00665 /* Procedure Header*/
00666 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00667 /* */
00668 /*  Name:*/
00669 /*        ::ip::isOverlap*/
00670 /* */
00671 /*  Purpose:*/
00672 /*         checks to see if prefixes overlap*/
00673 /* */
00674 /*  Synopsis:*/
00675 /*        isOverlap <prefix> <prefix1> <prefix2>...*/
00676 /* */
00677 /*  Arguments:*/
00678 /*         <prefix>*/
00679 /*             in form <ipaddr>/<mask> prefix to compare <prefixN> against*/
00680 /*         <prefixN>*/
00681 /*             in form <ipaddr>/<mask> prefixes to compare against*/
00682 /* */
00683 /*  Return Values:*/
00684 /*         1 if there is an overlap*/
00685 /* */
00686 /*  Description:*/
00687 /*        */
00688 /*  Examples:*/
00689 /*         % ::ip::isOverlap 1.1.1.0/24 2.1.0.1/32*/
00690 /*         0*/
00691 /* */
00692 /*         ::ip::isOverlap 1.1.1.0/24 2.1.0.1/32 1.1.1.1/32*/
00693 /*         1*/
00694 /*  Sample Input:*/
00695 /* */
00696 /*  Sample Output:*/
00697 /*  Notes:*/
00698 /* */
00699 /*  See Also:*/
00700 /* */
00701 /*  End of Header*/
00702 
00703 ret  ::ip::isOverlap (type ip , type args) {
00704     lassign [SplitIp $ip] ip1 mask1
00705     set ip1int [toInteger $ip1]
00706     set mask1int [maskToInt $mask1]
00707 
00708     set overLap 0
00709     foreach prefix $args {
00710     lassign [SplitIp $prefix] ip2 mask2
00711     set ip2int [toInteger $ip2]
00712     set mask2int [maskToInt $mask2]
00713     set mask1mask2 [expr {$mask1int & $mask2int}]
00714     if {[expr {$ip1int & $mask1mask2}] ==  [expr {$ip2int & $mask1mask2}]} {
00715         set overLap 1
00716         break
00717     }
00718     }
00719     return $overLap
00720 }
00721 
00722 
00723 /* optimized overlap, that accepts native format*/
00724 
00725 /* Procedure Header*/
00726 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00727 /* */
00728 /*  Name:*/
00729 /*        ::ip::isOverlapNative*/
00730 /* */
00731 /*  Purpose:*/
00732 /*         checks to see if prefixes overlap (optimized native form)*/
00733 /* */
00734 /*  Synopsis:*/
00735 /*        isOverlap <hexipaddr> <hexmask> {{<hexipaddr1> <hexmask1>} {<hexipaddr2> <hexmask2>...}*/
00736 /* */
00737 /*  Arguments:*/
00738 /*         -all*/
00739 /*             return all overlaps rather than the first one*/
00740 /*         -inline*/
00741 /*             rather than returning index values, return the actual overlap prefixes*/
00742 /*         <hexipaddr>*/
00743 /*             ipaddress in hex/integer form*/
00744 /*         <hexMask>*/
00745 /*             mask in hex/integer form*/
00746 /*         -ipv4*/
00747 /*             the provided native format addresses are in ipv4 format (default)*/
00748 /* */
00749 /*  Return Values:*/
00750 /*         non-zero if there is an overlap, value is element # in list with overlap*/
00751 /* */
00752 /*  Description:*/
00753 /*         isOverlapNative is avaliabel both as a C extension and in a native tcl form*/
00754 /*         if the extension is loaded (tried automatically), isOverlapNative will be*/
00755 /*         linked to isOverlapNativeC. If an extension is not loaded, then isOverlapNative*/
00756 /*         will be linked to the native tcl proc: ipOverlapNativeTcl.*/
00757 /* */
00758 /*  Examples:*/
00759 /*         % ::ip::isOverlapNative 0x01010100 0xffffff00 {{0x02010001 0xffffffff}}*/
00760 /*         0*/
00761 /* */
00762 /*         %::ip::isOverlapNative 0x01010100 0xffffff00 {{0x02010001 0xffffffff} {0x01010101 0xffffffff}}*/
00763 /*         2*/
00764 /* */
00765 /*  Sample Input:*/
00766 /* */
00767 /*  Sample Output:*/
00768 /*  Notes:*/
00769 /* */
00770 /*  See Also:*/
00771 /* */
00772 /*  End of Header*/
00773 
00774 ret  ::ip::isOverlapNativeTcl (type args) {
00775     set all 0
00776     set inline 0
00777     set notOverlap 0
00778     set ipv4 1
00779     foreach sw [lrange $args 0 end-3] {
00780     switch -exact -- $sw {
00781         -all {
00782         set all 1
00783         set allList [list]
00784         }
00785         -inline {set inline 1}
00786         -ipv4 {}
00787     }
00788     }
00789     set args [lassign [lrange $args end-2 end] ip1int mask1int prefixList]
00790     if {$inline} { 
00791     set overLap [list]
00792     } else {
00793     set overLap 0
00794     }
00795     set count 0
00796     foreach prefix $prefixList {
00797     incr count
00798     lassign $prefix ip2int mask2int
00799     set mask1mask2 [expr {$mask1int & $mask2int}]
00800     if {[expr {$ip1int & $mask1mask2}] ==  [expr {$ip2int & $mask1mask2}]} {
00801         if {$inline} {
00802         set overLap [list $prefix]
00803         } else {
00804         set overLap $count
00805         }
00806         if {$all} {
00807         if {$inline} {
00808             lappend allList $prefix
00809         } else {
00810             lappend allList $count
00811         }
00812         } else {
00813         break
00814         }
00815     }
00816     }
00817     if {$all} {return $allList}
00818     return $overLap
00819 }
00820 
00821 /* Procedure Header*/
00822 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00823 /* */
00824 /*  Name:*/
00825 /*        ::ip::ipToLayer2Multicast*/
00826 /* */
00827 /*  Purpose:*/
00828 /*         converts ipv4 address to a layer 2 multicast address*/
00829 /* */
00830 /*  Synopsis:*/
00831 /*        ipToLayer2Multicast <ipaddr>*/
00832 /* */
00833 /*  Arguments:*/
00834 /*         <ipaddr>*/
00835 /*             ipaddress in dotted form*/
00836 /* */
00837 /*  Return Values:*/
00838 /*         mac address in xx.xx.xx.xx.xx.xx form*/
00839 /* */
00840 /*  Description:*/
00841 /* */
00842 /*  Examples:*/
00843 /*         % ::ip::ipToLayer2Multicast 224.0.0.2*/
00844 /*         01.00.5e.00.00.02*/
00845 /*  Sample Input:*/
00846 /*         */
00847 /*  Sample Output:*/
00848 /*  Notes:*/
00849 /* */
00850 /*  See Also:*/
00851 /* */
00852 /*  End of Header*/
00853 
00854 ret  ::ip::ipToLayer2Multicast ( type ipaddr ) {
00855     regexp "\[0-9\]+\.(\[0-9\]+)\.(\[0-9\]+)\.(\[0-9\]+)" $ipaddr junk ip2 ip3 ip4
00856     #remove MSB of 2nd octet of IP address for mcast L2 addr
00857     set mac2 [expr {$ip2 & 127}]
00858     return [format "01.00.5e.%02x.%02x.%02x" $mac2 $ip3 $ip4]
00859 }
00860 
00861 
00862 /* Procedure Header*/
00863 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00864 /* */
00865 /*  Name:*/
00866 /*        ::ip::ipHostFromPrefix*/
00867 /* */
00868 /*  Purpose:*/
00869 /*         gives back a host address from a prefix*/
00870 /* */
00871 /*  Synopsis:*/
00872 /*        ::ip::ipHostFromPrefix <prefix> [-exclude <list of prefixes>]*/
00873 /* */
00874 /*  Arguments:*/
00875 /*         <prefix>*/
00876 /*             prefix is <ipaddr>/<masklen>*/
00877 /*         -exclude <list of prefixes>*/
00878 /*             list if ipprefixes that host should not be in*/
00879 /*  Return Values:*/
00880 /*         ip address */
00881 /* */
00882 /*  Description:*/
00883 /* */
00884 /*  Examples:*/
00885 /*  %::ip::ipHostFromPrefix  1.1.1.5/24*/
00886 /*  1.1.1.1*/
00887 /* */
00888 /*  %::ip::ipHostFromPrefix  1.1.1.1/32*/
00889 /*  1.1.1.1*/
00890 /* */
00891 /* */
00892 /*  Sample Input:*/
00893 /*         */
00894 /*  Sample Output:*/
00895 /*  Notes:*/
00896 /* */
00897 /*  See Also:*/
00898 /* */
00899 /*  End of Header*/
00900 
00901 ret  ::ip::ipHostFromPrefix ( type prefix , type args ) {
00902     set mask [mask $prefix]
00903     set ipaddr [prefix $prefix]
00904     if {[llength $args]} {
00905     array set opts $args
00906     } else {
00907     if {$mask==32} {
00908         return $ipaddr
00909     } else {
00910         return [intToString [expr {[toHex $ipaddr] + 1} ]]
00911     }
00912     }
00913     set format {-ipv4}
00914     # if we got here, then options were set
00915     if {[info exists opts(-exclude)]} {
00916     #basic algo is:
00917     # 1. throw away prefixes that are less specific that $prefix
00918     # 2. of remaining pfx, throw away prefixes that do not overlap
00919     # 3. run reducetoAggregates on specific nets
00920     # 4. 
00921     
00922     # 1. convert to hex format
00923     set currHex [prefixToNative $prefix ]
00924     set exclHex [prefixToNative $opts(-exclude) ]
00925     # sort the prefixes by their mask, include the $prefix as a marker
00926     #  so we know from where to throw away prefixes
00927     set sortedPfx [lsort -integer -index 1 [concat [list $currHex]  $exclHex]]
00928     # throw away prefixes that are less specific than $prefix
00929     set specPfx [lrange $sortedPfx [expr {[lsearch -exact $sortedPfx $currHex] +1} ] end]
00930     
00931     #2. throw away non-overlapping prefixes
00932     set specPfx [isOverlapNative -all -inline \
00933              [lindex $currHex 0 ] \
00934              [lindex $currHex 1 ] \
00935              $specPfx ]
00936     #3. run reduce aggregates 
00937     set specPfx [reduceToAggregates $specPfx]
00938 
00939     #4 now have to pick an address that overlaps with $currHex but not with
00940     #   $specPfx
00941     # 4.1 find the largest prefix w/ most specific mask and go to the next net
00942     
00943 
00944     # current ats tcl does not allow this in one command, so 
00945     #  for now just going to grab the last prefix (list is already sorted)
00946     set sPfx [lindex $specPfx end]
00947     set startPfx $sPfx
00948     # add currHex to specPfx
00949     set oChkPfx [concat $specPfx [list $currHex]]
00950 
00951 
00952     set notcomplete 1
00953     set overflow 0
00954     while {$notcomplete} {
00955         #::ipMore::log::debug "doing nextnet on $sPfx"
00956         set nextNet [nextNet [lindex $sPfx 0] [lindex $sPfx 1]]
00957         #::ipMore::log::debug "trying $nextNet"
00958         if {$overflow && ($nextNet > $startPfx)} {
00959         #we've gone thru the entire net and didn't find anything.
00960         return -code error [msgcat::mc "ip host could not be found in %s" $prefix]
00961         break
00962         }
00963         set oPfx [isOverlapNative -all -inline \
00964               $nextNet -1 \
00965               $oChkPfx
00966              ]
00967         switch -exact [llength $oPfx] {
00968         0 {
00969             # no overlap at all. meaning we have gone beyond the bounds of
00970             # $currHex. need to overlap and try again
00971             #::ipMore::log::debug {ipHostFromPrefix: overlap done}
00972             set overflow 1
00973         }
00974         1 {
00975             #we've found what we're looking for. pick this address and exit
00976             return [intToString $nextNet]
00977         }
00978         default {
00979             # 2 or more overlaps, need to increment again
00980             set sPfx [lindex $oPfx 0]
00981         }
00982         }
00983     }
00984     }
00985 }
00986 
00987 
00988 /* Procedure Header*/
00989 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
00990 /* */
00991 /*  Name:*/
00992 /*        ::ip::reduceToAggregates*/
00993 /* */
00994 /*  Purpose:*/
00995 /*         finds nets that overlap and filters out the more specifc nets*/
00996 /* */
00997 /*  Synopsis:*/
00998 /*        ::ip::reduceToAggregates <prefixList>*/
00999 /* */
01000 /*  Arguments:*/
01001 /*         <prefixList>*/
01002 /*             prefixList a list in the from of*/
01003 /*             is <ipaddr>/<masklen> or native format*/
01004 /* */
01005 /*  Return Values:*/
01006 /*         non-overlapping ip prefixes*/
01007 /* */
01008 /*  Description:*/
01009 /* */
01010 /*  Examples:*/
01011 /* */
01012 /*   % ::ip::reduceToAggregates {1.1.1.0/24 1.1.0.0/8  2.1.1.0/24 1.1.1.1/32 }*/
01013 /*   1.0.0.0/8 2.1.1.0/24*/
01014 /* */
01015 /*  Sample Input:*/
01016 /*         */
01017 /*  Sample Output:*/
01018 /*  Notes:*/
01019 /* */
01020 /*  See Also:*/
01021 /* */
01022 /*  End of Header*/
01023 
01024 ret  ::ip::reduceToAggregates ( type prefixList ) {
01025     #find out format of $prefixeList
01026     set dotConv 0
01027     if {[llength [lindex $prefixList 0]]==1} {
01028     #format is dotted form convert all prefixes to native form
01029     set prefixList [ip::prefixToNative $prefixList]
01030     set dotConv 1
01031     }
01032     
01033     set nonOverLapping $prefixList
01034     while {1==1} {
01035     set overlapFound 0
01036     set remaining $nonOverLapping
01037     set nonOverLapping {}
01038     while {[llength $remaining]} {
01039         set current [lvarpop remaining]
01040         set overLap [ip::isOverlapNative [lindex $current 0] [lindex $current 1] $remaining]
01041         if {$overLap} {
01042         #there was a overlap find out which prefix has a the smaller mask, and keep that one
01043         if {[lindex $current 1] > [lindex [lindex $remaining [expr {$overLap -1}]] 1]} {
01044             #current has more restrictive mask, throw that prefix away
01045             # keep other prefix
01046             lappend nonOverLapping [lindex $remaining [expr {$overLap -1}]]
01047         } else {
01048             lappend nonOverLapping $current
01049         }
01050         lvarpop remaining [expr {$overLap -1}]
01051         set overlapFound 1
01052         } else {
01053         #no overlap, keep all prefixes, don't touch the stuff in 
01054         # remaining, it is needed for other overlap checking
01055         lappend nonOverLapping $current
01056         }
01057     }
01058     if {$overlapFound==0} {break}
01059     }
01060     if {$dotConv} {return [nativeToPrefix $nonOverLapping]}
01061     return $nonOverLapping
01062 }
01063 
01064 /* Procedure Header*/
01065 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
01066 /* */
01067 /*  Name:*/
01068 /*        ::ip::longestPrefixMatch*/
01069 /* */
01070 /*  Purpose:*/
01071 /*         given host IP finds longest prefix match from set of prefixes*/
01072 /* */
01073 /*  Synopsis:*/
01074 /*        ::ip::longestPrefixMatch <ipaddr> <prefixList> [-ipv4]*/
01075 /* */
01076 /*  Arguments:*/
01077 /*         <prefixList>*/
01078 /*             is list of <ipaddr> in native or dotted form*/
01079 /*         <ipaddr>*/
01080 /*             ip address in <ipprefix> format, dotted form, or integer form*/
01081 /*         -ipv4*/
01082 /*             the provided integer format addresses are in ipv4 format (default)*/
01083 /* */
01084 /*  Return Values:*/
01085 /*         <ipprefix> that is the most specific match to <ipaddr>*/
01086 /* */
01087 /*  Description:*/
01088 /* */
01089 /*  Examples:*/
01090 /*         % ::ip::longestPrefixMatch 1.1.1.1 {1.1.1.0/24 1.0.0.0/8  2.1.1.0/24 1.1.1.0/28 }*/
01091 /*         1.1.1.0/28*/
01092 /* */
01093 /*  Sample Input:*/
01094 /*         */
01095 /*  Sample Output:*/
01096 /*  Notes:*/
01097 /* */
01098 /*  See Also:*/
01099 /* */
01100 /*  End of Header*/
01101 
01102 ret  ::ip::longestPrefixMatch ( type ipaddr , type prefixList , type args) {
01103     set ipv4 1
01104     while {[llength $args]} {
01105     switch -- [lindex $args 0] {
01106         -ipv4 {set args [lrange $args 1 end]}
01107         default {
01108         return -code error [msgcat::mc "option %s not supported" [lindex $args 0]]
01109         }
01110     }
01111     }
01112     #find out format of prefixes
01113     set dotConv 0
01114     if {[llength [lindex $prefixList 0]]==1} {
01115     #format is dotted form convert all prefixes to native form
01116     set prefixList [ip::prefixToNative $prefixList]
01117     set dotConv 1
01118     }
01119     #sort so that most specific prefix is in the front
01120     if {[llength [lindex [lindex $prefixList 0] 1]]} {
01121     set prefixList [lsort -decreasing -integer -index 1 $prefixList]
01122     } else {
01123     set prefixList [list $prefixList]
01124     }
01125     if {![string is integer -strict $ipaddr]} {
01126     set ipaddr [prefixToNative $ipaddr]
01127     }
01128     set best [ip::isOverlapNative -inline \
01129           [lindex $ipaddr 0] [lindex $ipaddr 1] $prefixList]
01130     if {$dotConv && [llength $best]} {
01131     return [nativeToPrefix $best]
01132     }
01133     return $best
01134 }
01135 
01136 /* Procedure Header*/
01137 /*  Copyright (c) 2004 Cisco Systems, Inc.*/
01138 /* */
01139 /*  Name:*/
01140 /*        ::ip::cmpDotIP*/
01141 /* */
01142 /*  Purpose:*/
01143 /*         helper function for dotted ip address for use in lsort*/
01144 /* */
01145 /*  Synopsis:*/
01146 /*        ::ip::cmpDotIP <ipaddr1> <ipaddr2>*/
01147 /* */
01148 /*  Arguments:*/
01149 /*         <ipaddr1> <ipaddr2>*/
01150 /*             prefix is in dotted ip address format*/
01151 /* */
01152 /*  Return Values:*/
01153 /*         -1 if ipaddr1 is less that ipaddr2*/
01154 /*          1 if ipaddr1 is more that ipaddr2*/
01155 /*          0 if ipaddr1 and ipaddr2 are equal*/
01156 /* */
01157 /*  Description:*/
01158 /* */
01159 /*  Examples:*/
01160 /*         % lsort -command ip::cmpDotIP {1.0.0.0 2.2.0.0 128.0.0.0 3.3.3.3}*/
01161 /*         1.0.0.0 2.2.0.0 3.3.3.3 128.0.0.0*/
01162 /* */
01163 /*  Sample Input:*/
01164 /*         */
01165 /*  Sample Output:*/
01166 /*  Notes:*/
01167 /* */
01168 /*  See Also:*/
01169 /* */
01170 /*  End of Header*/
01171 /*             ip address in <ipprefix> format, dotted form, or integer form*/
01172 
01173 if {![package vsatisfies [package provide Tcl] 8.4]} {
01174     /*  8.3+*/
01175     ret  ip::cmpDotIP (type ipaddr1 , type ipaddr2) {
01176     # convert dotted to list of integers
01177     set ipaddr1 [split $ipaddr1 .]
01178     set ipaddr2 [split $ipaddr2 .]
01179     foreach a $ipaddr1 b $ipaddr2 {
01180         #ipMore::log::debug "$ipInt1 $ipInt2"
01181         if { $a < $b}  {
01182         return -1
01183         } elseif {$a >$b} {
01184         return 1
01185         }
01186     }
01187     return 0
01188     }
01189 } else {
01190     /*  8.4+*/
01191     ret  ip::cmpDotIP (type ipaddr1 , type ipaddr2) {
01192     # convert dotted to decimal
01193     set ipInt1 [::ip::toHex $ipaddr1]
01194     set ipInt2 [::ip::toHex $ipaddr2]
01195     #ipMore::log::debug "$ipInt1 $ipInt2"
01196     if { $ipInt1 < $ipInt2}  {
01197         return -1
01198     } elseif {$ipInt1 >$ipInt2 } {
01199         return 1
01200     } else {
01201         return 0
01202     }
01203     }
01204 }
01205 
01206 /*  Populate the array "maskLenToDotted" for fast lookups of mask to*/
01207 /*  dotted form.*/
01208 
01209 namespace ::ip {
01210     variable maskLenToDotted
01211     variable x
01212 
01213     for { x =  0} {$x <33} {incr x} {
01214      maskLenToDotted = ($x) [intToString [maskToInt $x]]
01215     }
01216     un x = 
01217 }
01218 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1