 Okay. So this is just kind of fun and games. So speak up and I'll try not to take too long. So this question comes up. Occasionally to us we get asked by people that are just learning BPF. Like they don't know much about BPF. They're like a director or something or they're like doing some sort of like analysis of languages, right? And the question was... Or analysts. An analyst. There we go. Thank you. And so the question was like asked of me a couple times and I was thinking, well, is this actually true or not true, right? If you don't know what a Turing machine is, like this is my cartoon. I'm not going to write the whole formula down. Like you go to like Wikipedia or anywhere on the web and find the like the actual articulation of a Turing machine. But if you don't know, the basic idea is you have a tape. That's the top part. It has infinite memory, right? And then you have a needle there that can either write, can read and write to the tape. And then you have a program at the bottom of the state machine that tells you if you should read, write, and then if you need to go left or right. And there's like a formal function that that has to meet and a definition of the tape and the alphabet and all that good stuff. But I'm going to skip over the formal definition and just talk a little bit about this part. So what does this actually like, what does this mean like in, you know, what's Turing complete mean in kind of not mathematically formal terms? It means you can do loops. It means you have control flow and you have this unlimited memory tape. Of course we know that that's not actually true. So we have this arbitrarily large memory is how we replace that. Technically that moves you down in the language hierarchy and all that fun stuff. But for the fun and games part, we're not going to define all of that or just say arbitrary large memory control flow and loops. Then what does it actually mean like why do I care? Is it probably a good question that I always ask when people ask me this? There's some things that cannot be solved by Turing machines. There's some things that can be solved by Turing machines. The halting problem is the classic one. You cannot tell if you're going to halt. A mortality problem is basically do all of these strings terminate with this machine. The word problem for groups is given like an expression and a set of rules on that expression. Can it be reduced to the equivalent strings basically? It's like a fun algebraic problem. So those things cannot be solved. What can you do? You can simulate Turing machines. If you've seen the game of life, you can run the game of life on your Turing machine. You can compute general recursive functions. I don't know about you, but I've been really wanting to do that with my VPF programs. What else can it do? It can do all these useful things too, right? Like actually parse traffic, DDoS protection, collect metrics, file integrity monitoring. So like all this useful stuff VPF can do, right? Whether or not it's Turing machine complete doesn't really matter to do all the useful things. So who cares? This is sort of my caricature of people that ask me this question, right? So usually it can be somebody who's learning VPF, who's trying to understand the big picture. Maybe they have like a language and compiler background. Maybe they're an academic and they just want to like they're coming to VPF and like asking these kind of questions and trying to compare it to other languages they know, right? The other, the second person who comes and asks this question is usually already convinced that it's not Turing complete and they'll say things like you can't write an HTTP parser because it's not Turing complete and what if you have endless headers in your HTTP parser, right? Or like I have Geneva and I want you to parse every TLV and the Geneva thing, right? So these these kinds of things and they're usually already set against VPF and they may or may not have another solution in mind usually. And then the character three is kind of myself who's just thought like this would be fun to do. So let's do it. Okay, so a little bit of side point. So the main problem is going to be the loops, right? Because I know VPF can do control flow no problem. VPF can do arbitrary memory because we have maps of array sizes that can be arbitrary large. 64 point size bit pointers aside, right? Then the other point I just make when people ask this is like they're worried about upper bound times like being able to loop. Having an upper bound is actually a pretty useful property of a system, right? Usually I don't want my networking to run forever. I want it to have an upper bound. Same way with any kernel security schedulers, XDP, right? In general, at least in most of the work that we do, we're trying to drive down the program cost. We're not like trying to see if we can do more loops. So there we go. I actually have trouble finding a useful use case for VPF where I would not want this property of boundedness. So I'm interested if there's some reason people want unlimited runtime VPF where you have no clue where it stops, right? I couldn't think of anything particularly useful. I mean, calculating functions aside and playing game of life inside VPF. Yes, let's go, you guys. There was a real use case. So there is this causal profiler approach where you slow down everything except like one or two different things and measure how that like actually one thing and then measure how speed kind of like you simulate speeding up something by slowing down everything else. Okay. And then like you measure how much like if you speed up something to X, how much it influences like the overall latency, right? So why not? Like VPF slows down everything except like one code path. So you do that with like a sleep? You can burn CPU or sleep, yeah. Okay. Cool. I'll put that in the next slide deck. Something also relevant is that I'm thinking of how to inject the latencies using VPF. So there's the latencies you can't, I want it to be like to be customizable at a runtime. So you specify the latencies at runtime. So when you write a program, you don't know how long going to delay. And that's something I'm thinking of recently. Okay. It sounds almost like we need a sleep, which wouldn't, you know, have the have a VPF helper for sleeping and then sleep for as long as you say. Cool. All right. Two use cases. I stand corrected. All right. So if I want to show that it's trying complete, the real hook is like how do we do loops, right? Like how do we get something to run forever? I think if anybody objects, let me know. If you think that the memory maps aren't arbitrary large and the control flow is not an if-else, but I think we're pretty good. And the arbitrary large depends on that we don't want to argue about 64 bit pointers, which some people do. All right. So we basically need to do again. So this is what I did for a do again, so that we could recursively loop and just create a callback with a timer of zero. You'll get right as long as there's you put back on the timer list and you'll get called back immediately with your callback. And this will run forever until it terminates. Any objections to my loop? It's pretty close, right? It's not much different than like a CPU relax, for example. I don't think anybody would argue CPU relax is okay in your loop. All right. So we have a loop, so like with that. And so then the question is, is that enough for turning complete? This is just a sketch, but what you would say is showing something's turning complete usually you'd want to build something that simulates a Turing machine. That's sort of a pain to do. So we want to find something that's Turing equivalent, basically because of the properties of Turing machine. If something's Turing complete, you can simulate the thing that's Turing complete, then you can simulate Turing machine by walking through the chain. So there's these things called Tuesday systems, which are sort of interesting and useful, but also easy to program. What they are is a set of production rules, which tell you what to do when you see the letter A or B. So you can just say, when I see an A, I want to append A, B, A, B at the end. And when I see a B, I'm going to append an A at the end. And then there's a cut number, which says how many numbers you want to take off the front. So you read the first letter, tells you what to prepend, and then you cut off two from the front. And there is a papers, I didn't put a link, but I can put a link to it. There's a bunch of papers that will show you that this is actually equivalent to a Turing machine and can simulate any Turing machine, which gives you an any Turing machine considerably. It is a universal Turing machine, and so you get your chain. So all you need to do is simulate this. All right. Oh, I'm not going to do a demo, I guess. Let's see. Is this going to work? Here we go. Did it crash in the back? Oh, I killed it. Okay. So basically, in the Silly and Meabee PF library, mostly because I wanted to figure out some of the Silly and Meabee PF APIs on the latest version, I created a Turing example. Basically, it's an implementation of the two tags with the set of productions, and what it'll do is when you run it, type in my secret password, and what it'll do is it'll sit there and run until it runs out of memory, and then it crashes. But what it's doing is, since this is a non-terminating example of a two tag system, you probably can't see it from there. It's replacing A B with B A and B with A B. So it's going to sit here and run forever since this is a non-terminated one. The terminated ones are also interesting, but it's kind of more fun to show a non-terminating case for this example. And it's one program execution with a timer. So you run the program just once. You don't constantly run it. No. No, no. This is just a... Here, I'll show you the code to pop that, otherwise it never exits. So there's just an f3. The code's really ugly, by the way. I wrote this last night or something, but let's see. So this is the loop machine. So it's just this function, which you can see here when we terminate what we do is we just post to the ring buffer, we post the string. So every iteration of this loop, we're posting what the current string is to over the ring buffer. All you're seeing on the printer side is that printing. So we just read the buffer, and every time we get a new string, we print it. That's the terminating case. You can see I'm messing around with it there. But down here is... Here's the production rules for A. Here's the production rules for B. So they're in a map, so you can put whatever production rules you'd like. So we just read out the production rule for that entry, and then we basically prepend it and then cut based on whatever the cut value is that we configured from the user space. So print case there, because I wasn't sure it was actually working. And then... So that's one step. And then you just call your loopback machine again through the timer. Run it again for every step. We'll run until it terminates, or it will run until your system runs out of battery. How did you trigger it? What was the trigger for this? Oh really? TCP Connect, because you know... Why not? It's an f-entry program on TCP Connect. But I was smart enough to do this enable thing so that it didn't start a new turning machine every time my system connected to something, right? But then anyways, what you do is you just... I mean there's probably tons of better ways to do this, right? But I just write it out of a map, you knit this, and it has your knit configuration out of a map. It's an array of one, so it's a load underneath the covers. You look up your tag. Your tag is that string. And then you kick off the timer. You you knit the timer and you kick it off. Maybe this is interesting. I don't know if everyone does this, but if you want to copy arbitrary string sizes, right, you just do a probe read from your from your string back into your string. That way you don't have to do like a try to do a mem copy. Just use the helper to do the mem copy. Mem set to zero. You pass now as a source for probe read. And it should be bpfpropriet kernel by the way. You are setting a bad example here. You know what? This runs on 419. So when were timers introduced probably after the probe read? With bpf it doesn't matter. You always use bpfpropriet kernel and substitute bpfpropriet on old kernels. I'll fix it before the blog posts. Thanks. I mean this whole program's a mess, right? Like let's be honest. I mean and it's from tcbconnect. So anyway that's the program. That's my trying complete thing. I think we might do something fun with it. Yeah I don't have anything else. That was just the fun after you know break thing. No questions. Yeah no questions. Perfect. Thank you so much. I think now we convince the analysts going forward that we're too incomplete. You can program anything in bpf you want to. There's no limits. It's as powerful as your computer. Yeah bpf foundation declares bpf too incomplete from now on. We're good. We should start you know computing recursive functions and doing like serious what math math functions inside bpf because we came. Cool thank you. Thank you so much.