diff options
author | Eugene M. Kim <astralblue@gmail.com> | 2017-10-09 04:10:49 -0700 |
---|---|---|
committer | Ilya Etingof <etingof@gmail.com> | 2017-10-09 13:10:49 +0200 |
commit | 1d5af2afc0b79fd7ed5b7ea9e564932c9adfdaac (patch) | |
tree | 840a8ce658f8d1ae17234470f93b4f086262f48e | |
parent | c383f2de5bbdbbd64f880726d7f9a6a55855c82a (diff) | |
download | pysnmp-git-1d5af2afc0b79fd7ed5b7ea9e564932c9adfdaac.tar.gz |
Render NetworkAddress indices (#87)
* Add OID-index roundtrip methods to NetworkAddress
This enables use of NetworkAddress as a table index.
* Use NetworkAddress for RFC1213-MIB::atNetAddress
Previously atNetAddress defined to be an IpAddress, whose table index
mapping was different from that of NetworkAddress. This prevented
proper use of RFC1213-MIB::atTable instances, because:
- OID-to-symbol resolution was failing;
- Symbol-to-OID mapping result was invalid.
* Move clone() from Choice to NetworkAddress
Previously it was implemented in pyasn1.type.univ.Choice in case there
may be more Choice-based types—such as NetworkAddress—used as a table
index. However, SMIv2 (RFC 2578) limits the SYNTAX of an OBJECT-TYPE to
be only PyASN1 “simple” types, and NetworkAddress is the only known
Choice-based type used as a table index in MIB-I, so there is little
reason to clutter PyASN1 with the one-off logic in anticipation of
something will probably never happen.
Having NetworkAddress's own clone() method also allows use of string
literals as the value, so the following invocations are all valid:
na = NetworkAddress()
na1234 = na.clone('1.2.3.4')
na1234_2 = na1234.clone()
na1234_3 = na.clone(na1234)
na4321 = na.clone(IpAddress('4.3.2.1'))
To elaborate on simple types, SMIv2 limits the object syntax to be:
- a base type (or its refinement)
- a textual convention (or its refinement); or
- a BITS pseudo-type.
All base types descend from ASN.1 integer, octet string, or OID, all of
which are simple types. PySNMP defines SMIv2 BITS as a subclass of
OctetString, which is again a simple type. Finally, a SMIv2 textual
convention (RFC 2579) is simply a syntactic sugar applied on top of
either a base type a BITS type, so it is a simple type.
-rw-r--r-- | pysnmp/proto/rfc1155.py | 51 | ||||
-rw-r--r-- | pysnmp/smi/mibs/RFC1213-MIB.py | 3 |
2 files changed, 53 insertions, 1 deletions
diff --git a/pysnmp/proto/rfc1155.py b/pysnmp/proto/rfc1155.py index fb7e76ae..35f6110b 100644 --- a/pysnmp/proto/rfc1155.py +++ b/pysnmp/proto/rfc1155.py @@ -51,6 +51,57 @@ class NetworkAddress(univ.Choice): namedtype.NamedType('internet', IpAddress()) ) + def clone(self, value=univ.noValue, **kwargs): + """Clone this instance. + + If *value* is specified, use its tag as the component type selector, + and itself as the component value. + + :param value: (Optional) the component value. + :type value: :py:obj:`pyasn1.type.base.Asn1ItemBase` + :return: the cloned instance. + :rtype: :py:obj:`pysnmp.proto.rfc1155.NetworkAddress` + :raise: :py:obj:`pysnmp.smi.error.SmiError`: + if the type of *value* is not allowed for this Choice instance. + """ + cloned = univ.Choice.clone(self, **kwargs) + if value is not univ.noValue: + # IpAddress is the only supported type, perhaps forever because + # this is SNMPv1. + if not isinstance(value, IpAddress): + value = IpAddress(value) + try: + tagSet = value.tagSet + except AttributeError: + raise PyAsn1Error('component value %r has no tag set' % (value,)) + cloned.setComponentByType(tagSet, value) + return cloned + + # RFC 1212, section 4.1.6: + # + # "(5) NetworkAddress-valued: `n+1' sub-identifiers, where `n' + # depends on the kind of address being encoded (the first + # sub-identifier indicates the kind of address, value 1 + # indicates an IpAddress);" + + def cloneFromName(self, value, impliedFlag, parentRow, parentIndices): + kind = value[0] + clone = self.clone() + if kind == 1: + clone['internet'] = tuple(value[1:5]) + return clone, value[5:] + else: + raise SmiError('unknown NetworkAddress type %r' % (kind,)) + + def cloneAsName(self, impliedFlag, parentRow, parentIndices): + kind = self.getName() + component = self.getComponent() + if kind == 'internet': + return (1,) + tuple(component.asNumbers()) + else: + raise SmiError('unknown NetworkAddress type %r' % (kind,)) + + class Gauge(univ.Integer): tagSet = univ.Integer.tagSet.tagImplicitly( diff --git a/pysnmp/smi/mibs/RFC1213-MIB.py b/pysnmp/smi/mibs/RFC1213-MIB.py index 5dc0d0e2..b0fda664 100644 --- a/pysnmp/smi/mibs/RFC1213-MIB.py +++ b/pysnmp/smi/mibs/RFC1213-MIB.py @@ -19,6 +19,7 @@ SingleValueConstraint, ConstraintsIntersection, ValueSizeConstraint, Constraints ModuleCompliance, NotificationGroup = mibBuilder.importSymbols("SNMPv2-CONF", "ModuleCompliance", "NotificationGroup") IpAddress, TimeTicks, NotificationType, ModuleIdentity, Integer32, Counter32, MibIdentifier, ObjectIdentity, Gauge32, Unsigned32, mgmt, MibScalar, MibTable, MibTableRow, MibTableColumn, Bits, iso, Counter64, mib_2 = mibBuilder.importSymbols("SNMPv2-SMI", "IpAddress", "TimeTicks", "NotificationType", "ModuleIdentity", "Integer32", "Counter32", "MibIdentifier", "ObjectIdentity", "Gauge32", "Unsigned32", "mgmt", "MibScalar", "MibTable", "MibTableRow", "MibTableColumn", "Bits", "iso", "Counter64","mib-2") DisplayString, PhysAddress = mibBuilder.importSymbols("SNMPv2-TC", "DisplayString", "PhysAddress") +from pysnmp.proto.rfc1155 import NetworkAddress at = MibIdentifier((1, 3, 6, 1, 2, 1, 3)) ip = MibIdentifier((1, 3, 6, 1, 2, 1, 4)) @@ -35,7 +36,7 @@ if mibBuilder.loadTexts: atIfIndex.setDescription("The interface on which this e atPhysAddress = MibTableColumn((1, 3, 6, 1, 2, 1, 3, 1, 1, 2), PhysAddress()).setMaxAccess("readwrite") if mibBuilder.loadTexts: atPhysAddress.setStatus('deprecated') if mibBuilder.loadTexts: atPhysAddress.setDescription("The media-dependent `physical' address. Setting this object to a null string (one of zero length) has the effect of invaliding the corresponding entry in the atTable object. That is, it effectively dissasociates the interface identified with said entry from the mapping identified with said entry. It is an implementation-specific matter as to whether the agent removes an invalidated entry from the table. Accordingly, management stations must be prepared to receive tabular information from agents that corresponds to entries not currently in use. Proper interpretation of such entries requires examination of the relevant atPhysAddress object.") -atNetAddress = MibTableColumn((1, 3, 6, 1, 2, 1, 3, 1, 1, 3), IpAddress()).setMaxAccess("readwrite") +atNetAddress = MibTableColumn((1, 3, 6, 1, 2, 1, 3, 1, 1, 3), NetworkAddress()).setMaxAccess("readwrite") if mibBuilder.loadTexts: atNetAddress.setStatus('deprecated') if mibBuilder.loadTexts: atNetAddress.setDescription("The NetworkAddress (e.g., the IP address) corresponding to the media-dependent `physical' address.") ipForwarding = MibScalar((1, 3, 6, 1, 2, 1, 4, 1), Integer32().subtype(subtypeSpec=ConstraintsUnion(SingleValueConstraint(1, 2))).clone(namedValues=NamedValues(("forwarding", 1), ("not-forwarding", 2)))).setMaxAccess("readwrite") |