Overview | Index by: file name | procedure name | procedure call | annotation
lldp-1.0.tm (annotations | original source)

#
#    Copyright (C) 2010 Alexandros Stergiakis <alsterg@gmail.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

#//#
# The "lldp" module enable layer2 network discovery via the [https://trac.luffy.cx/lldpd/ lldpd] package.
#
# Supported protocols:
# * LLDP (Link Layer Discovery Protocol)
# * CDP (Cisco Discovery Protocol)
# * FDP (Foundry Discovery Protocol)
# * SONMP (Nortel Discovery Protocol)
# * EDP (Extreme Discovery Protocol)
#
# @assume lldpd is compiled with: --with-privsep-user=_drop --with-privsep-group=_drop --with-privsep-chroot=/var/log/lldpd
#//#

module require base 1.0
module provide lldp 1.0

namespace eval ::module::lldp {
namespace import ::helper::* ::module::api::*

proc description {} {
    return "Layer 2 Network Discovery"
}

proc version {} {
    return "lldpd Version 0.4.0. Supported protocols: LLDP CDP FDP EDP SONMP"
}

proc check {} {
    if {[lempty [auto_execok lldpd]]} {
        error "lldpd is not installed"
    }
    if {[lempty [auto_execok lldpctl]]} {
        error "lldpctl is not installed"
    }
}

proc update_lldpd {} {
    variable lldpd_run
    variable lldpd_protocols
    variable lldpd_vlan
    variable lldpd_class
    
    killall lldpd
    
    if {$lldpd_run} {
        set params {}
        foreach p $lldpd_protocols {
            switch -exact -- $p {
                "cdp" { append params "-c "}
                "fdp" { append params "-f "}
                "edp" { append params "-e "}
                "sonmp" { append params "-s "}
                default { error "Unrecognized network discovery protocol: $p" }
            }
        }
        
        if {$lldpd_vlan} {
            append params "-v "
        }
        
        if {$lldpd_class} {
            append params "-M $lldpd_class "
        }
        
        exec lldpd {*}$params
    }    
}

proc reset {} {
    variable lldpd_run 0
    variable lldpd_protocols {}
    variable lldpd_vlan 0
    variable lldpd_class 0
    
    update_lldpd
}

proc constructor {} {
    log::Info "Loading \"lldp\" module: [description]"
    
    check

    Global USER USER_GROUP
    
    # The following paths are embedded in lldpd, that is why we don't use VAR_DIR.
    file mkdir [file join / var log lldpd]
    file attributes [file join / var log lldpd] -owner $USER -group $USER_GROUP
    file delete -force -- [file join / var run lldpd.socket]
    
    variable Classes [list endpoint1 endpoint2 endpoint3 network]
    
    reset

    # Finally load Command Specs
    sysconf loadspecs "modules/lldp/lldp.specs"
}

proc destructor {} {
    # First unload Command Specs
    sysconf remove "lldp"
    
    reset ;# will terminate daemon.
}

################
# Handlers
################

command LldpRun {cmdline argstart sid out no arguments args} {
    variable lldpd_run
    OnError Critical
    
    if {$no} {
        set lldpd_run 0
    } else {
        set lldpd_run 1
    }
    update_lldpd
}

proc print_LldpRun {} {
    variable lldpd_run
    if {$lldpd_run} {
        return "lldp run\n"
    }
    return
}

command LldpProtocols {cmdline argstart sid out no arguments args} {
    variable lldpd_protocols
    
    set protos [getall PROTOCOL]
        
    if {$no} {
        foreach p $protos {
            if {$p in $lldpd_protocols} {
                lremove lldpd_protocols $p
            }
        }
    } else {
        set lldpd_protocols $protos
    }    
    update_lldpd
}

proc print_LldpProtocols {} {
    variable lldpd_protocols
    
    if {! [lempty $lldpd_protocols]} {
        return "lldp protocols $lldpd_protocols\n"
    }
    return
}

command LldpVlan {cmdline argstart sid out no arguments args} {
    variable lldpd_vlan
    
    if {$no} {
        set lldpd_vlan 0
    } else {
        set lldpd_vlan 1
    }
    update_lldpd
}

proc print_LldpVlan {} {
    variable lldpd_vlan
    
    if {$lldpd_vlan} {
        return "lldp vlan\n"
    }
    return
}

proc class2num {class} {
    variable Classes
    set result [lsearch -exact $Classes $class]
    if {$result == -1} {
        error "unrecognized severity level \"$class\""
    }
    incr result
    return $result
}

proc num2class {num} {
    variable Classes
    if {! (1 <= $num <= 4)} {
        error "class number out of bounds"
    }
    return [lindex $Classes $num-1]
}

command LldpClass {cmdline argstart sid out no arguments args} {
    variable lldpd_class
    
    if {$no} {
        set lldpd_class 0
    } else {
        set class [dict get $arguments CLASS]
        set lldpd_class [class2num $class]
    }
    update_lldpd
}

proc print_LldpClass {} {
    variable lldpd_class
    
    if {$lldpd_class} {
        return "lldp class [num2class $lldpd_class]\n"
    }
    return
}

command ShowNeighbors {cmdline argstart sid out no arguments args} {
    variable lldpd_run
    
    if {! $lldpd_run} {
        return "Layer 2 Network Discovery is not enabled"
    }
    
    if {[dict exists $arguments detailed]} {
        exec lldpctl -d
    } else {
        exec lldpctl
    }
}

} ;# End of Namespace

Overview | Index by: file name | procedure name | procedure call | annotation
File generated 2010-03-13 at 22:28.