[DTrace-devel] [PATCH 1/3] Add support for the link_ntop() subroutine

Kris Van Hees kris.van.hees at oracle.com
Tue Dec 12 04:39:38 UTC 2023


On Mon, Dec 11, 2023 at 05:03:05PM -0500, Eugene Loh via DTrace-devel wrote:
> On 12/9/23 00:29, Kris Van Hees wrote:
> 
> > On Tue, Aug 29, 2023 at 09:54:31PM -0400, eugene.loh at oracle.com wrote:
> > > diff --git a/bpf/link_ntop.S b/bpf/link_ntop.S
> > > new file mode 100644
> > > @@ -0,0 +1,127 @@
> > > +#define ARPHRD_ETHER		1
> > > +#define ARPHRD_INFINIBAND	32
> > Maybe add that these coe from <linux/if_arp.h> ?
> 
> Maybe.  But that starts a cascade of other stuff that gets included.

I didn't say include linux/if_arp.h...  just mention that those constants are
taken from that include file (like you do for the following ones).

> In particular, if I understand correctly, we do not include /usr/include. 
> We include build/include, which has symlinks to various /usr/include/
> directories.  The cascade leads to adding directories sys/, gnu/, bits/,
> etc., as well as files features.h, stdc-predef.h, etc.  We cannot just turn
> build/include into a link to /usr/include since then we could not touch
> .dir.stamp.  So, since we do not actually include /usr/include, it feels to
> me like these two #define make some sense.  Much simpler.
> 
> > > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> > > @@ -6039,6 +6039,31 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> > >   	emit(dlp,  BPF_ALU64_IMM(BPF_ADD, dnp->dn_reg, tstring_offset));
> > >   }
> > > +/* Definitions from libdtrace/net.d or /usr/include/linux/if_arp.h. */
> > > +#define ARPHRD_ETHER         1
> > > +#define ARPHRD_INFINIBAND   32
> > Why not simply include <linux/if_arp.h> ?
> 
> Yeah, though mimicking what's done in the bpf .S file also makes sense, and
> there (per earlier discussion) including if_arp.h gets complicated.

I think including if_arp.h here makes more sense.

> > > +
> > > +static void
> > > +dt_cg_subr_link_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> > > +{
> > > +	dt_node_t	*type = dnp->dn_args;
> > > +	uint_t		Lokay = dt_irlist_label(dlp);
> > > +
> > > +	/* Determine type and check it is okay. */
> > > +	dt_cg_node(type, dlp, drp);
> > > +	emit(dlp,  BPF_BRANCH_IMM(BPF_JEQ, type->dn_reg, ARPHRD_INFINIBAND, Lokay));
> > > +	emit(dlp,  BPF_BRANCH_IMM(BPF_JEQ, type->dn_reg, ARPHRD_ETHER, Lokay));
> > > +	dt_cg_probe_error(yypcb, DTRACEFLT_ILLOP, DT_ISREG, type->dn_reg);
> > > +	emitl(dlp, Lokay,
> > > +		   BPF_NOP());
> > > +
> > > +	/* Move addr into dnp->dn_args so we can call dt_cg_subr_arg_to_tstring(). */
> > > +	dnp->dn_args = type->dn_list;
> > You probably should do this in a way that after the dt_cg_subr_arg_to_tstring()
> > call, you can restore the node structure.  I.e. dnp->dn_args = type.  That way,
> > depending on what type is, dt_node_free() will ensure proper cleanup is done
> > when dt_node_free( is done on dnp.
> 
> Okay.
> 
> > But worse, this causes the dt_cg_check_ptr_arg() in dt_cg_subr_arg_to_tstring()
> > to get bypassed (and thus err.link_ntopbadaddr.d fails) because you move the
> > 2nd argument into the 1st argument spot, and then dt_cg_subr_arg_to_tstring()
> > checks the type of the *1st* argument of link_type() according to its
> > prototype.  And since that is not a pointer, the check is never done.
> 
> I don't follow.  dt_cg_subr_arg_to_tstring() checks the type of its 1st arg,
> which is the 2nd arg to link_ntop().  E.g., for err.link_ntopbadaddr.d, it's
> a pointer.  So that 2nd link_ntop() arg *is* a pointer, we do in fact run
> dt_cg_check_ptr_arg(), the NULL pointer is rejected, and the test passes.

The type is checked based on what the prototype of link_ntop() provides, not
based on the type of the passed argument.  See dt_cg_subr_arg_to_tstring():

        isp = dnp->dn_ident->di_data;
        assert(isp && isp->dis_args);
        argtype = &isp->dis_args[0];

        /* handle the one "input value" */
        /* (its type matters only as to whether we check it is null */
        dt_cg_node(arg, dlp, drp);
        if (dt_node_is_pointer(argtype) || dt_node_is_string(argtype))
                dt_cg_check_ptr_arg(dlp, drp, arg, NULL);

So, in this case you pass the 2nd argument of link_ntop(), but the check is
done on the expected type of the first argument of link_ntop() which is an
integer.

> Is err.link_ntopbadaddr.d really failing?

Yes.

> > Rather than remapping the args (exchanging type and addr), I think you need
> > to keep them as they are, and do (assuming addr = dnp->dn_args):
> 
> How can we assume addr=dnp->dn_args?  The first arg of link_ntop() -- that
> is, dnp->dn_args -- is the type.

Sorry, my mistake.  But you know what I mean by addr - the actual HW address.

> > 	dt_cg_node(addr, dlp, drp);
> > 	dt_cg_check_ptr_arg(dlp, drp, addr, NULL);
> > 	dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_link_ntop", DT_ISREG, addr->dn_reg, DT_IGNOR, 0);
> > 
> > But then you do need to rework dt_link_ntop to accept type as the main argument
> > and addr as the extra argument.
> > 
> > > +
> > > +	dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_link_ntop", DT_ISREG, type->dn_reg);
> > > +	dt_regset_free(drp, type->dn_reg);
> > > +}
> 
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list