That's precisely the point. You can specify part of the routing table at compile/configure time - the rest gets generated at runtime.
The data/control plane distinction is conceptual. It doesn't hold in memory when the router is handling its own network traffic - it has a single routing table/world-view.
My own routing table is shared by the data plane AND control plane.
At some point you will receive an external data (routing update) which requires runtime validation, you will do reflection and update your own routing table (ring 0 address space) based on external events.
>The RIB is not going to have a schema like that which changes at runtime.
The schema need not change. The entries/relations between objects changing is sufficient to violate type-safety.
Route add( *str1, *str2) to Number.add().
It's not clear to me if you are suggesting that a dynamic routing table with different kinds of routes cannot be implemented in a type-safe manner in a statically typed language, or if you're working with an analogy where a routing table is like a dynamic programming language at runtime, in that a static set of entities and relations are known ahead of time and those are modified by runtime input. If it's the latter I'm not really sure how the analogy works—if programming languages are to routers as types are to routing entries, what in a router is analogous to a value of a given type?
I can speak more to the former possibility; here's a rough sketch of how one could implement a routing table using the tools available in a statically typed environment (and in a type-safe way). One way to do it (I believe the common way, and certainly the only one I've seen in commercial router implementations) is to treat statically populated and dynamically learned routes more or less uniformly in the data structures used to perform data-plane lookups. Each such route entry has the same fields and gets inserted into a data structure with a predefined shape. Where special behavior is needed for routes of different kinds, that behavior can be implemented by using dynamic dispatch in the sense it's usually used in C++, Java, Rust, etc. to call a method associated with a route entry, or using other techniques common to statically compiled languages—there is a fixed set of such operations defined up front. Adding and removing entries from the routing table at runtime does not typically implicate type safety because the types used to describe the table describe all of its possible valid states. For instance, the type for a node in a radix trie might describe how it can either be leaf node or contain subnodes, etc.
> The schema need not change. The entries/relations between objects changing is sufficient to violate type-safety. > > Route add( str1, str2) to Number.add().
It's obviously not always true that entries or relations changing will validate type safety; any non-trivial system will let you perform some kinds of data manipulation at runtime. Conventional static type systems will allow some kinds of mutations (like changing around pointers in a radix trie to insert a new node) but will not have the flexibility to support some others (like changing the shape of a dispatch table at runtime).
One kind of call pattern which is incompatible with statically compiled dynamic dispatch is where the types of parameters change along with the base type which owns the dispatch table; I think this is what your add() example is getting at—you need the type of the second parameter to match the first, which you can't validate without runtime checks if you don't know what concrete implementations will be in use at runtime. In the case of a routing table I don't think this kind of polymorphism is needed though; I can't think of an instance where an operation would fundamentally require a fixed relation in the concrete types of different routes. For instance, when routes overlap you can derive a priority value for each one to decide which one to use, rather than directly implementing some kind of function whichIsBetter(a, b) which relies on knowing what concrete route kinds a and b are.
How? A routing function is precisely a M:N mapping with untyped input.
It's just some data somebody sent you! Route it.
Unless you can infer more about the meaning of those bits the only strategies possible are static(M), round-robin(M) or random(M).
Programming is about explaining desires to computers. It is a complex, error-prone activity and we depend on our automated tooling to save us from ourselves.
Obviously, in theory you can build the exact same software in Assembly as you can with Java. But not in practice because the programming language is a human-computer interface and a symbiosis with useful feedback loops emerges at higher levels of abstraction.
The design choices of your language impose certain limits/discipline on your expressive power.
Some design patterns become easy to express; where others become difficult to express and your paradigm’s features become obstacles.
At which point it is your choice to switch off the guard rails.
Like the chap somewhere down below telling me he will use Rust “unsafe” so he can have direct control of his memory. Yes! You can! You can also read/write to /dev/mem directly!
Translated in English “I will turn off the compiler’s safety checks because it is getting in my way”. There are many ways to shoot yourself in the foot with this level of power.
He is agreeing with me, but this is HN and opposition must be maintained. Dung must be flung. For reasons.
Sure, for certain kinds of protocols this kind of polymorphism is not always needed. But I am merely pointing out the threshold where the type-safe paradigm begins to falter. The corner cases where the pros don’t outweigh the cons. Where the “compile time” and “runtime” distinction becomes a hindrance rather than a useful separation of concerns.
You can go further. Software Defined Networks. Application router.
In general, contexts in which it would be useful to know the shape of your data at runtime!
As a spontaneous aside… if your entire information-processing system is well-typed (top to bottom) - congratulations. You are well on your way to understanding Category Theory.
The entire data-schema of your stack is what Mathemaricians call a (small) “Category”.
Any routing logic which makes routing decisions based on information nested arbitrarily deep into your packets.
Is this an IP packet containing data; or an IP packet containing an HTTP GET request to www.google.com?
You have to do arbitrarily deep type inference in real time.
The the data has no semantic content until you infer some! Is just a bitstream!
It's not an analogy. Programming languages and routers are particular instances of computable functions. "dispatching" and "routing" are just another example of us using different English words to describe the exact same computation: M:N mapping function.
Whether the input is mapped to an IP address or a memory address - boring implementation details.
Nothing in a router is analogous to a value of a type because there is no such thing as "types" at runtime unless you infer them! Types exist only at compile time. Types are semantic annotations of data. You are helping the compiler help you by telling it what you know about the data you are handling.
This blob encodes a Number. That blob encodes a String.
If you don't want any help from your compiler, you don't have to tell it the types of anything - just manipulate the data directly!
That's precisely what an Assembly language do. Everything is untyped.