[prev in list] [next in list] [prev in thread] [next in thread] 

List:       net-snmp-users
Subject:    Re: GET on a ReadWrite OID.
From:       wrb () wrbuckley ! com
Date:       2001-06-29 23:31:11
[Download RAW message or body]

On Thu, 28 June 2001, Dave Shield wrote:
> > Looking at the code produced by mib2c, we see that what is generated are
> > the following C functions:
> > 
> >       void init_softnerdDemos(void)  Which handles MIB and SubAgent
> >                                      registration
> 
> Which handles MIB registration (together with any other necessary
> initialisation, such as config handler registrations) - yes.
> 
> It's a bit misleading to talk about "subagent" registration, since the
> MIB module (typically) neither knows nor cares whether it's in the
> master agent or a subagent.

From my perspective, it is not misleading to refer to the process as
subagent registration. From my perspective, the MIB module is the text
of the MIB, not the code generated by mib2c.  The code generated by
mib2c is an implementation of the MIB; it is not the MIB.  What is
registered is the routine which is to be called to support a set of
OIDs, together with the OIDs themselves.  By registering the OIDs
and their servicing routine, we tell a Master agent how to service
OIDs.  From earlier discussions, the Master agent also registers
OIDs and corresponding servicing routines.  In any case, the process
of registration provides for coming to know a set of OIDs and the
routines which service GET and SET requests for those OIDs.

> But basically, yes.
> 
> >       var_softnerdDemos(...)         Which is the callback routine
> >                                      initiated by the Master Agent in
> >                                      servicing relevant OIDs contained
> >                                      in GET and SET PDU's
> 
> Yes.
> 
> More precisely, it's the *only* routine called for servicing GET PDU's
> This is the "GET handler" that I referred to.
> It's typically a single GET handler for a whole bunch of objects.
> 
> Although this is also called for a SET request, that's not really
> its intended purpose - the main reason that it is currently called,
> is because the MIB registration just has one routine per object.

I understand.  It is the pathway to servicing SET requests, not the
means of such service.

> Ideally (e.g. with the upcoming architecture), the MIB registration
> will probably include two calls for each agent, so the GET handler
> (i.e. var_softnerdDemos) will *ONLY* be called for GET requests,
> and *NOT* called for SET requests.

Both designs have their virtues.  Creating two function handles will
in general result in the having all OIDs represented twice in the
code, one for GET and one for SET.  Of course, the OID is represented
by means of a defined constant, such as that used in the switch
statement of the var_xxx function.

> That's not currently the case - but it may help to pretend that
> it is for the purposes of this discussion.
> 
> >       write_scalarReadWrite(...)     Which is called by the callback
> >                                      routine to service the one OID
> >                                      of the ExampleApp1_MIB having a
> >                                      MAX-ACCESS of read-write
> 
> Almost.
> 
> It's called by the callback routine to service SET requests (and *ONLY*
> SET requests) for the one OID......
> It's not called for a GET request on that object.
> 
> This is the "SET handler" that I referred to.
> 
> Note that a single GET handler is typically shared between multiple objects,
> while a SET handler (at least as output by mib2c) typically handles one
> object.
>   (I don't particularly like this approach, but what the heck)

Frankly, I do like this approach.  The one to one mapping of SET handler
and OID facilitates solution space partitioning.

> >       write_scalarOctetString(...)
> 
> Similarly.
> 
> > Note, there is no separate routine which addresses the lone OID having a
> > MAX-ACCESS of read-only.  All work related to this OID is performed in the
> > function:
> > 
> >       var_softnerdDemos(...) 
> 
> All work relating to *all* GET requests is handled by this routine.
> So yes - all work related to the read-only OID is indeed performed here,
> but that's because of the type of request received - not the access
> level defined in the MIB.

Clearly, there is a causal relationship between the access type and the
representation of an OID within the code produced by mib2c.  

>   A SET request for scalarReadOnly would end up trying to call the
> write_method hook set up for the (non-existant) 'write_scalarReadOnly',
> find this didn't exist, and so report an error.
>   (That's a slight simplification, but it's sort-of true)

Presumably, the value of the write_method pointer is initialised to zero,
and that testing for such value is the means to determine such existence.

> > I therefore conclude that by GET and SET handlers, you are referring to
> > the functions:
> > 
> >       var_softnerdDemos(...)        <--- GET handler
> >       write_scalarReadWrite(...)    <--- SET handler
> >       write_scalarOctetString(...)    <--- SET handler
> 
> > >But that doesn't mean that they are both invoked every time.
> > 
> > If I have correctly identified the handlers you write about, then
> > I must ask:
> > How can your ascertion be correct?
> 
> 'Cos that's what the code does :-)

At this point you should have guessed that you were being set-up.  My goal for
doing so is made clear later in this posting.

