Hi Florian,
On 6 November 2015 at 16:02, Florian Maury <florian.maury(a)ssi.gouv.fr> wrote:
Hi everyone,
While working on my Knot-Resolver (kr) module, I came to think that the
current YIELD mechanism for layers will not work properly, if multiple
YIELD-enabled modules are loaded simultaneously.
My understanding of how the current YIELD system works is as follows.
A layer receives the current state through ((knot_layer_t*) ctx)->state.
The current state can be modified by previous layers returned value.
When a layer returns a YIELD state, the chain of responsability,
maintained by the lib/resolve.c:ITERATE_LAYERS macro is broken (break;)
and the resolution plan is evaluated once more to handle the tail
element of the rplan.
Once the rplan popped up all rplan_pushed queries, then the query that
yielded is once more the last element of the rplan stack. This element
is then evaluated, calling once more all layers, starting with the
first layer. This time, the state that is provided to the layers is
YIELD, except if a layer returns another value instead of returning the
state as is.
It doesn't evaluate *once more all* layers, but only the layer that
yielded, and all that follow.
For example, if the server has following:
LAYERS = { Iterator, Rrcache, Validator, Stats }
RPLAN = { Q1 }
The I,R are executed, Validator for Q1 yields and pushes Q2, Stats is
not called.
It looks like this.
RPLAN = { Q2, Q1[yielded at V] }
All layers are evaluated for Q2, and it pops out.
RPLAN = { Q1[yielded at V] }
Driver calls Validator on Q1 again with state YIELD, it returns normal state,
the next one is Stats which receives its state and finishes the resolution.
A layer could behave differently, based on whether it
receives a YIELD
state or not as "input state". This is, in fact, what is provided as
example in the documentation:
>>
consume = function (state, req,
answer)
answer = kres.pkt_t(answer)
if state == kres.YIELD then
print('continuing yielded layer')
return kres.DONE
else
if answer:qtype() == kres.type.NS then
req = kres.request_t(req)
local qry = req:push(answer:qname(),
kres.type.SOA, kres.class.IN)
qry.flags = kres.query.AWAIT_CUT
print('planned SOA query, yielding')
return kres.YIELD
end
return state
end
end
<<<
The issue, I think, is that a module has no way of knowing whether it is
the one that yielded or not.
When it receives YIELD state, it is always the one which yielded.
Let's say I have three module, A, B, and C. B and
C can yield, and A
only returns YIELD, when it receives YIELD as input state.
That's a cycle, it will yield to itself until the iteration limit is
reached and resolution is terminated.
On the first evaluation, A and B returns DONE. C
yields. Then on the
second evaluation, A returns YIELD, because it does not handle this
state and only passes it along. B receives the YIELD from A. B, as said
You can't pass along YIELD state, when a layer returns it, the layer
walk is suspended.
It's like when you're making coffee and realize there is none left, so
you leave the coffee maker and hot water in the kitchen and go
buy some more. When you get back you have everything prepared, so you
just put in the coffee you bought and finish.
above, may yield in some cases. B will therefore
handle the YIELD, and
do his "YIELD" actions, ignoring the fact that the module that actually
yielded was C.
I suppose B and C could define flags to be capable of remembering
whether they yielded on this query or not. Unfortunately, there is
currently no framework to ensure uniqueness of these flags.
Sadly, this email does not come up with a proposed solution. I'm only
sharing a thought about what I think could be an issue.
What is your take on this? Have I missed something or misunderstood how
the yield state works?
Thank you.
Cheers,
Florian
There is one problem similar to this - if you want to push new query
and intercept it, there's no unique way to mark it as "this is an
answer to query I'm waiting for".
You can use query flags like in DNS64 [1], but I'd like to do better
than that in the future.
Cheers,
Marek
[1]:
https://github.com/CZ-NIC/knot-resolver/blob/master/modules/dns64/dns64.lua…
_______________________________________________
knot-dns-users mailing list
knot-dns-users(a)lists.nic.cz
https://lists.nic.cz/cgi-bin/mailman/listinfo/knot-dns-users