The Simple Network Management Protocol (SNMP) has, on the bottom, tagged values of types integer, octet string, object identifier, null and sequence. The oid's (object identifiers) are pointers into an agent's information database. For example, an object identifier could look like this: (:object-identifier ".1.3.6.1.2.1.1.1.0") This specific object identifier also has the name .iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0 . You can set or get this piece of data using the oid as a reference. On the wire the values are encoded with Basic Encoding Rules (BER). The oid above would be encoded like this: SNMP1> (ber-encode '(:object-identifier ".1.3.6.1.2.1.1.1.0")) => #(6 8 43 6 1 2 1 1 1 0) Basically, the encoding is a tag octet, a length octet, and an octet for each sub-identifier, with a few special cases. An integer would be coded like this: SNMP1> (ber-encode '(:integer 12345)) => #(2 2 48 57) Again a tag, a length and a number of octets representing the value. This also works the other way around: SNMP1> (ber-decode #(2 2 48 57)) => (:INTEGER 12345) When you need to encode a computed value, use backquote instead of quote, and use the comma operator to unquote. For example: SNMP1> (let ((request-id (random 1000))) (ber-encode `(:integer ,request-id))) => #(2 2 0 254) A null value is a tag and a length of zero: SNMP1> (ber-encode '(:null)) => #(5 0) We now put two of these values in a sequence. The effect is that two octets are prepended to the other encodings, a sequence tag and the length of the content of the sequence: SNMP1> (ber-encode '(:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null))) => #(48 12 6 8 43 6 1 2 1 1 1 0 5 0) This form, a sequence of an oid and a value, is in SNMP called a varbind (variable binding). The Protocol Transfer Unit (PDU) uses a sequence of these, so we wrap it in another sequence to get a list of varbinds: SNMP1> (ber-encode '(:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null)))) => #(48 14 48 12 6 8 43 6 1 2 1 1 1 0 5 0) This is a GET PDU constructed around the previous varbind list: (:get (:integer 12345) (:integer 0) (:integer 0) (:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null)))) The :get keyword is the same as :sequence, except it has its own tag. The first integer is the request id, whatever we put in there we get back in the response. To finish it up, we create an SNMP message, which is a sequence of version, community and the PDU. Version is 0 for version 1. The community is a kind of password. (:sequence (:integer 0) (:octet-string "public") (:get (:integer 12345) (:integer 0) (:integer 0) (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null)))) We encode the complete message, the result is of type (SIMPLE-ARRAY (UNSIGNED-BYTE 8)) SNMP1> (ber-encode '(:sequence (:integer 0) (:octet-string "public") (:get (:integer 12345) (:integer 0) (:integer 0) (:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null)))))) => #(48 39 2 1 0 4 6 112 117 98 108 105 99 160 26 2 2 48 57 2 1 0 2 1 0 48 14 48 12 6 8 43 6 1 2 1 1 1 0 5 0) Then we send this message to the agent. The udp-send-and-receive function is a wrapper around sbcl's socket library, the parameters are ip-adress, port, wait-between-retries, retry-count and then the buffer to send. SNMP1> (udp-send-and-receive #(127 0 0 1) 161 1 3 *) => #(48 124 2 1 0 4 6 112 117 98 108 105 99 162 111 2 2 48 57 2 1 0 2 1 0 48 99 48 97 6 8 43 6 1 2 1 1 1 0 4 85 76 105 110 117 120 32 98 114 101 97 100 32 50 46 54 46 49 53 45 50 55 45 97 109 100 54 52 45 103 101 110 101 114 105 99 32 35 49 32 83 77 80 32 80 82 69 69 77 80 84 32 70 114 105 32 68 101 99 32 56 32 49 55 58 53 48 58 53 52 32 85 84 67 32 50 48 48 54 32 120 56 54 95 54 52) The array above is the encoded response message from the agent. When we decode it we see that we have a :response PDU, where the :null in the varbind has been replaced with an octet string from the agent's information database: SNMP1> (ber-decode *) => (:SEQUENCE (:INTEGER 0) (:OCTET-STRING "public") (:RESPONSE (:INTEGER 12345) (:INTEGER 0) (:INTEGER 0) (:SEQUENCE (:SEQUENCE (:OBJECT-IDENTIFIER ".1.3.6.1.2.1.1.1.0") (:OCTET-STRING "Linux bread 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64"))))) We can also do SET, GETNEXT and TRAP PDUs. There is no conversion function between the symbolic representation and the dotted integer representation of object identifiers in this package, i.e. there is no mib-compiler. The encoding and decoding functions should work in all implementations. The udp-send-and-receive function will have to be coded again for implementations other than sbcl. As long as you have means to send and receive discrete udp packets, that should be easy. This is Free Software. The license is LLGPL.