> >                                 Consider function var_softnerdDemos.  For
> > every call to this function where the vp->magic value is SCALARREADWRITE,
> > we have the setting of the parameter write_method (a handle by the way,
> > which is a pointer to a pointer, and in this case a handle to a function,
> > which is a pointer to a pointer to a function) to the function named:
> > 
> >       write_scalarReadWrite;
> 
> Yes - quite correct.
> 
> > Thus, by implication, this function is executed for every reference to
> > the corresponding OID.
> 
> No - that's where you're wrong.

Me thinks you complain too loudly.  I did say "by implication."

> This parameter is set up for every reference, yes.
> But the surrounding agent code can still choose whether or not to call it.
> That surrounding code knows whether or not this is a SET request, and
> hence whether it's necessary to try and call this write hook.
> 
> The handle_one_var() routine that I suggested you read essentially boils
> down to:
> 
>     handle_one_var( PDU_type, OID )
>     {
>         reg_entry = search_MIB_registry(  OID  );
>         // We now have the 'struct variable' entry for this OID
>         //    from the initialisation routine
> 
>         current_value = reg_entry->handler(  PDU_type, OID, &writehook );
>         // We now have the current value of this object,
>         //    and a handle to the SET handler if this is writeable
> 
>         if (( writehook != NULL ) &&
>             ( PDU_type  == SET  )) {
> 
>             // Only call the SET hendler if *both* this object
>             //   is writeable *AND* this is a SET request.
>             writehook( .... );
>         }
>     }
> 
> (The code's somewhat more complex than that - but this is the basic
>  flow of control.)
> 
> >                       Any failure of this function to occur is totally
> > outside of the scope of the var_softnerdDemos function.
> 
> Yes.
> 
> > As far as the var_softnerdDemons function is able to tell, the function
> > write_scalarReadWrite is executed for each and every reference to the
> > OID scalarReadWrite.
> 
> No.
> As far as the var_softnerdDemons function is able to tell, the function
> write_scalarReadWrite is *available* for each and every reference to the
> OID scalarReadWrite.   It may or may not be called - at the discretion
> of the main agent code.
> 
> That's what I meant by my correction of:
> > > Not quite.   It assumes that the intent is to be able to write a value. 
> > >                                            ^^^^^^^^^^
> 
> > To the best of my ability to tell, the only components of my sub Agent are
> > those four functions listed above,
> 
> The only components that are specific to this particular MIB - yes.
> 
> >                                  and of those, only three perform the core
> > operations of an agent.
> 
> Together with the common agent routines, yes.
> 
> >                        After all, these are the only things produced by
> > execution of mib2c, and so, simplistically, I as a programmer must conclude
> > that these four routines define in toto the components of my sub Agent.
> 
> Those four routines *plus the agent library* - yes.

From my perspective, the agent library is NOT part of my agent.  From your
perspective, it is otherwise.  Frankly, these are semantic issues.  Yet, the
perspective of the individual is important for the conveyance of knowledge.

> >                                                           It matters
> > not that other components of the sub Agent are contained within link
> > libraries.  After all, I have no idea what is contained within such link
> > libraries.
> 
> Correct.  As this has no influence on how you write your MIB handler, you
> can disregard how they work.
> 
> >            In fact, the link libraries might just as well be of zero size
> > for all I, as a programmer, care.
> 
> They can be of zero size as long as they do the right thing - yes.
> 
> As a MIB implementor, you can completely ignore the rest of the (sub)agent
> code, as long as you trust your routines to be called at the appropriate
> times.

In the words of Ken Thompson, as given in his 1984 Turing Award Lecture,
from a paper titled "On Trusting Trust," you can't trust.  Further, in the
words of Ronald Reagan regarding his Arms Control Talks with Mikhail Gorbachev,
Trust, but Verify.

I am the kind of person who acts only when I completely understand all the
attendant details.  If there is a single point of uncertainty, then I do
not act.  This means that not knowing some detail of operation of an element
of the Net-SNMP toolkit, then I will not use that element.

>   The thing about this discussion is that you're questioning whether
> this is happening.  So this means that you *do* need to consider how they
> work, in order to assure yourself that the MIB-specific bits (which
> are all you really need to worry about) *will* be called at the right
> times.
> 
> > My friend, your ascertion seems based upon faulty logic.
> 
> (And you wonder why we sometimes clash during our discussions! :-) )
> 
> It may be faulty to you - but that's how the code works.
> I've tried to guide you how things are organised, and explain this
> as best as I can.   You can either choose to believe me, or try
> to follow the actual code and point out where I'm wrong.

As a programmer, you are sure to be well aware of the immense time
that it takes to read and comprehend the intricate operation of code
produced by another programmer.  Few, if any, users of the Net-SNMP
toolkit will have the luxury of time.

>   I find it a little frustrating that you seem to be telling me
> that it can't possibly work this way - based apparently purely 
> on your assumptions of how this fits together, without looking
> at the code.

Not that it can't.  Just that I have no reason to assume such operation.
There is no documentation which provides Net-SNMP users with explication
of the conceptual design of Net-SNMP.  Frankly, given the state of the
documentation, it is solely upon the foundation of ASSUMPTION that anyone
expects the code to operate in a particular fashion.  This is the reason
for which I have pursued this discussion, and we will see shortly where
you answer my questions to the satisfaction of my need.

