8000 [draft] Create new 'snabb' module to define the core API by lukego · Pull Request #465 · snabbco/snabb · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[draft] Create new 'snabb' module to define the core API #465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

lukego
Copy link
Member
@lukego lukego commented May 8, 2015

The idea is to explicitly define our core API in one place. Then users will not required a lot of individual modules (core.packet, core.link, etc) but instead access everything through a unified and well-defined module (snabb).

This draft API would make code look more like this:

local config = snabb.config()
config:add_app(...)
config:add_link(...)
snabb.engine.configure(config)

and

local packet = snabb.packet()
packet:shiftleft(42)
print("packet length after shortening: " .. packet:length())

Notably you would not have to require() any modules anymore. (You could require("snabb") if you want to but we could probably just make it global.)

This MIGHT also make it easier to create new versions of the API with semantic versioning (http://semver.org/) and even to allow apps to say which API version they depend on so that we could keep compatibility with older versions for as long as we want.

The idea is to explicitly define our core API in one place.  Then
users will not required a lot of individual modules (core.packet,
core.link, etc) but instead access everything through a unified and
well-defined module (snabb).

This draft API would make code look more like this:

    local config = snabb.config()
    config:add_app(...)
    config:add_link(...)
    snabb.engine.configure(config)

and

    local packet = snabb.packet()
    packet:shiftleft(42)
    print("packet length after shortening: " .. packet:length())

Notably you would not have to require() any modules anymore. (You
could require("snabb") if you want to but we could probably just make
it global.)

This MIGHT also make it easier to create new versions of the API with
semantic versioning (http://semver.org/) and even to allow apps to say
which API version they depend on so that we could keep compatibility
with older versions for as long as we want.
@lukego
Copy link
< 8000 /span>
Member Author
lukego commented May 8, 2015

This would be a big change. What do we think (a) of the idea of a unified snabb module and (b) of this draft API?

@sleinen
Copy link
sleinen commented May 8, 2015

I don't feel qualified to comment on the concrete API, but the approach with the snabb module sounds very attractive to me. It could make Snabb more "approachable" and give it(s core) a clearer identity.
Note that I'm speaking as someone who has been interested in Snabb switch for a long time, but never programmed to it so far. So I completely ignore the cost of moving to such a model!

@lukego
Copy link
Member Author
lukego commented May 10, 2015

Thanks @sleinen! You are the target user for this change in many ways i.e. the idea is to create a friendly and stable interface for people to write their first app.

I mean "stable" in the sense that we would only make backwards-compatible changes to the snabb module. If we need to make incompatible changes then we do that by creating a new module like snabb2 and snabb3. The older modules would be deprecated and then removed in a thoughtful and controlled way.

So the user module might actually start with:

local snabb = require("snabb1") -- get warning/error if deprecated/removed

The implementation cost seems minimal thus far in that the snabb module is a thin layer over the top of the actual implementation. The module would need to become more complex over time if it implements an older API version that is less in sync with the actual implementation (e.g. if we have a snabb0 that supported the iovec API in some clever way even though it does not exist in the actual packet module).

I am experimenting with how the Getting Started apps would look in this scheme. I will push progress on those experiments onto this branch.

This is an experiment in programming style. The programs are written
realistically but have not been tested. The idea is to see if this is
the way we want people's first programs to look.

Compared with the master branch the intended differences are:

- Use the new Snabb API from this branch.
- Use require("snabb1") to explicitly depend on API version 1.
- Use the "apps have a private sandbox" model in sprayer.lua.
- Use the 'link:transmit(packet)' object-oriented syntax variant.
- Make program/ module files simply run instead of loading first.
- Added engine:run({duration = 'toidle'}) option (run until idle).

The overall effect should be shorter code that looks more like plain
Lua scripts.

The use of 'link:transmit(packet)' syntax feels right to me in this
example. It is also a retreat from the position that I took on
snabb-devel where I advocated for 'l:link_transmit(packet)' (after
having previously advocated for link.transmit(l, p)).
@lukego
Copy link
Member Author
lukego commented May 10, 2015

In commit b44f510 I wrote an experimental new version of the Getting Started sprayer app/program. For comparison the version that works on master is in #439.

This is a style experiment: if I could write this code using any of the programming styles currently under discussion on snabb-devel then how would I want it to look? This code is an attempt to make the code simple and more like plain scripts rather than parts of a big framework. (The code does not actually run yet.)

See the commit message and code for full details.

Question: Is this the coding style that we want to adopt and explain to new users? What is good and what is bad? What details do I miss?

lukego added 2 commits May 10, 2015 12:36
Use short method names like transmit() instead of link_transmit().

This is consistent with spray.lua but inconsistent with
snabb.lua. Question is: which is better?
The previous commit consistently used short method names:

    link:transmit(packet)

this new one switches to long ones:

    link:link_transmit(packet)

This is a style experiment: redundancy vs ambiguity.
@lukego
Copy link
Member Author
lukego commented May 10, 2015

Commit 40bc269 uses short method names and commit eb36db5 uses long ones.

The trade off seems to be between redundancy when the variable name conveys type information:

engine:configure(config)      -- short and sweet
engine:engine_configure(conf) -- long and redundant

verses ambiguity when the name does not clearly tell you what the type is:

input:is_empty()      -- short and ambiguous
input:link_is_empty() -- long and clear

Just at the time I am writing this I prefer the long names. That frees you up from having to think about whether you are conveying type information in your variable names. You could call a config object config, conf, old, new, or c and nobody need get confused or ask you to change it on a github review.

@eugeneia
Copy link
Member

I am not sure I like the local snabb = ... pattern. Currently we do have the core API globally accessible to every file without doing any requires and without the snabb. prefix. Do we want people to explicitly specify an API version in each of their files? I feel this should be handled in a declarative way independent from the code (e.g. a build option) and I feel the option of using multiple API versions in one file is not important.

@lukego
Copy link
Member Author
lukego commented May 11, 2015

Do we want people to explicitly specify an API version in each of their files?

Good question.

Suppose we say yes. Could we then support multiple apps each choosing which API to use? That is, some apps already using the latest and greatest, and others using older APIs. This would allow us to introduce a new and incompatible API with a new module name (e.g. snabb3) and immediately make it available to everybody but without forcing them to adopt it.

That would mean, for example, that Alex could pull from master into his VPN branch and get radically new features, but decide for himself when to adopt them.

The goal that is developing in my mind is to support rapid improvement on the master branch (API revisions, app sandboxes, parallel execution, etc) and also for application developers to feel that they can safely pull from master and have the chance to adopt new features on their own schedule. That is unlike the situation now where pulling a feature like the straightline API means you have to immediately update all of your code before you can run again.

@lukego
Copy link
Member Author
lukego commented May 11, 2015

Question: is that the right goal? and what is the best way to achieve it?

@lukego
Copy link
Member Author
lukego commented May 11, 2015

@eugeneia I suppose the reason for the local snabb = ... is that it seems like a really simple mechanism that does not involve any new concepts. How else would we indicate API version? I think it would be more complex to do it in the Makefile for example.

If we simply made all of the APIs globally accessible then that would be simple too, but then we would be writing function calls like snabb2.config() instead of snabb.config().

@lukego
Copy link
Member Author
lukego commented May 11, 2015

Speaking of the Makefile...

If we supported multiple API versions then a very nice test case would be to run the latest Snabb Switch core with the older apps based on the previous API. Then we would have full test coverage on the original API instead of gradually less as fewer modules are using it.

How could we do that? I mean, run core from master but apps from an older branch.

This thread becomes long :-). That is good: we can use this PR mostly for discussing ideas. I will resubmit the code on a new PR once we know how it should look.

@eugeneia
Copy link
Member

What if the snabb variable was implicitly defined (globally), then you could redefine it manually (local snabb = require("semver")) or through some Makefile trickery.

I think we should eliminate patterns that will effectively will be the same in almost every file, e.g. a common header. I feel the same way about our module(...,package.seeall) dance.

@lukego
Copy link
Member Author
lukego commented May 12, 2015

@eugeneia If we have a global snabb module then how does it work when we introduce new and incompatible versions? For example if we have snabb1, snabb2, and snabb3 then how does each app get the right one bound do its snabb variable?

I am totally on board with avoiding boilerplate. I am not sure that is what we are talking about here though. The local snabb = require("snabb2") seems like important semantic information that is being put in the most directly relevant place. It tells both the reader and the compiler "This file has to be linked with API version 2." I don't immediately see a good way to handle this otherwise.

The whole scheme could be naive of course. For example we may end up with a mess of modules based on different versions calling each other and passing incompatible objects. I am not sure what is the best precedent for a scheme like this.

@lukego
Copy link
Member Author
lukego commented May 12, 2015

Here is one more idea:

If we would go ahead with the design to sandbox each app in a private Lua VM then we could also have one API version valid in each VM. That way each app could depend on a specific API version and we would not have the issue of calling modules with different APIs (each app can only load one API).

@lukego
Copy link
Member Author
lukego commented May 12, 2015

This can also be that I am drifting into fantasy land a bit.

Concretely the problem to solve is to be able to redefine core APIs and deprecate rather than immediately remove older ones.

Could be a simple idea to have a single snabb module that should implement the union of all supported API versions?

@eugeneia
Copy link
Member

I just meant that an app would use the latest and greatest by default or lock to a specific version using the local snabb assignment.

and passing incompatible objects.

This is a good point. To be honest to me the multi-api-version scenario sounds a bit wonky to me. I feel like keeping radical API revisions in a long lived feature branch until we are happy with it might be the simpler and more failure proof approach.

How about divide and conquer? Split this train of thought into (a) a branch with the API we want, (b) considerations on how/when to integrate it. But let us not get one in the way of the other.

@lukego
Copy link
Member Author
lukego commented May 12, 2015

I just meant that an app would use the latest and greatest by default

The scenario that I want to support is that a long-lived branch supporting a specific application (for example Alex's VPN device) can safely pull from master. The expected effect is to automatically get fixes and optimizations but that API changes do not cause breakage and can be adopted separately.

That is, to stop doing what we have been doing recently, where pulling straightline means your branch is broken until you update all your apps, and pulling program means the scripts to run your programs are all broken, etc. I think it is time to start being more responsible about this so that people will continue to track master closely.

@lukego
Copy link
Member Author
lukego commented May 12, 2015

To be honest to me the multi-api-version scenario sounds a bit wonky to me

I am coming around to this way of thinking at the moment. :-)

keeping radical API revisions in a long lived feature branch until we are happy with it

Would two weeks be "long lived"? :-) I would love to land a new API in the June release so that we can bring new people into the project with a warm and fuzzy getting started experience.

@lukego
Copy link
Member Author
lukego commented May 12, 2015

The next step on this branch for me is to flesh out the proposed API more and make it actually work and then we can see whether it gets a thumbs up or thumbs down.

@eugeneia
Copy link
Member

I personally feel like right now is still a sensible moment to make radical changes, but we should ask Alex and the people who actually feel the pain.

@lukego
Copy link
Member Author
lukego commented May 12, 2015

The code currently on this branch is actually both radically new and backwards compatible. The documentation would tell people to use the snabb module but that is only a front-end on the code that already exists.

Isolating apps in sandboxes might be done only when the app class is given as a string so that "classic" apps can continue to share a Lua VM and operate exactly as they always did. (People might want to wait for an excellent implementation of parallelism before bothering to update their apps to the new scheme to take advantage of it.)

@lukego
Copy link
Member Author
lukego commented May 12, 2015

I feel like keeping radical API revisions in a long lived feature branch until we are happy with it might be the simpler and more failure proof approach

That is actually a really excellent point. It is a perfectly valid idea to stick with the API that we have today, that we want to support for some time to come, and that by now have good documentation for. Then the new features (APIv2, sandboxes, parallelism) could develop at their own pace on their own branches and be merged onto master when it makes sense for everybody. (Or not at all in the case of ideas that lead to dead ends.)

There is more than enough to get on with this month just in terms of shaving off rough edges and fixing open bugs.

@lukego
Copy link
Member Author
lukego commented May 24, 2015

Closing because the goal of making an experiment and getting feedback is accomplished.

@lukego lukego closed this May 24, 2015
@lukego lukego deleted the snabb.lua branch June 18, 2015 13:17
lukego referenced this pull request in virtualopensystems/snabbswitch Aug 12, 2015
874e48b adds counter support in core.app, core.packet and core.link.
Cache counter functions lookup locally for better performance.
mwiget pushed a commit to mwiget/snabb that referenced this pull request Oct 15, 2016
Move lwaftr/nexthop to snabbvmx/nexthop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0