[RFC PATCH 00/20] Context typed filters

Asbjørn Sloth Tønnesen ast at 2e8.dk
Thu Jan 9 00:38:37 CET 2020


Hi Ondrej,

Thanks for the feedback.

On 1/6/20 3:16 AM, Ondrej Zajicek wrote:
> Thanks for the patchset, sorry for not giving feedback sooner, was on
> vacation.

No problem, I was expecting that. I am also first responding now, since I
have been under the weather for the past few days.


> If i understand it correctly, the main point of this patchset is to
> introduce 'typed symbols', which have multiple values based of network
> type of processed route.

Correct. The patches allows for explicitly typed constants, filters and
functions. If a filter or function uses a typed symbol, it will implicitly
be typed itself. Once the context is know that version of the filter will
be generated.


> I must say that i do not like the approach taken in the patch, seems to
> me that for intended purpose it is too intrusive change and the feature
> is too idiosyncratic - i don't recall any language where a constant may
> represent multiple unrelated values based on context.

I agree that the patch set is a little intrusive, but I decided that it
was good enough for a PoC and to get the discussion started, hence
labeling it as an RFC patch.


In bird 1 it was possible to have bird4.conf and bird6.conf share common
configuration files, but have 2 different files defining symbols.

In bird 2 this ends out with a lot of symbols ending in "4" or "6",
and quite a few case statements or to do address family specific processing.
The case statements could be hidden behind a case-function per data type.

function get_typed_pfx_set(prefix set v4; prefix set v6)
{
         case net.type {
                 NET_IP4: return v4;
                 NET_IP6: return v6;
         }
}

Even this leads to long lines like: get_typed_pfx_set(AS65000_prefixes4, AS65000_prefixes6),
including the need to pass both prefix sets, through generic filtering functions.
Overall leading to an idiosyncratic config.

I would hope that people would only use this feature to store related values,
however I have only enforced that they must have the same data type.


> It is also over-specific (dispatch hardcoded for net_type, while there
> are other, context-specific properties, like protocol type).
I made the syntax and symbol part very net_type specific, since I'm not aware
of other context parameters where it would make a lot of sense.

I specifically choose not allow a fallback value, ie. calling cf_error
if a symbol is not defined for a given net_type.

With protocol typing I see it as more useful for protocol specific
overrides, so maybe a fallback value should be allowed?

Does anybody else have any feedback on this?


> One way to make it less intrusive would be to keep symbol table the same
> (just symbol->value mapping) and do the change just in 'value' part.
I don't have a problem with converting it to a linked list of versions of the symbol.


> You have this example:
> 
> define default_route:ipv4 = 0.0.0.0/0;
> define default_route:ipv6 = ::/0;
> 
> This could be done by using function instead of constant:
> 
> function default_route()
> {
>    case net.type
>    {
>      NET_IP4: return 0.0.0.0/0;
>      NET_IP6: return ::/0;
>    }
> }
 >
> I agree that it is more cumbersome than your version.

I used default route mostly as an easy to understand example, the big
benefit comes with prefix filtering hence the reference to bgpfilterguide.


> Seems to me that your intended objective could be achieved, while keeping
> it universal and reasonable, by several independent changes:
> 
> 1) Allow 'lazy-evaluated constants', that could depend on context. These
> are essentially zero-argument functions in disguise.
 >
> 2) Allow something like if/case expressions (instead of just statements).
> 
> 3) (optional) partially-evaluate/adapt filters based on context.

When we originally discussed this idea during RIPE78 in Reykjavik, we also
talked about that it should be possible to optimize it parse time.

Therefore I wanted to explore the feasibility of doing that, the shortcut
I took here, by only having a thin adaptation layer, is that I had to mark
it as never constant. That could be fixed by moving most of the linearization
work to the adaptation state, leaving only a loop check the current
linearization stage.

The benefit of doing the adaptation at parse time, means that non-existent
variants of a symbol can be revealed before a new config is loaded.

The redundant case statements during run-time is not an issue for us,
but I imagine it could be to some of the route server operators.


> So one could wrote something like:
> 
> define default_route = case net.type {
>    NET_IP4: 0.0.0.0/0;
>    NET_IP6: ::/0;
> }
This syntax could work, but should just result in the entries being put in
a linked-list under the symbol, so that it can be guaranteed that they all have
the same type.

I prefer to be able to define constants as several individual statements.

If constants can be defined for other parameters than net_type, should then
also be possible to do it multi-dimensional? Fx. for ipv4 in protocol x.


> (The remaining wart is a current style of enum constants, like 'NET_IP4'.)

I'm aware that net.type uses the C constants, but I choose to use `net_type`,
since it is consistent with table and channel type definitions.


-- 
Best regards
Asbjørn Sloth Tønnesen


More information about the Bird-users mailing list