>   [ I probably ought to delete that last paragraph - it runs
> the risk of sparking another feud.  Suffice it to say that it's
> not meant to do so - just to indicate a certain level of frustration.
> I'll let it stand, and hope not to regret that decision. ]

Actually, I see no reason for regret, or another feud.

> >                                                       Since the content
> > of the code generated by mib2c sets the write_method function handle to
> > reference the SET handler (I surmise this, given your prior explanation),
> > it must be that the decision to perform a GET or SET service is determined
> > behind the scenes.
> 
> Yes!  Exactly!

On this point you replied NO in an earlier posting.  The corresponding clip:

     >>Well, not quite.  If behind the scenes the PDU type determination
     >>is made during the several calls to the routine write_scalarReadWrite
     >>so that during the state UNDO the current setting is returned,
     >>then I see how the value may be read. 
     > 
     >No - it doesn't work that way. 

I proposed a mechanism.  That was secondary to the issue, however.  Ths issue
was the source of decision.  The decision is not within my agent (my
perspective).  It is, instead, taken behind the scenes.

However, this is exactly what I needed to hear (read).  Moreover, this point
ought to be part of the documentation regarding subagent implementation.

> The MIB module writer doesn't need to make that decision.
> He/She simply provides a GET handler ('var_xxx') and a SET handler
> ('write_xxxObj1') - and lets the rest of the agent decide which to call when.
> 
> >                      I may well be mistaken as to the involvement of the
> > specified write_method function (that it takes part or not) but, certainly
> > it is the case that if such function is not called, then earlier, and still
> > behind the scenes of the code produced by mib2c, a decision is evaluated
> > regarding the nature of the PDU.
> 
> Exactly.
> 
> The agent calls the GET handler.
> Then, based on the results from that (write_method) and the type of PDU
> (asp->rw), the agent decides whether or not to call the SET handler.
> 
> >                                                        So, the var_xxx
> > function provides both the current value of the OID and the handle to the
> > write_method function for that OID.  Exercise of the write_method function
> > is addressed later, and outside the scope (behind the scenes) of the code
> > produced by the action of mib2c upon my application MIB.
> 
> Exactly.
> 
> > The most important point for me is that the indicated structure element,
> > 
> >              asp->rw
> > 
> > is not EVER expressed in the code produced by mib2c.
> 
> Correct.
> The only reason I mentioned it, was that you were expressing disbelief
> that the object handlers would be called at the correct time.   It's
> necessary to know about this to validate correct operation of the library.
> It's not necessary to know about this to *use* the library, if you're
> prepared to accept that it operates correctly.
> 
> >                                                     This is an immensely
> > important point to an implementer of an AgentX sub Agent.
> 
> I'm going to introduce another "subtle point of semantics" here.
> Mib2c is concerned with implementing a MIB module, not a sub-agent.
>                                        ^^^^^^^^^^

Subtle point 2:  mib2c produces implementation code for a MIB module,
                 which may be used to construct an agent, Master or sub.

> A MIB module implementor does not need to be concerned with *when* and
> *how* the individual bits (initialisation, GET, SET, etc) are invoked.
> Just what they need to do.  

This is never stated in the documentation.

> A sub-agent implementor *does* need to be concerned with this wider
> picture.   However, by linking the MIB module objects together with
> the sub-agent library, all this can be handled quite simply.

Again, this is never stated in the documentation.

> That's why the tutorials (neither AGENT.txt nor the AgentX sub-agent stuff)
> don't make explicit reference to asp->rw.   Neither the MIB module
> implementor, nor the sub-agent implementor actually need to be concerned
> with this.
>   From the MIB module writer's point of view, this is "too high a level"
> and is handled by "someone up there".
>   From the sub-agent implementor's point of view, this is "too low a level",
> and is handled by the library.
> 
>   It's only something that needs to be explicitly handled by someone
> implementing the middle layer - i.e. writing the agent library itself.
> Given that we will be providing that as part of the project, I'm not
> sure why we would need to include that as part of the front-line
> documentation.  It's only really relevant in the context of the internal
> design of the library.

So that one understands the concepts of operation.  Trust is a bad basis for
code design and agent implementation.

> > I do get a fair amount of instruction from your explication.  However, I
> > strongly believe that a more thorough tutorial is necessary for conveyance
> > of this information to other users.
> 
> One very important thing regarding documentation is precisely who it is
> aimed at.   If you are offering to write additional documentation (which
> I would warmly welcome - believe it or not!), I'd ask whether this is
> primarily aimed at someone wanting to *use* the library, or someone
> wanting to understand the inner workings of the library?   Both are worthy
> aims to cover, but I suspect that the amount of detail, and the sort
> of information needed will be different.
>   A "one-size-covers-all" approach is (IMO) a mistake.   I trust my
> ramblings above give you some indication as to why.
> 
> Dave

William R. Buckley



_______________________________________________
Net-snmp-users mailing list
Net-snmp-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/net-snmp-users

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic