GoBGP: BGP Implemented in Go(github.com) |
GoBGP: BGP Implemented in Go(github.com) |
* Authority DNS
* DNS caches
* ntp
* SMTP
* SSH
* IMAP (added later)
* SNMP
* PBX/Telephony
Fortunately, as time goes on, fewer and fewer people need to run these services at all.
Let's say I have replaced bind, unbound, ntpd, postfix, openssh, dovecot, snmpd and asterisk with Go-written equivalents. Three weeks later, there is a bug found in the standard Go TLS library.
My distro ships all the packages noted above, but not their Go-equivalents, so my work load now includes monitoring security-announce lists for eight different products, where before I monitored the security-announce list for my distro.
I need to be able to rebuild all eight systems myself, rather than getting automatic package updates to my test systems, and then promoting the packages through alpha and then production. Go is nicer than some other languages about that, but it builds binaries, not packages.
Next:
I'm pretty sure you can't build an snmpd without ASN.1 parsing, and ASN.1 parsing is the very model of a fraught and perilous splatter-fest. Will the Go ASN.1 parser be better maintained than libtasn? Maybe, maybe not. Repeat this for everything else.
Can these problems be solved? Sure. Are they ready right now? Not that I'm aware of. Please enlighten me, if you have good answers.
The whole point of using Rust or Go instead of C is that the "peril" of implementing things like ASN.1/BER is pretty much eliminated.
As for your former point: I don't follow. Go's deployment infrastructure is a superset of C's, and, if you're a masochist, almost everything in C's deployment toolkit is available to Go projects as well.
On the flipside, though, this is probably a case where using something like Rust could be excellent: stronger language support for eliminating entire classes of bugs but also able to be compiled down to something that can be a shared library.
I'm not an ML expert, but reading about the things the Mirage project has done related to TLS, leveraging OCaml to provide compile-time guarantees, sounds very exciting. Rust feels like it could be that bridge. Start rewriting core libraries in it: cleaning up old code, removing dead code, avoiding bugs by virtue of the language/compiled, in one fell swoop.
But say your distro includes the Go versions, but not the C ones... You're basically complaining that your distro doesn't include everything.
https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/...
(Sorry for being light on details; typing from phone)
You could handle it the same way that python handles it. Don't rely on a distro, have each person package their own stuff.
I'm not sure what you mean here. Are you suggesting it's a positive that the Internet is becoming centralized? Why is it "good" or "bad" that lots of people run SSH, their own email, or their own phone server?
Obviously one part is that it's hard to run them correctly, but I would argue the internet may be a better, more authority-resistant mechanism if some of these services were run from each person's home or VM rather than on Google's platform.
https://security.stackexchange.com/questions/56069/what-secu...
All of these services would be better suited for a language which has blessed async IO, concurrency, parallelism primitives. Go has these, Rust does not. pthreads are not the answer.
I much prefer Rust, but Go's stdlib and concurrency features far exceed that of Rust at the moment.
Go does not have truly async I/O. It has a userspace (M:N) implementation of threaded, synchronous I/O. There is a distinction, and it's not an academic one.
Rust uses the kernel-level (1:1) implementation of threaded, synchronous I/O, with async I/O provided by mio if you want it.
There is no meaningful distinction between Go's language-level primitive channels and Rust's MPSC channels in the standard library. Not supporting generics is a good reason to put channels directly in the language, but that doesn't apply to Rust.
Additionally, I don't see how Go provides any parallelism primitives that Rust doesn't. In fact, Rust's parallelism (particularly data parallelism) libraries far exceed the capabilities of Go's, mostly because of SIMD and generics which allow you to build highly optimized data parallel abstractions. If I tried to parallelize the project I work on in Rust using Go's built-in primitives, it would be far slower than sequential.
And while Go does have great built-in stuff for a certain kind of concurrency, Rust's approach is more flexible and safer. It's a tradeoff, not a "far exceed" in my mind.
Concurrency & parallelism primitives + safety.
(In particular, note that SSH daemons can fail in many ways other than by remote code execution.)
In the long run, C's role is indeed shrinking - but let's not be too hasty.
But most of what people do with SSH in a devops context isn't interactive; it's a simple control channel for well-defined sequences of file transfers and commands.
I'd prefer a minimal, Go/Rust-based SSH server for my EC2 servers, for instance.
I don't know why I'd prefer OpenNTP to a Go/Rust NTP. What's the advantage to it? OpenNTP is carefully built to avoid a class of bugs that its implementation language is very susceptible to. Go/Rust simply don't have those bugs at all. The latter seems like the safer option.
Same goes for DNS.
Doing it in idiomatic way and dealing with all that goroutine per request model, concurrent memory access and unpredictable GC pauses is simply not worth it. It's going to be safer, but not of a decent quality. Better to live with what we have.
For Rust, I imagine, it's going to take even more work.
Virtually every Go program that anyone has deployed at scale has scaled I/O with goroutines (though not necessarily with "concurrent memory access").
With the exception of NTP, I can't see a single example of a service in the list I provided that is sensitive to "GC pauses" on the scale you'd end up with in an idiomatic Go program.
Granted, that uses pfring pretty substantially, but still...
[0]: https://twitter.com/brianhatfield/status/692778741567721473
ntppool.org uses golang for DNS https://news.ntppool.org/2012/10/new-dns-server/
just curious about this: are there folks trying out dpdk with go ? implementing these control-plane applications in vanilla sockets (or close-to-zero-wrappers on those), doesn't seem fruitful anymore.
fwiw, i have been doing dpdk stuff, but have been mostly using C...
the sheer number of person-hours at developer salary rates in north america would probably amount to at least a few million dollars.
EDIT: As an example, the gogs project has implemented a small ssh server so people running it don't need to hook into OpenSSH, which relies on specific versions of OpenSSH to be performant. See https://github.com/gogits/gogs/blob/master/modules/ssh/ssh.g...
http://dave.cheney.net/2014/09/01/gos-runtime-c-to-go-rewrit...
Operational experience at scale is needed to know how to write an effective SMTP implementation, and that experience is half-documented by many people in many different information silos.
But... I'd also say it's an extremely forgiving protocol. In fact, it's the fact that it's so forgiving which makes operational experience required to implement it. A "correct" SMTP implementation has a lot of latitude in the choices it makes - and it's that latitude which makes life difficult.
Off-hand, you could use GoBGP to do cheap loadbalancing-ish things without external dependencies.
Seeing the same trend with Go now. Why add the language name to the software name? Real question...
I don't really like the language-name-prefix thing either. It makes the language seem like the important thing about the project. Sometimes it is the most important thing, but even then, that is mostly only true at the beginning of a project when attracting contributors is most critical. But I'm not sure the other approaches are much better.
The problem with those sorts of projects however, is inertia. The average hobbyist rarely ever uses BGP. Large networks and ISPs aren't going to implement my personal project as a critical component to keeping their entire infrastructure online without a very good reason.
This project looks promising, I'm hoping it doesn't suffer this problem.
Suggestion: include a quick abstract what what BGP is with a link for more information.
Even if you're not a huge ISP, it's handy to have a BGP implementation available because you can use it to do network analytics and traffic management.
I also clicked through several pages on the repo / site and there was no clue as to what BGP was, except some mention of RPC.
But it can be helpful for topics with ambiguous acronyms or tech. names (Apple) Swift vs. (OpenStack) Swift, for example.
In general: We can all be better teachers. Acknowledging that not everyone who writes code in Go shares the same background, training or interests is a good step to getting more people to use Go.
Compiler entirely in Go and very fast cancels that whole line of thinking. Far as precision, the original source could've been ported from COBOL and that wouldn't matter. The point would remain it's now in Go and gets the job done.
Yes, every connection has a (small) thread stack associated with it. But in a "truly asynchronous" network program, every connection still has memory associated with it; it's just that the memory doesn't take the form of a procedure stack.
That's also true with 1:1 threading. It's just that the context switching is handled by the kernel.
Semantically, there's no difference between what Go does and what NPTL does. The difference is in implementation: Go does a lot of the work itself in userspace, while NPTL does the work in the kernel. (I say NPTL not to be pedantic but because there were pthreads implementations in Linux that used Golang-like schedulers. They were abandoned in favor of NPTL because the extra complexity was judged to not be worth it for small if any performance gains.)
You're right of course that you need per-connection state in any model. But with a state machine you can be much more compact than a call stack. Modern compilers (I doubt this includes Go 6g/8g, but haven't checked) will do stack coloring to reduce stack usage, but the overhead is still significant because compilers essentially always choose runtime performance of straight-line code over stack compactness wherever there's a tradeoff. State machine compilers, like C#'s async/await compiler, make the opposite choice, and as a result they can use less memory. Moreover, with state machines you can go the extra mile and really pack your state into a tiny fixed-size allocation you can allocate with a segregated fit arena. That's pretty much unbeatable for performance.
You have to remember, Rust is a systems language. Which means that you need access to what the system gives you, and that means at least OS threads and both synchronous and asynchronous IO. We can't just decree "the world must use only aio and green threads", or we would be compromising Rust's fundamental design goals.
Adopting Go's approach would force either asynchronous I/O or M:N threading on everyone, which is unacceptable for Rust's goals.
Still, I want to reiterate, that event loops in modern languages are more about managing complexity, than performance.
A project page for a $language implementation of $protocol shouldn't be expected to give a basic description of $protocol. If you care about a new implementation, you already know what the protocol does, at least generally. If you're lucky, the project page links to a protocol description (possibly at wikipedia), or, as above, you can simply google it yourself and then decide whether a $language implementation of it is something you care about.
I mean, it already has a link to the golang website, but no mention of what BGP actually is.
Really, you're playing on a semantic ambiguity in the word "router". A BGP implementation doesn't forward packets; it maintains a database of forwarding paths that the packet forwarding layer consults. In a large Cisco router, the SOC that runs BGP and maintains the RIB isn't the same electronic component that forwards packets.
Standard network software such as Postfix and OpenSSH took ten years to replace their predecessors, and their eventual replacement will be just as gradual. It's not happening right now, so I think it's a bit of a stretch to call it a trend.
My objection is that you are advocating this in the same narrow-focused way that people advocate node with npm, python with pip, ruby with gem: little or no cooperation with the whole system is available yet. This is perfectly fine from the point of view of a group which does one thing, but not from my point of view, running large numbers of diverse systems.
When libfoo gets updated, all N packages on the system which use it via dynamic linking gets the benefit as soon as the packages restart. This is highly desirable.
If Go-libfoo is updated, each of those N packages needs to be rebuilt, but I don't have a programmatic way of finding out.
If there are N teams developing those packages, some of them will be faster off the mark than others, and now I have a window of vulnerability that is larger than the one I had when I could update libfoo on day 1.
You have multiplied my workload. I won't do that without a really good reason.
But I notice you didn't respond to my SNMP point, which is disappointing, because I was hoping that at least some fake Internet points might accrue to my otherwise fruitless efforts at implementing SNMP from scratch three separate fucking times. Can I at least be rewarded for that by winning a dumb message board argument!?
There's even a cool trick to implementing BER encoders I could have talked about!
Instead, it looks like the thread is going to be about dynamic versus static linkinnzzzzzzzzzzzzzzzzzz.
This is IMHO the most backwards logic ever. Everything about dpkg and apt makes this process easy, from running an internal custom packages repository, through to "apt-get source" for any system package on a moment's notice, through to having everything just magically revert back to Debian-patched versions as part of the normal upgrade process assuming you versioned your custom packages carefully.
A well run Debian shop is a thing to be seen, unfortunately it's not cohesively documented in any one location on the Internet. If there's any problem encountered in the wild on the Internet, after 22 years, there is almost certainly a solid process built into Debian to handle it.
Compare that to home directories full of tarballs of binaries with dubious compiler settings and godknows what else, I have no idea why someone would advocate against it, assuming of course they've actually done sysadmin anywhere aside from the comfort of an armchair
That's a misunderstanding. What Debian, and every other mature Linux distribution, gives you are the tools to not only rebuild a package on a moments notice (try to build any non trivial third party package sometime, and compare that to rebuilding the Debian package) but also keep track of those patches over time (where did it originate? bug id? upstreamed yet?) and keep a bird's eye view over deployment (which nodes? when?). You need to ask yourself those questions, because your auditor will.
Good for you to implement SNMP, and using the f word in writing, but maintaining infrastructure is something else. Your reason to not use Debian for critical infrastructure should be because of contractual liabilities and/or support reasons, its build tools and associated policies are solid. It's not the only way to roll, but it's a perfectly valid one.
And yes, I agree. I think we're to the point now where sysadmin-style "I'll wait for Debian to entmoot on this TLS vulnerability and eventually drop something" server maintenance is on its way out for those who operate cattle. Especially high-visibility cattle, as you imply. The industry is teasing the post-distro world into existence but doesn't yet know what it's dealing with on that point. I don't even consider CoreOS a distribution, for example; I think it's more of what Linux will look like in several years time for cattle herders, while Debian and friends will continue to go in pretty hard on pets.
Dynamic linking creates more problems than solutions in a cattle fleet as opposed to a pet fleet. People who philosophically argue for one or the other are expressing their preference for how to administer a server and do not realize that it is a preference, and not "correctness," per se. The package manager argument is the same way. Execute the code and get it done, or be "correct" and only apply updates through RPM. Cattle, pets. It's all cattle and pets, and the arguments that spawn between the cattle camp and the pet camp will never be resolved, this thread included. People need to realize this, that there is not one way to operate a server, and my way is not more correct than your way.
My way, for example, comes with the baggage of an expected organizational structure to enable its mission. That's not always easy, and I understand that. I can say, however, that the SRE/cattle way makes a hell of a lot of sense at scale.
Apparently gcc seems to be the only C compiler lacking this capability, thanks to glibc.
Also, you can use dynamic linking in Go since version 1.5.
That is true; but updates to native libs that would propagate to C, Python &al. will generally not propagate to Go because, like Java, Go eschews native bindings.
After all, there is a reason it's called the wikipedia rabbit hole, do you know how often I start with a quick search and suddenly it's an hour later and I've learned all about $something-other-than-originally-intended?
On other issue, here's what typing BGP into Google gace me at the top: "Border Gateway Protocol (BGP) is a standardized exterior gateway protocol designed to exchange routing and reachability information among autonomous systems (AS) on the Internet. The protocol is often classified as a path vector protocol but is sometimes also classed as a distance-vector routing protocol."
Some things are hard to search for. Others, like BGP protocol, are so common you'll get it easily. Those can default on Google. Further, what use is a programmer going to be in robustly implementing the protocol if they can't figure that out? Hence the filter part. So, my position is more solid now that I Googled it.
i don't even
care
anymore.
sorry, but i still don't grok it. for example, if you take a person 'object' defined as :
Person {
name string (or equivalent asn.1 type-name, with type-identifier == 1)
age int (or equivalent asn.1 type-name, with type-identifier == 2)
}since b.e.r is basically a tlv (type-length-value) encoding, a person with name "james" with age '10' i.e.
james_person = Person(name = 'james', age = 10)
gets hex-encoded as :
"james" : 01 05 6a 61 6d 65 73
"10" : 02 01 0A
so the whole thing looks like this:
"01 05 6a 61 6d 65 73 02 0A".
ofcourse this would be prepended with appropriate type-number for 'Person' with corresponding length.
if we assume that 'Person' gets a type-identifier == 3, then 'james_person' instance would be encoded as:
"03 06 01 05 6a 61 6d 65 73 02 0A"
where '06' == total length (6 bytes) of this instance of person object.
may you please elucidate your trick with the above example ? thanks for your insights !
I think the right solution is something like async/await to make truly asynchronous programming palatable. But in the meantime, 1:1 threading is really not that bad on Linux, because the kernel is very optimized.
.NET defaults to this, you can opt out (which you usually want to do, at least for correctness) by doing await Foo().ConfigureAwait( continueOnCapturedContext: false )
EDIT: my etc.'s are weaseling around the word thread... more details about .NET here: http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-awa...
I fear a world of gevent/Twisted, EventMachine/Celluloid/base Ruby, Boost/a litany of other options.
And then the fact that safe, reliable code is only first step toward secure code where an intelligence, malicious person is targeting it. Totally different ballpark that neither Sendmail nor Cisco handled so well. Small shops like Sentinel and Secure64 did way better with a tiny fraction of the money. So, it has to be intentional for the extra profit at customers' expense.
Dynamic linking just makes it easy to program for the same scenario.
The problem is that you have to wait for the patch to be bundled. I've watched that take a long time, while services I knew to be vulnerable had to sit there and be vulnerable because the organization deploying the service didn't have any infrastructure to apply a custom patch.
Consider the degenerate case, where you have to wait for a Debian patch because you paid for the research that found the vulnerability. More than one of my clients wound up in that situation. But that's not the only way to learn about a simple, critical source patch that won't land in a Debian patch for days.
$ apt-get source bash
$ cd bash*/
$ quilt new my_urgent_patch
$ patch -p1 < ~/my-urgent-patch.diff
$ quilt add file1 file2
$ quilt refresh
$ dpkg-buildpackage ...
$ dupload ../*.changes
# trigger apt-get upgrade on target machinesI know I'd personally chose maintaining the system packages and where possible put extraneous language dependencies in packages too (fpm comes in handy as it can deal with a variety of packages, gem, npm etc). It makes life a lot simpler when it comes to administering a bunch of systems and trying to keep things consistent.