 Okay, right on time. All right, so let's start. Hi everybody. My name is Adam Sayah. I'm a field engineer at Solo.io. What we do is that we help with everything, API getways and service mesh. That's what I do in my work. Though now I'm basically interested more into a deeper layer. So historically again, I work with anything incoming traffic, ingress traffic to commit this cluster, for example, or service mesh technologies. But recently, that's what operates if you look at the OCI model. We are talking about L7 type networking, application networking. But now I'm trying to learn more kind of the deeper network layer, so L3, L4. This is just to optimize everything that is related to networking in general and mostly regarding security and monitoring and things like that. That's a bit of my background. Again, first, thank you all for attending the session. If you have any questions, please reach out to me on Twitter, dash ASAYA. Or you can find me on LinkedIn, for example, OK? So this is an interactive workshop. What we're going to do mostly is a quick introduction to what is EPPF, what is XDP. And then we are going to take a look at some examples of real-world use cases that can be implemented tomorrow. If you guys want to implement some scenarios using XDP, OK? This is really intro level. It's nothing too technical. There's some code to understand and to read. But there's nothing really crazy to, you know, I'm keeping it pretty, pretty basic. And again, if you have any questions, don't hesitate. All right, so first thing is, what is EPPF? And I think I want to start with a question here in the audience, who heard of EPPF before? Awesome, so most of you guys. And who's using it in some kind? Are you guys using EPPF today? No, OK. And who heard of XDP? OK, cool. All right, awesome. OK, so what is EPPF? And why do I care about EPPF in this use case? Again, I was mentioning earlier that what I usually do is to deal with, you know, networking issues. And when we talk about application networking, application networking, you have always some incoming traffic from a client, for example, to a cluster, right? So we have, for example, your mobile phone calling out to a cluster on communities or things like that. And at that level, you think about more, you know, in terms of security and monitoring, you want to monitor your traffic that comes, the ingress traffic coming to your cluster, and you want to also do things like security, right? You want to rate limit based on an IP source, or you want to protect from DDoS attacks, and things like that, right? This is one of the most use cases, most important use cases for anything related to load balancing, for example, and just application networking. And that's operates usually at kind of the L4, L7 layer when we talk about application networking. But this can always be optimized, OK? Mostly because L7 is too late in the network, like, you know, on the stack. It means the application layer, I mean, everything got parsed, went through the network filters and all that stuff, meaning it's really expensive, either from a resource standpoint or also from just, you know, processing. It's too late. If we can't stop things earlier, it's always better. And this is why I'm interested in EBPF, because EBPF, the way it operates, just a quick reminder for everyone here, EBPF is a way for us to create programs that runs on the kernel, OK? So it runs directly in Linux, kernel, and you can interact with it using what we call a user space program, can interact with a kernel space program. So you create some code, and you put that some code attached to, you know, in your kernel. And then you have your user space application that interacts with it, for example, right? So this is really cool. Why? Because then you can really look into things on the kernel level, like, for example, to either monitor, you know, we attach to certain hooks, and then we can do things like monitoring or reshaping the traffic or alternating something, right? And that means that we don't wait until the application layer, which is too late. I do that super fast. I do that at the kernel level. And that's awesome. So if I want to create an eBBF program again, I'm going to write some eBBF code for my kernel space. I add that to my kernel, and then I have another what you call, like, if we take a look here, let's say I want to create a navigation that monitor any type of traffic. I will create first an eBBF program that will listen to hooks here. And some certain hooks are, for example, a network or like a network or file system functions. And based on that, I can report data, right? I can report data to my user space program that can, for example, create the Prometheus function, right? But this is cool. Or I can do it the other way around. So from a process perspective here from a user space, I can create an application that will transfer, like, let's say, I'll say, deny this call from this source to this target. This will go through what you call a map. So it can send data from the user space to the kernel space. And then the eBBF program will get from the kernel space, will get the data, and enforce a certain policy, right? This is, for example, for anything security-related. And we're going to see an example of kind of especially more of the kernel space mechanisms today. So why eBBF? What would we care about the eBBF? I mentioned this earlier. One of the important things is that if I want to, like, monitor what's going on my machine, it is really useful to look at what's happening directly in the kernel instead of waiting for the user space layer, right? User space are consuming, it's too late. If I can get the data faster, right, at the start from the kernel, that'd be awesome. And this is why we use eBBF mostly for monitoring. So anything like traffic-related, you know, like, if there is a call from this space to another, how can I report it easily there and send it to user space to create, like, an approximate metric? So observability, again, is one of the most important features that are, you know, where we can use eBBF. The other thing is networking and security in general. So networking can be like reshaping traffic and that's what we're gonna see using the kind of the tutorial in the workshop today. Networking is really important where we wanna make decision on, like, the packets right at the start. Like, hey, well, now I wanna send this traffic to this different host or I wanna deny access to this machine or I want to restrict something or filter something, right? Anything related to networking can actually get mixed a bit with security where if something happened, like, you know, like something wrong happened on my machine, like packets that are not supposed to be received or a function call that should not have been done, I can capture that using eBBF, I can make a decision there saying, well, this is not permitted, this is denied, and then you can secure your application right from the start without going all the way up to the application layer. Now, what is XDP? Again, eBBF is more like the umbrella term here, but XDP is more dedicated to how we can create things that are way earlier on our network stack. And XDP stands for Express Datapath. It's actually a Linux in Kernel, FastPath. It's basically programmable, like you need compatibility from the driver, from the network, from the driver to be able to use XDP. And what it means by that is like we are listening or actually interacting with the traffic way earlier. So we are talking about like driver here, so that is basically one of the first steps after the physical layer, right? Physical layer, you have the driver, and then you deal with all your other network functionalities. So anything done there at XDP, this is really, really early, right? So in terms of security or routing or anything like that, this is perfect for us. And it can be used for a lot of use cases, and I mentioned earlier like anything related to security or anything related to load balancing, this is a perfect use case, right? For security, for example, you wanna make sure, like if you're dropping the packets right at the start, you are protecting your system 100%, like way better than waiting all the way to the application later, because it's too late sometimes. And for the load balancing, the same thing. If a load balance, using XDP, it's super early, so meaning like you don't have to process packets later on, so you kind of save on processing time and things like that. All right, so if we think about the use case here, like the way we deal with a traditional way of dropping packets, like here is an example of packet drop, I want to completely drop a specific packet. If we're thinking about the kind of the network stack layer using net filter, in this case, you'll see that you have network stack, you have net filter, and then you can drop your packet but the thing is like, the communications already been here when all the way to your driver and now it's in your network stack and then well, basically if it's here, for me, it's started to be too late. So now let's say I want to improve this a bit and we can talk about TC. TC is another way of dealing with traffic, right? And this can be attached between, let's say between the driver and the network stack. Here we can make a decision saying, well, drop the traffic but it's still like one through the driver and it's better than the network filter step, right? That we saw earlier, but it's a bit after the driver here so we can optimize this better. Now in term of optimization, here's we're talking about the XDP in this case, right? XDP is definitely running at this stage here, right? So we are talking about like way too early, which is awesome. So now bad traffic is coming to my network interface and then going all the way to my driver and here I can make this decision say, well, now, well, you know, drop that packet right there. You don't have to go anything like anywhere to network stack it's completely protecting your system and that's what XDP can offer us, for example, in the security from the security aspects but this can also apply for rerouting or forwarding packets, right? In term of load balancing, the driver itself can definitely like send traffic to a different network interface or deal with traffic super early. Okay, now let's talk more about use cases for like in terms of security. In terms of security, XDP can be used to, here's some examples, right? This is not the full, this is not the full list but this is kind of some ideas that I'm, that you can work on. For example, you can restrict certain IPs, right? Certain sources. That's this perfect for preventing the US attacks, for example, or just restricting and putting network security or network resiliency and that's like mostly security, right? No, not resiliency in this case but mostly security to protect a certain targets from a certain IPs, right? Restricting protocols, that's also important, you know, like if you don't wanna allow certain protocols to be used, let's say you have an application that is only TCP. What would you care about having UDP, for example, right? So in this case, you can just create a filter that would restrict the traffic to only TCP traffic. Other things like the DOS attacks, I think I mentioned earlier kind of a previous example, if the DOS is happening, you need to detect it early and from there you can just, you know, obviously either packet counting or anything like that, you can make a decision saying, well, now drop this traffic, you know, prevention, super early, this is awesome. And also that's part of the DOS part, you can catch with any malicious packets or anything going on that is not, for example, part of the TCP stack, you can just filter this out directly and we're gonna see kind of examples of, we're gonna see an example of this and probably more just keeping it basic, we're gonna see an example of restricted IPs. Okay, now in term of security, there's a lot of tools out there that are taking advantage of this, okay? One of the important blogs I found online, which is Cloudflare, right? Cloudflare is a solution for, you know, to help you with like basically providing your data faster. I think a lot of people know about their solutions. They are using XDP to prevent the DOS attacks and that's using directly their, you know, their mechanism where this layer here is the one protecting mostly the deploying rules, but their XDP layer is the one providing an extra layer of security here to save, you know, to prevent from the DOS attacks way early in the chain. Now, XDP for routing, there's multiple use cases here that we can talk about, but basically in term of routing, we can use XDP to forward traffic to a certain host directly or certain targets. We can route early, way too early, and I showed you guys earlier. Things for load balancing also, we can create load balancing policies where we can, you know, and we're gonna see an example of the load balancing part. You know, you can do intelligence routing, so making decisions way early again. This is not typical for any XDP, but you can do it there, and in performance. So this is really, like, XDP, again, being super early is super performance. So, you know, if you look at XDP at Meta, they are using, you know, a tool that they open source call Ketran, and this is basically their XDP tool to load balance faster. And they are saying that they gained a 10X performance over the previous generation of the load balancing just because they're using XDP. 10 times faster. This is awesome. This is pretty interesting technology to be used, especially load balancing others. Same thing for Selium, right? Selium mostly also use XDP, especially like on the North-South type traffic, right? We can make decisions there faster. We can route traffic, you know, it's way faster than other type of technologies. I'm gonna see a graph later. They don't use it, they use DC for the rest, for the East-West, but in terms of like Selium capabilities, XDP is used for the foreign traffic part. And you can see the performance gain that they got from just using XDP. First of all, who knows about Selium here? Awesome, great. Well, Selium is a CNI for Kubernetes, okay? It just allow you to route traffic and assign, actually define policies and so network policies on Kubernetes, anything that a CNI would offer. So instead of the kind of the basic Q-proxy that comes with Kubernetes directly, we'll see that, we see that Q-proxy and you see the difference here. TC is also, TC is EBPF, but still you see that XDP in terms of gain, the CPU optimization that got from the traffic is just crazy. You see that there's no even comparison between a Q-proxy here, that Q-proxy that comes with Kubernetes directly and a Selium-based XDP forwarding, right? This is a term of like almost we're doing like a triple here in terms of performance optimization. So this is why, yeah, and this is another kind of showing the same thing here. Again, I'm taking that from the documentation of Selium. You can see that L4 load balancing using XDP, you see in terms of usage used here and you see this APVS, it's just crazy. That just, we're talking about like, I don't know, 20X here. That's definitely something to look into in terms of like traffic, right? Traffic, load balancing, things like that. Okay, so this was basically the introduction to XDP and we saw that can be used for security, can be used for load balancing. Now it's actually the fun part of the workshop, I hope, of this session is to do some hands-on and try to create some policies that actually try to use some small examples to replicate everything we talked about here. All right, so it's workshop time. Again, this workshop can be done on your laptops if you are interested, right? You have just to go on this link and you're gonna be able to follow with me. If not, I can definitely, I'm just doing it, I'm gonna do it again in front of you here and if you wanna follow, that's fine. If you wanna do this workshop later, it's also an option. This link gonna be available for three days, right? If you guys wanna follow with me today and do the workshop on your own time, that's also another option. I'll complete it up to you guys. All right, so I'm gonna start here. So first thing you have to do to get access to the workshop, just click on that link, basically go to that again. Bitly XDP-Tutorial and we're gonna get to this platform where you just click on the link and go to Intro to EPP-FXDP. I'm gonna start, click on Start Track, okay? It's gonna take about two minutes to get things ready. So I'm gonna put back the link here for you to copy if you wanna start. Now, any question up to here regarding YXDP? Awesome, seems like I'm really clear, like that. Plus it's five, pretty sure like, you know. It's gonna take about two, what are you saying? I'm going back to my workshop thing. This is the platform we use called Instruct. Again, also I'm gonna talk about after this workshop, actually at the end of the workshop, I'm gonna talk about another open source tool we use called Bumblebee, okay? That's something that we are working on and allow us to create EPP-F programs easily. So this is an interesting thing to learn about if you are interested in creating EPP-F programs. In the meantime, I can actually show you guys the, if I do Bumblebee, this open source program called, it's definitely, I'm gonna show you an example later, but it helps you create and package and push EPP-F programs like you do with Docker, right? Like with Docker experience, for example, you build your Docker container image, you push it to a registry and then from registry can use Docker to either pull that image or run it. It's kind of the same thing, the same experience you can have with Bumblebee where you can create your EPP-F program, you can build it, you can package it, you can put this into an OCI image so it can be persisted into registry, like a Docker registry, and then you can pull it and run it. So it's really interesting technology if you wanna reuse this within your company for other use cases, right? Imagine you create a good EPP-F program that someone else can take advantage of, you're just gonna put it into the, you know, kind of the OCI image, you give him a link the same way you give like a Docker image link, someone to pull and to run. Okay, so it's still taking time. Great, good timing. All right, let's start. Let's get started here. Again, this environment can be available for three days. If you want to do this workshop later, don't hesitate. If you wanna do it now, again, that's an option too. All right, so here's the environments you're gonna work with. The environments we are working with here is just some Docker containers, okay? I have five, sorry. I have like a couple Docker containers if I take a look here. I have router, which basically the router is kind of the pod where I'm gonna run all my EPP-F code, my XDP code, okay? Let's kind of think about it as the load balancer pod. And that's mostly just for testing. I have a client I call the restricted client and I have another client, just client. And just the same thing. They have like curl, they have ping and ping six for IPv6 pinging. And then you have target A and target B. There are just services that return like a 200 with a message saying, hey, I'm like target B service. And a registry, which is a Docker registry. Nothing crazy, just Docker registry. Oh, connection closed, it's happening here. That's really fresh. All right. So let's, yeah, let's start. I think, so let's take an example. Let's start playing with my components here. Here, if I make a call from the, as you see here, I'm doing a call, a ping. I'm pinging the router address. So this is the IP of the router. And I'm doing a ping of that address from the client pod. I thought the client is doing a ping to the router pod. If you do this, you will see that it works fine. I'm getting response back from my router. So the client is able to talk to the router. All right. Now, let's actually do the same thing. We're exact same thing this time. Though, if you guys see the difference, this time we're using ping six, okay? So ping normal, just ping, is using IPv4. It's using the IPv4 version of the router pod. Ping six is using ping but using the IPv6 address of the router pod, okay? That's the only difference. This time I'm gonna make a call. Awesome, I'm getting data back from the router. Calling from the client can ping using IPv6 or IPv4, the router pod, which is awesome. All right, so first, this example here is about traffic filtering, okay? So what I'm gonna use XDP for in this example, let's say I wanna write some code to not allow any IPv6 traffic. And I'll just restrict and actually filter it to only let IPv4 traffic go into my router pod. So when I ping, I'm expecting ping to work but not ping six. So let's do this. Let's create some code to enforce this policy. So let's start here. I'm gonna just start by creating an empty file. And again, if you guys wanna see the configuration, you can click on configuration here. All the code you're gonna do will be here. Let's create the first step of creating an eBPF program. First thing I wanna do is to include some, actually I can't even like, yeah, I'm gonna use the C formatting. So yeah, the first thing I wanna do is just include some dependencies. They're not all needed right now. I'm just adding them because I'm gonna need them later, like in the other examples. This are usually especially like the eBPF helper and eBPF are useful for allowing us to give functions to deal with our eBPF traffic, eBPF functions. So this is the first step here, just adding dependencies, nothing important. Now let's say I wanna actually this time, plus step two, this time I'm gonna start actually writing some XDP code. Writing the same command here, so this time I'm just gonna reopen it because there's a problem when I modify file. So here, I'm gonna start writing an eBPF program. And if you guys wrote an eBPF program, you know that you need the sec macro, it's just to place actually the program into LVPF. It's not super important, but actually it's important when you deal with maps. But for function calls, it's not gonna be super important. Just give it like a name that you would distinguish how your eBPF program. Again, not a really crazy step here. Now let's actually, now let's start creating like an eBPF, like an XDP program. XDP actually has multiple packet options, like a packet drop would, to write an XDP program in eBPF, it's just a function that's return int, this int is representing one of the following functions. Either XDP drop, XDP drop mean drop the packets, okay? If I'm returning, if I return XDP drop meaning traffic needs to be dropped, XDP pass mean just like, hey, let's this traffic go through, that's fine. XDP TX is for the same network interface, so it's going back to the network interface. But actually you can modify it. XDP direct to, it's actually direct the network through another NIC. And XDP aborted, that's definitely if there is an issue we wanna just like do an abort. Usually we don't recommend using this XDP abort. So the first XDP program you're gonna create right now using, it's gonna use XDP drop. And we wanna, let's say we're gonna create an application that drops all the traffic going to that specific host. For that, we're gonna just run this command here just to get the code for the step three, which is, yeah, she's here. And you guys see, right? The creation of some XDP code here is pretty straightforward. Again, it's like a function that returns an int. It's gonna take the connection as parameter. And it's, you can use, well, this function here is BPF program just, BPF function is just to print some, any data you want. But here the important thing is like just returning XDP drop, right? So this XDP drop means that everything going through this filter will be dropped, any type of traffic. So here's the basic XDP function. All right, something else. It's definitely something else. Okay, so we're not gonna run this command. Look at this XDP filter yet. Let's do another one. This time, let's create, actually, we're gonna run the step four of my code. Instead of dropping everything, I said I wanna drop only IPv6 traffic. I wanna allow my IPv4 traffic to still go through. And here it is. Remove here, just not open it again. So you see here, this function is more, kind of more advanced than the one we saw earlier. This time, we're doing more, a bit more logic. It's getting a bit more complicated, but it's still simple to understand. So here, this function, again, XDP is returning an int. The first part we're doing is we are parsing ETAs. We know our Ethernet RTCP IP packet. And actually, if we can parse that packet, if we know that's like valid packets, then we can process it. If there's a problem, like parsing it, meaning like there's a problem with the traffic, which is just the way we're training an XDP abort. Again, this is just valid, very fine that the packet is valid. So this is kind of a type of filtering. Through this code, this would make, that just means that if, again, if the traffic is valid, let it through, if not, drop it. Actually, abort it, which is, again, a sign of something bad happening. Again, I mentioned that we have a lot of function helpers and this time, I'm using BPF and TRHC. This time, I'm using this function to just validate that if, you know, if the her pro on the ETH is not IPv6, okay? So if it's not IPv6, let it go through, right? XDP pass, meaning let the traffic go through. Well, if it's not this, meaning it's actually IPv6, this case, drop it, okay? Again, this function is pretty straightforward. If it's not IPv6, let it go through. If it's IPv6, drop it. Okay, awesome. Let's run this function. To do this, I'm just gonna, I have already a make file that compiles the code. I'm just gonna compile this traffic, this file called XDPC, which is under this, okay? And for this, it's pretty straightforward. Why do you package everything, right? And I'm gonna run it here. So here, there you go. If you see, this one here, it's basically, I'm just running a C-Lang to build my XDP program, and I'm using a BPF tool to attach the network interface, ETH0, okay? Nothing crazy, nothing complicated. Again, I have an example here, if you guys wanna copy it to do it on your own, that's also an option, but here it is. Now, we are actually running that XDP program I showed you earlier to restrict traffic to only IPv6, to only IPv4 traffic, and removing and filtering out only all the IPv6 type traffic. Meaning now, if I do the test again, like I did earlier, if you remember at the start of my workshop, I tested the calls using, I made a call using a ping and ping6. Let's do the same thing, okay? So if we do the same thing here, let's say I'm gonna make a call to my, from the client to the router, so again, the router is the container where the BPF program is running. Now, if I'm doing a call from the client to the router, we see that IPv4 traffic is good, okay? So again, this is awesome. Now, what about IPv6? If I do this call, which is, you know, this time you see that I'm getting the IPv6 address of the router and I'm calling the client, from the client I'm doing a ping6 to the router address. If I run this, you see that I'm getting destination unreachable, okay? Again, the simple program we created earlier can completely filtered out my IPv6 traffic. So my pod router now allow only IPv4 type traffic, okay? Awesome, so this is a quick, simple example of how we can use XDP to filter traffic super early on the filter, on the filter chain, right? All right, so first example, pretty easy filtering out all IPv6 traffic. Let's take a look at another example. So first time, yeah, first lab was filtering. Now we're gonna take a look at restricting. So what I mean by restricting is to use XDP to deny traffic from a certain source. This is really important if you wanna prevent like any U.S. type attack. Imagine you have a lot of packets coming to a destination. You wanna reduce the impact. You wanna secure your targets. Then you can use XDP filter for that. And in this example, I have two containers, which is client again. If you remember, I'm gonna do a Docker PS here just for you guys to remember. You see I have two containers, one called restricted client and one called client. I don't know if it's visible there from the back, but I wanna restrict the traffic coming from a restricted client, okay? I want the restricted client to not be able to talk to my router, but I want my client to still be able to talk to it, okay? So first step is just to test that everything works fine now. If I actually make, sorry, I'm gonna copy this and let's say I run it here. Here is an example where we see that basically I can call again from my client. From this client, I can call my router. This is good, this is good. Now, if I wanna make a call from my restricted client, oh, it is working, right? So that's gonna be a scenario where you wanna like white list or black list certain IPs. And you see in this case, my restricted client is still able to talk to my router endpoint. So this is not good. What I will do right now, I'm gonna create an XDP filter to completely restrict traffic from a certain IP. And for this, I'm going to, let's start here by just copying the right files. And if we go back to my configuration, the only difference now is that we're using XDPH2 for my dependencies. So it's kind of loud way to now on my XDP.C. Let's take a look at the code. I'm actually, right now, I found this example for the IP address online, which is awesome, but here is the thing. The client is, you know, we define a client to be 1722, 170, 14. That's basically how Docker is assigning my IPs. This is the real IP, that's the IP of my client. And this is the IP of the restricted client, okay? 172, 1705. Now let's write some code to kind of restrict the client, restricted client actually. So again, this is the exact same code as earlier, right? And now I'm going to add my logic. So for this, I'm gonna run this command here, going back to my terminal, just to get the new code. Step two, we go back to my configuration. Sometimes it doesn't update easily, so I'm gonna have to open it again. Yeah, so now you see, the only new step I have here is I'm parsing my IPH, you know, just to get the IP header information, okay? The same way we kind of parsed the packs earlier, this time I'm just very finding that, you know, I can get the IP address of that specific source. Now we can have, make some logic, you know, we can create some logic here around restricting the specific IP. And for that, I'm gonna run this command. I'm gonna actually, you know, get the new code for a step three. And here's the logic. Here's how I can restrict certain IPs using XDP. Oops, opened the wrong file. So here you can see that now, or is this, actually not yet. Close this one, close this one, opening this one again. Yeah, here's the logic, right? So I'm checking if my address, you know, the source address from my packets, if it's equal to the address of the restricted clients, right, then drop it. I don't want the traffic from that, you know, from that bad client. Think about that as like, not only rate limiting, but let's say, you know, geographic areas that you don't want your traffic from, or just within the same, you know, the same infrastructure, let's say all your internal traffic coming from a specific VPN address need to come through, but not all the other traffic. If you're using XDP in this case, you can drop traffic way early, okay? Then you're gonna secure it instead of using all the way up to a gateway to do this. Your actually network itself is filtering out specific traffic. And if it's not the client, it's not the client that's like a restricted client, then just let the traffic go through, okay? So here we go, go back to this, and let's actually, now that we have the code, let's actually run it. So I'm gonna run this command. They're actually gonna detach all the code we had earlier, and then attach the new one to my ETH0 interface. All right, let's make some calls like here. Let's take a look at the same thing we did earlier. Let's make a call here. Here's, I'm making a call back from my client to my IPv4 router pod. And you see that the client itself is still working, right? It's good. That's because the traffic is coming from the client. Now let's take a look at the restricted client. All right, so for the restricted client, let's make a call here. You see it's not returning anything, which is awesome. That's what we want. Now using basically XDP with restricted traffic from a specific destination from the restricted client container. So the container restricted client cannot talk to my router pod container, which is awesome. So again, second scenario, if you remember in the presentation earlier, I was talking about XDP can be used for multiple use cases. I was talking about filtering and security, and this is a quick example how XDP can be used for these two use cases, okay? Now the other thing I was talking about is load balancing and packed forwarding aspect of XDP. So let's take an example of load balancing, okay? So this time we are going to load balance using XDP between two different targets. So for this, let's go to the next lab and take a look at this load balancing example. Again, I found most of this example online. I kind of modified it to fit this workshop. There's a lot of material out there that can be used. If you want to learn XDP, there's great material. Like XDP tutorial, this repo here has a ton of examples. So if you go back here, there's like couple examples that you can just follow to learn more about how XDP can be used, different monitoring or tracing or redirecting or filtering and so on. So okay, that's good material. There's a lot of, there's some examples on the Sillian website too. There's some good talks. Like for example, the load balancing from Liz Rice was really interesting to me too, if you want to learn more things on that from actually, you know, packed forwarding and stuff like that. Let's go back to my example. Now let's actually create an XDP filter that load balance between two different targets. And first thing I'm going to do is to just see how is actually a response from my clients. If I'm talking, if the client is calling to the target app, if you guys remember also here, okay, sorry, Docker. Yes, so if you see here, I have, again, I have my client and so on, but I have also my target A and target B. And this is what the response I get from target A if I'm calling the target A service. I get just the IP of the server and I get kind of a server name here. And if I do that for target B, I'm going to get target B instead. That's pretty basic. And it's just a simple example here. And the goal of this example is to call the router. And when I call the router, it should load balance between target A and target B. Kind of a road around Robin, probabilistic around Robin approach. All right, so let's start. First step is to, well, get the code for DXDPC, back here, C plus, sorry, CSS, what's that? No, C plus plus. All right, so the only difference this time, again, it's kind of for using the same code I showed you earlier. This time I'm actually defining multiple more IPs. Defining the target B and target A and target B addresses. Again, an addition with our router and addition with the clients. So it's kind of for using the same mechanism we saw all the way here, right? Nothing crazy going all the way down here. So that's the same code. Just again, defining just these two new addresses here. All right, let's write some code now. Next step is to go to, let's add some logic around load balancing. So here's the logic. If, again, the same mechanism we used to detect an IP earlier and restrict it, we can use the same thing. We can say, well, if the packet is coming from the source address from the clients, then send that traffic with destination address is gonna be the address of a specific backend, right? And the backend, in this case, I'm either picking back in A or back in B, like 50% of the time. Like, you know, we have a 50%, I'm using this BPF K-time NS to just like randomize the fact that 50% of the time's gonna be back in A and almost 50% of the time's gonna be back in B. All right, so that's the logic and then when I make a decision, I'm just gonna switch either back in A or back in B and then I'm gonna use that address for my destination address for the packets, okay? So I have my source address as the client, my destination address is the IP of the, you know, this backend pod containers and that's pretty much it. The thing is, yeah, also for header destination, I'm gonna keep the same thing. Now, the traffic coming back, right? If I get the traffic back to the router, I wanna make sure that the destination, right, the destination of the packet needs to go back to the client, not just stop at the router, right? So this is the kind of the other part of it. Once the call is made all the way to the target, that's good, this is the load balancing part and then if the packet is coming back, it's coming back to the client, right? And I'll come back to the router. So in this case, that's the logic here, destination address, again, of the packets is not the router, but it's actually the IP client, the IP of the client. And also, the source address this time is gonna be, you know, the router. And sometimes, you know, in the IP, we need the checksum, I don't wanna get this too much, technical, I don't wanna get the aspect there to understand the different components, but here, here's the logic is easy. Again, client calling the router to a load balance between target A and target B, response coming back to, it needs to go back to the client itself. All right, let's run this code. Awesome, so if I do this, oh, well, it's kind of the same thing, let's run the one we just wrote, actually. All right, so now I have that code that I just showed you now attached to my ETH0 interface. All right, moment of the truth now. Let's take a look at an example, and there you go. So you see here, first call, we made it through, went all the way to target A, okay? Cool, so actually, we call in the router. You guys see that's where the client is not calling the target endpoint directly, it's calling that the client is talking to the router pod container, and the router is load balancing, directing traffic all the way to client A. She's great, that's what we are looking for. Now, let's actually do make another call again, and we see it's target B this time. So again, if I do the calls A, we see B, we see A, we see B, A again, B. You see now, we easily created a load balancer that is forwarding traffic straight to my target destinations, and that's one of the power of XDP. Using just a couple lines of code, we were able to direct traffic all the way down to the destination. Cool, awesome. So now, here's a couple problems we have. Here's a couple problems we have with this code, and actually, all everything I showed you earlier today. We wrote only the user space, the kernel space program. We just wrote the logic that is driving my network stack, but we didn't create any user space program to interact with that code. And this is really important because, look, if we go back to the configuration here, we're just taking an example of the data is coming back, or actually, we're making decision based on. You see here, we actually statically define the address of the client, the router, the backend A and backend B, which is not good, right? This is not the use case that you will see out there. The use case you will see is that there's a dynamic process that would find these IPs and send them back to the kernel space program to make decision based on, right? So this should not be defined this way. It should be user space program that gets the IPs or get the data or gets whatever you wanna do and be pushed down to the user, to the kernel space program, and here we can make the logic. Now, in terms of communication between user space and kernel space, then you need, we need basically what we call maps, right? The way it works in eBPF in general, if we take a look at, I don't know if I have here any, see if I have map here. Yeah, let's take a look at this example here. The way it works in XDP or in eBPF in general again, you're gonna write some code, like for example, your kernel code, and here's the, here's for example, the kernel, no, this isn't, no, actually this is good. This is the user space program. But let's go back to my example. So here's an example of like a kernel code. That's actually the same thing we kind of did today, right? We are using this XDP function to do something, but the important part here is that to send data to the user space program, we use maps, right? So the way you define a map is just a struct, you define your keys, your values definition, the max entries, the type of it, there's multiple types, you can have like a per CPU map, you can have like a ring hash and all that. So there's a different type of like maps you can use. And once you define your map, you can interact with it and you can push data into it. And there's multiple, I don't wanna get into details here, there's a way to look for an element if it exists in your map, there's a way to push data into your map. And the way it happens is that you can, this is bi-directional, so basically you can go to, to user space program. So going back to my examples here, and if I go back to my, well, my user space program was this one, and here you can write all the code you want, right? You can actually create the, like here you see the options that are, you can pass to your application. If you think about the XDP example I showed you earlier, you can write your own code that will find the IPs of the clients or find the logic you wanna do and be pushed down to your map. And then from the other side, from the Kernel space, you can get, from the, yeah, from the Kernel program, you can get the data from, for example, the IPs of the clients or things you wanna restrict. Imagine I'm gonna create an application that says, I don't know, stop traffic by IP, right? I wanna create this application. The way I'm gonna do it, I'm gonna do the same thing I showed you in lab two where I'm gonna have this process to like find an IP and basically restrict based on it. But I'm also gonna create like a user space program where I'm gonna define the logic saying, well, if I'm calling this stop traffic by IP space, this specific IP, this IP gonna be passed down all the way using the map to the Kernel space from the user space. And based on that data, I can restrict a specific target, right? So this is really important in that logic. So user space is important. A map is, again, what is used to do this communication between a user space and Kernel space. Now the problem is, the problem is like you see here, like this is like a super basic example, right? Basic one, but you see that it gets pretty complicated to do user space programming and then Kernel space programming. And if you wanna do something easy, that doesn't help you, right? Most of the time, I mean, you guys noticed, like most of the time, sometimes you wanna create a quick logic to attach like an XDP program without having to care first about the user space. Maybe you don't have to write this code. Well, actually, I just wanna have an easy way to package it, to push it, to put in the container, put in OCI image and put it down and run it. Kind of what I was talking about earlier using Bumblebee. So again, Bumblebee is an open source project that helps you create eBPF programs easy, easily. And we'll take a look at how we can, we'll use Bumblebee to create a small eBPF program and what's the advantage we have compared to kind of the approach we are taking right now. Let's go back to my tutorial and I'm just gonna go to the next lab. Here is, we're setting up the new lab for Bumblebee. And again, I'm gonna show you the repo here if you wanna learn more about it, okay? It's give you, again, it's give you kind of the same way you deal with, the same way you deal with like a Docker image, right? Docker image, what you do, again, you have a manifest, you have a file, whatever, you're building your image and then you are pushing it somewhere to a certain registry and then you can pull it, you can run it, right? It's easy, makes your life easier and all that stuff and you can also share that specific image with someone else in your company to take advantage of. Same thing with the same thing with the eBPF using Bumblebee, right? You can build your code, you can package it, you can push it in the registry, then you can have that shared to other colleagues or internal users, pull that and they can run it in their occurrences or they can run it just on their machine directly. There's multiple use cases there you can take advantage of and they invite you to dig into it. Now, let's take an example of like a small, how we can do it with Bumblebee and see how it's way faster. So, here you go. First, I can just install Bumblebee. So now have be installed like just, oh, sorry. I can make it bigger because it's kind of harder to read. So, there you go. So yeah, so now I have be installed and what I can do is I can do just B in it, right? So, again, oops. So B, oops. It's like five now. Oh, almost six, stopped working. Again, B in is gonna create my ABPF program for Stan. Then I can select what kind of language I want to use. I'm obviously now only thing supported to C, though, you know, there's options to start looking into other technologies. That would support this. Now, what type of like program I want to create? I want to create like a network type program or I want to create like a file system one. Like file system obviously can create ABPF programs to like watch who's doing something on your machine and just like either report on it or block stuff like that, right? So in this case, I just say I want to do a network one. Can do a network. Then again, I talked about maps, right? I talked about the way to like send data from the kernel to the kind of bi-directional way to send data from a user space program to a kernel space program or vice versa, right? So in this case, you can select type of map you want to use. In this case, the two options we have are either ring buffer or a hash map. I'd say I want to just start with like a, well, I don't know, ring buffer for this use case. And then you can, you know, create kind of a counter. And this is important because certain programs don't really need like a complicated user space program. You just need some sort of reporting and maybe you need some sort of way to like create like a permutinous metrics, right? Like to monitor something. Well, here we can say, well, I don't know. I just want to print. And then you can give it an example. I don't know. Let's say just foo.c. I don't care at this point, just like I want to show you an example, right? Now, okay, this is easy, but let's say I want to just start with like a real use case program, right? You know, let's say I want to create the following. So let's see if I can open it here. Let's say I want to start with the TCP connects, right? So, oh, this is crazy to look at in this font. I don't want to get into too much detail, but this is part of the libbpf tool, right? It is like an open source project. You can look at it here, bftool. And it has a lot of examples here, right? You can take a look at any example you want. This is kind of the things that you would, you know, they're already there, like, for example, you know, I know the TCP dump or, in this example here, we're looking at the TCP connect, right? So again, TCP connect. So TCP connect is an ebpf program in this case, that also have a user space program to interact with, it has a user, a kernel space program that actually just counts the TCP connections. So every time something happened between the source and the destination, it somehow reported to the user space. It's pretty complicated to look into. I don't want to already bore you guys with all the data here and how we create this. But, you know, we just need to know that it's kind of pretty complicated, especially like, you know, even like for the user space program, imagine all this code to write. Now, let's take this example and just make it so easy with Bumblebee. So again, I just grabbed only the kernel space program. That's it. Just tcpconnect.c, which is the kernel space program, no user space. I don't really care about this. Now, tcpconnect.c is here, I can build it using Bumblebee. Again, just bbuild tcpconnect.c, again, kernel space program. And actually, I'm gonna give it like the same way you do like a Docker build, you know, do a dash t and give it like a Docker registry address, kind of the same thing. Here, I have already a Docker registry running or actually can be any type of registry. Again, and I'm actually just calling it tcpconnectv1. That's it. I'm gonna run Bumblebee. That's gonna build my application and build my, you know, eppf program into an OCI image, which is great. It's kind of same thing when you do like a Docker build dash t dot, right? It's compiling the eppf program, gonna verify it if it's good and all the fun thing you expect from a tool that will simplify your life. All right, so now we have an image. Awesome. I have this local image, local host, 5,000 solo toys tcpconnectv1. Again, as I said, the same thing like you do with Docker, you can do the push of that specific image to your registry. And this is actually pushing it to the local registry we have running on my machine. But this can be your, I don't know, any registry have the same way, any OCI compatible registry. Like if you think about Docker, this is an OCI, there's Harbor, there's multiple ones. All right, now when I have my registry, I have my image in my registry, then it just matter of doing like a B run, that's it. The same way you do Docker run, right, of an image. There you go. It's gonna pull the image and gonna run it, sweet. Now I can just make calls like, you know, let's take an example of the, I don't know, if I do, I don't know, like any curl. You know, if I do curl, Google.com, it's automatically gonna register my destination address and my source address. So this is my machine calling out to my destination address, which is the Google servers. And they can actually even like, if you take a look at the, you know, Docker exact client, like we did earlier, if I do the Docker exact client, so the client's calling to my router. If you see, I'm getting back to, again, that's kind of the load balancer we were looking at earlier. And you can see here, if you go back to terminal, you can see the address. You can see that now. Actually, every time I'm making a call, it is captured and automatically, you know, incrementing my counter, saying, well, this is basically, this is the address, you know, this, oh, I don't know how to remove this thing. Yeah, you see here, 17204, that's the IP client, IP of the client, and it's talking to the router, which ends with six, right? And again, also things you can see is that now that my, if B is running, like Bumblebee, you can also make a call to the metrics or automatically generate metrics for you that you can, you know, that's probably the most compatible metrics that can be pushed to create dashboards or do signaling or do like alerting or anything that goes with it, right? So basically, in this case, we have an easy way to get metrics saying, well, this time, you know, this address called this address three times. And if you guys noticed, I get all this without even like creating anything for my user space. So if I go back to my example, I didn't write any of these, like all this user space program to do this logic completely abstracted to you. So it's speed up completely your, you know, development of ABPF programs and to make it easier to, again, package, push to registries, share, and all the things you can do it. All right, so I did the workshop in an hour 10, which is great for a long day. I know you guys are tired and especially looking at ABPF and code at six is no fine here. So yeah, again, thank you for joining this session. That was really, I know that's where it's hard to stay for this session, but really thank you for this and hope to see you soon. Do you have any questions? Oh, thank you for all your presentations. You said that we can improve the network networking performances by using ABPF and XDP. So could it happen in the future that the legacy networking stocks, that networking stocks in Linux will be no longer used and ABPF and XDP will be used as a default? Yeah, great questions. So basically what the legacy, if the legacy things will get out from the picture. Yeah, I mean, the replacement is there. ABPF, XDP is progressing a lot and we see that as a not, I don't think it's gonna be mainstream like replacement of one, like you still need your physical layer, you still need that. I think the cool thing that we see right now, specifically with XDP, we see that the code, the kernel is getting closer to kind of the physical layer and way to interact with each other. You through XDP, for example, right? Like now XDP interact directly with the driver, right? So I'm assuming in the future, the way we're gonna see you, we're gonna see you gonna see more upon standard that maybe even gonna go, I don't know, I don't think it can go any further, but this kind of two layers are easily merged together into like an interface that users like me and you can interfere with and post. So maybe not today, but yeah, in the future, we're gonna see more XDP being, XDP and anything related being kind of a mainstream thing. Yeah. All right. Again, thank you everybody. I guess time to rest, right? That was a long day for you guys. Thank you.