1 00:00:00,000 --> 00:00:11,000 I'm going to make an introduction without much ado, talking about high-speed packet filtering and Cloudflare from the London office. 2 00:00:11,280 --> 00:00:16,500 Welcome to DEF CON, and my pleasure to introduce you to Gabriel Tobler-Tinn. 3 00:00:16,740 --> 00:00:17,480 Thank you. 4 00:00:23,380 --> 00:00:27,420 Okay, good morning. Thanks, everyone, for joining me today. 5 00:00:27,420 --> 00:00:32,240 Today, we talk about past, present, and future of high-speed packet filtering on Linux. 6 00:00:32,480 --> 00:00:33,420 So, let's get started. 7 00:00:34,120 --> 00:00:36,560 About me, I'm a system engineer at Cloudflare. 8 00:00:36,700 --> 00:00:39,580 I work in the DDoS mitigation team in the London office. 9 00:00:40,300 --> 00:00:42,820 For the ones of you who don't know what Cloudflare is, 10 00:00:42,900 --> 00:00:46,980 Cloudflare is a security and performance company which offers a reverse proxy CDN service. 11 00:00:47,360 --> 00:00:52,100 So, when a site is on Cloudflare, all its traffic is routed through our edge network first, 12 00:00:52,180 --> 00:00:54,580 and then it's proxied back to the origin servers. 13 00:00:54,900 --> 00:00:56,980 This means we can provide different services, 14 00:00:56,980 --> 00:01:01,820 such as caching, content optimization, and, most importantly, for the sake of this talk, 15 00:01:01,960 --> 00:01:04,640 we can provide DDoS mitigation. 16 00:01:05,400 --> 00:01:06,960 We have a fairly large network. 17 00:01:07,220 --> 00:01:10,620 We see a lot of traffic every day, and also a lot of malicious traffic. 18 00:01:10,980 --> 00:01:15,580 And, in fact, on a daily basis, we have to deal with hundreds of different DDoS attacks. 19 00:01:16,420 --> 00:01:22,740 To give you some numbers, on a normal day, we see attacks ranging from 50 to 100 million packets per second, 20 00:01:22,860 --> 00:01:26,020 and from 50 to 250 gigabits per second. 21 00:01:26,980 --> 00:01:28,720 And, we have also seen much bigger attacks. 22 00:01:29,580 --> 00:01:35,940 These graphs, for example, show one of the biggest TCP-SIM flows we recorded a few months ago. 23 00:01:36,380 --> 00:01:40,220 The green line represents the volume of the attack traffic, 24 00:01:40,420 --> 00:01:45,200 while the small yellow line at the bottom represents the larger traffic. 25 00:01:45,540 --> 00:01:52,180 And the job of my team is to basically drop all the malicious traffic before it hits our servers, 26 00:01:52,360 --> 00:01:56,920 without affecting in any way the small portion of yellow traffic. 27 00:01:56,980 --> 00:02:00,880 So, let's start from iptables. 28 00:02:01,080 --> 00:02:06,760 In the beginning, we were relying simply on iptables to drop traffic. 29 00:02:07,320 --> 00:02:11,120 And, iptables is great for many reasons, because it's a well-known tool. 30 00:02:11,380 --> 00:02:15,340 It's relatively easy to interface with it from different programming languages. 31 00:02:15,700 --> 00:02:22,100 It has this nice concept of tables that hooks into different parts of the network stack and chains. 32 00:02:22,460 --> 00:02:26,960 It's also well integrated with the Linux kernel, and it has support for BPF management. 33 00:02:26,980 --> 00:02:33,700 Which means it's possible to use BPF bytecode to specify how a rule will be matched. 34 00:02:34,040 --> 00:02:36,520 And, this gives iptables a reasonable flexibility. 35 00:02:37,140 --> 00:02:43,080 And, speaking of BPF, in the last few years, we've been developing a set of utilities called BPF tools, 36 00:02:43,300 --> 00:02:48,720 which allows to generate on the fly BPF bytecode to match a specific class of packets. 37 00:02:49,020 --> 00:02:55,720 In this example, I'm basically generating BPF bytecode to match a specific class of TCP-SIM packets. 38 00:02:55,720 --> 00:03:02,460 And, without going too much into the details, the weird string that you can see passed through the BPFgen command 39 00:03:02,460 --> 00:03:08,980 is called pofsignature, and it's basically a short description of all the interesting fields of a TCP-SIM packet. 40 00:03:09,340 --> 00:03:12,280 And, the way we used to use iptables is the following. 41 00:03:12,520 --> 00:03:16,780 We use the usual iptables syntax to express most of the mitigation logic, 42 00:03:16,960 --> 00:03:22,360 and we resort to BPF to express those bits that cannot be expressed by just using iptables. 43 00:03:22,520 --> 00:03:23,460 And, this works great. 44 00:03:24,020 --> 00:03:25,360 But, there is a problem. 45 00:03:25,460 --> 00:03:25,700 And, there is a problem. 46 00:03:25,720 --> 00:03:29,020 With iptables, we can't handle big packet flutes. 47 00:03:29,360 --> 00:03:34,840 And, last time we checked, we could, like, do two, three million packets per second on a single box, 48 00:03:35,000 --> 00:03:38,080 leaving no CPU at all to the user space applications. 49 00:03:38,540 --> 00:03:45,140 And, this is, for us, a problem, because on our network, each server, which serves HTTP and DNS traffic, 50 00:03:45,360 --> 00:03:47,340 also participates in DDoS mitigation. 51 00:03:47,620 --> 00:03:53,860 So, we can't just afford to spend a whole box just mitigating DDoS attacks. 52 00:03:53,860 --> 00:03:59,800 There are a few Linux alternatives, but we didn't really consider any of them. 53 00:04:00,140 --> 00:04:06,920 And, the reason is that we are not just trying to squeeze some more million packets per second of DDoS mitigation capacity. 54 00:04:07,460 --> 00:04:15,180 We'd like to have a solution that we can use, that uses as little CPU as possible to filter packets at line rate. 55 00:04:16,000 --> 00:04:23,760 So, before discussing our current setup, I'd like to give you a quick introduction about the path of a network packet in the Linux kernel. 56 00:04:23,860 --> 00:04:30,160 And, this is to make it clear why it's so expensive to filter packet by just using iptables. 57 00:04:30,760 --> 00:04:37,220 So, first, let me define a couple of important data types that I will refer later during the talk. 58 00:04:37,420 --> 00:04:47,060 So, when I speak about packet buffers, the one at the bottom, I'm just referring to memory pages which contain the actual network packet. 59 00:04:47,440 --> 00:04:53,840 When I'm speaking about SKBuff, I'm speaking about a big data structure that contains a lot of memory. 60 00:04:55,680 --> 00:05:04,240 So, basically, it's just a structure that keeps the context about a specific packet while the packet is being processed by the network stack. 61 00:05:04,500 --> 00:05:16,300 And, when I'm speaking about Eric Strings, the one on the nick diagram, I'm speaking about data structures used by the network card to keep track of all the packet buffers that are actually in use. 62 00:05:17,500 --> 00:05:20,220 Okay, so how does Linux receive packets? 63 00:05:20,460 --> 00:05:22,880 Linux uses a mechanism based on polling. 64 00:05:23,860 --> 00:05:28,860 So, basically, periodically, Linux invokes the NetRx action and goes through the list of network cards. 65 00:05:29,060 --> 00:05:32,160 And, for each network card, it checks if there are new packets. 66 00:05:32,660 --> 00:05:42,320 And, the important point of this slide is that just the network driver has to do a lot of expensive operation, memory operation, to deal with the packets. 67 00:05:42,640 --> 00:05:52,240 It has to DMA and map the packet, allocate an SKBuffer, and allocate a new page for a new packet that will replace the old one. 68 00:05:52,360 --> 00:05:53,840 And, actually process the packet. 69 00:05:53,860 --> 00:05:57,180 And, in the end, free all these data structures. 70 00:05:57,380 --> 00:06:01,680 So, there is a lot of memory pressure just from the point of view of the driver. 71 00:06:02,540 --> 00:06:08,760 So, I want to really quickly go through this code trace of the network stack receiving a packet. 72 00:06:08,900 --> 00:06:14,640 Just to give you, again, a quick sense of how many operations the network stack does when it receives a packet. 73 00:06:14,840 --> 00:06:16,960 And, so, why it's so expensive to actually drop them. 74 00:06:17,180 --> 00:06:22,240 So, as I said, NetRx action is called periodically, which goes through... 75 00:06:22,240 --> 00:06:24,760 Which goes the driver function. 76 00:06:25,200 --> 00:06:27,480 And, we have to allocate SKBuffers. 77 00:06:27,640 --> 00:06:30,860 And, there is some generic receiver flow processing. 78 00:06:31,300 --> 00:06:33,320 And, this is repeated for each packet. 79 00:06:33,620 --> 00:06:37,760 Then, the driver has to allocate new pages for the new packet that will arrive. 80 00:06:38,060 --> 00:06:44,520 And, there is IP header processing, IP tables, row contract, and more contracting, routing decision. 81 00:06:45,120 --> 00:06:51,240 Finally, we encounter the IP tables chain, which is fairly late in this whole list, of course. 82 00:06:52,240 --> 00:06:57,780 And, finally, layer 4 protocol handling and IOM meeting, other things that we don't care here. 83 00:06:58,280 --> 00:07:00,100 So, what's the point of this? 84 00:07:00,300 --> 00:07:03,300 The point is that we should not say that IP tables is low. 85 00:07:03,420 --> 00:07:07,560 We should say that IP tables is just executed too late into the network stack. 86 00:07:07,760 --> 00:07:12,580 And, we have to do all these actions for each packet that we are going to drop. 87 00:07:12,700 --> 00:07:14,840 And, that's why it's so expensive to drop packets. 88 00:07:15,660 --> 00:07:20,100 And, so, we should move to our current solution, which is based on user space upload. 89 00:07:20,480 --> 00:07:22,100 And, when I say user space upload... 90 00:07:22,240 --> 00:07:26,160 I mean offloading to user space the task of dropping the packets. 91 00:07:26,860 --> 00:07:30,440 So, user space offload is based on a technique called kernel bypass. 92 00:07:31,180 --> 00:07:41,380 Kernel bypass means taking some of the network card receive and transmission rings, mapping them in user space, and allowing a user space program to deal with them. 93 00:07:41,720 --> 00:07:48,960 So, basically, partially the network card is detached from the network stack, from the Linux network stack. 94 00:07:49,120 --> 00:07:51,320 And, the user space program can take control of that. 95 00:07:51,320 --> 00:07:55,200 So, it can write packets from there and reads packets from there. 96 00:07:55,300 --> 00:08:01,780 And, one of the reasons this technique is used is to implement user space network stacks. 97 00:08:01,980 --> 00:08:08,780 Because a user space program can just read and write packets from the NIC directly without having to deal with the kernel. 98 00:08:09,760 --> 00:08:13,000 But, this technique is also useful to filter packets. 99 00:08:13,240 --> 00:08:17,660 Because you can map a receive ring in user space. 100 00:08:17,920 --> 00:08:21,300 And, a user space program can start reading all the packets. 101 00:08:21,320 --> 00:08:24,760 From there, without any interference from the kernel. 102 00:08:25,080 --> 00:08:32,360 And, then the user space program can filter, actually, what are just buffers of packets. 103 00:08:32,920 --> 00:08:43,320 So, the way this works is by just selectively offloading the attack traffic to a specific receive queue. 104 00:08:43,780 --> 00:08:48,860 And, then after that, a user space program will be able to read the packets from the queue. 105 00:08:48,860 --> 00:08:53,900 And, if the packet is a good one, it will just be re-injected into the network stack. 106 00:08:54,140 --> 00:08:59,500 And, if it is a malicious one, there is nothing to do, really, because of the way this framework works. 107 00:08:59,720 --> 00:09:05,320 So, instead of having to allocate and de-allocate packet buffers, like the Linux kernel does, 108 00:09:05,900 --> 00:09:09,000 this framework usually uses circular buffers. 109 00:09:09,100 --> 00:09:12,720 So, there is no real work to do in case we are dropping packets. 110 00:09:13,000 --> 00:09:18,280 And, since, in case of big floods, we are dropping, like, 90%, 99% of the traffic, 111 00:09:18,280 --> 00:09:20,580 this is a big save in terms of performance. 112 00:09:22,460 --> 00:09:27,740 So, we use a technique called partial kernel bypass, because we keep the network card, 113 00:09:28,320 --> 00:09:33,200 most of the receive rings attached to the kernel network stack. 114 00:09:33,420 --> 00:09:37,060 And, we bypass only a single or a couple of receive rings. 115 00:09:37,340 --> 00:09:40,620 And, we use what is called an RxFlowHash rule. 116 00:09:40,800 --> 00:09:45,480 So, basically, we try to steer all the potential traffic to a RxQueue. 117 00:09:45,520 --> 00:09:47,480 In this case, RxQueue. 118 00:09:48,380 --> 00:09:49,900 And, then we filter it. 119 00:09:50,120 --> 00:09:55,980 And, when I say potential bad traffic, I mean, for example, traffic that is targeting a specific destination IP. 120 00:09:56,320 --> 00:10:00,000 So, we can leave the kernel work on the normal traffic, as usual, 121 00:10:00,100 --> 00:10:02,560 and we can filter in user space the bad traffic. 122 00:10:03,520 --> 00:10:07,140 So, there are a bunch of, like, different frameworks to do this, 123 00:10:07,200 --> 00:10:09,500 that do exactly, more or less, the same thing. 124 00:10:09,940 --> 00:10:13,500 And, in fact, from the user space point of view, 125 00:10:14,300 --> 00:10:18,200 the way a user space filter is done is the following. 126 00:10:18,280 --> 00:10:22,640 So, a user space program keeps asking the network card for new packets. 127 00:10:22,900 --> 00:10:28,160 And, as soon as there is a new packet, the program goes through a list of rules. 128 00:10:28,420 --> 00:10:33,100 And, if any of them is a drop, the packet is dropped, which means we do nothing. 129 00:10:33,540 --> 00:10:37,280 And, if a packet is not a match for the rule, it means it's a good one, 130 00:10:37,400 --> 00:10:40,340 and so we reinject it in the network stack. 131 00:10:41,740 --> 00:10:47,840 So, this solution works great, because we can, like, filter six to eight million packets per second 132 00:10:47,840 --> 00:10:48,260 on a single packet. 133 00:10:48,280 --> 00:10:51,680 Compared to two, three million packets on a whole box. 134 00:10:51,840 --> 00:10:54,160 So, this is a great performance gain. 135 00:10:54,820 --> 00:10:58,380 But, unfortunately, there are some limitations about this solution, 136 00:10:58,580 --> 00:11:01,360 because legit traffic has to be reinjected, 137 00:11:01,380 --> 00:11:06,760 and this can be, sometimes, expensive, depending on the framework that we are using. 138 00:11:07,660 --> 00:11:11,400 One or more cards have to be reserved completely for this kind of thing, 139 00:11:11,500 --> 00:11:15,600 because the way we do it is by busy polling the NIC, 140 00:11:15,700 --> 00:11:18,260 and this is because we want to keep the latency as low as possible. 141 00:11:18,260 --> 00:11:22,860 And, also, you have to pay a lot of kernel space and user space content switches 142 00:11:22,860 --> 00:11:27,080 every time you move from kernel to your filtering user space program. 143 00:11:28,140 --> 00:11:32,000 And so, the future, XDP, or Express Data Path. 144 00:11:32,640 --> 00:11:37,100 So, XDP is a new technology recently introduced in the Linux kernel, 145 00:11:37,280 --> 00:11:41,580 and it's a concrete alternative to IP tables or user space offload. 146 00:11:41,800 --> 00:11:46,680 And the idea is to filter network packets as soon as they are received by the network card. 147 00:11:46,680 --> 00:11:52,080 So, using an eBPF program, which will take as input a packet, 148 00:11:52,280 --> 00:11:56,180 and it will produce as output what is called an XDP action, 149 00:11:56,340 --> 00:12:00,380 which can be XDP pass, so the packet should proceed to the network stack, 150 00:12:00,860 --> 00:12:02,740 XDP drop, so the packet should be dropped, 151 00:12:02,880 --> 00:12:06,380 and there are even other actions and other cool things that you can do with XDP, 152 00:12:06,520 --> 00:12:08,700 but that we don't care today. 153 00:12:09,480 --> 00:12:13,300 So, if you remember the five long slides call trace, 154 00:12:13,560 --> 00:12:15,680 this is where XDP is run. 155 00:12:16,680 --> 00:12:20,580 It's just at the beginning, just as soon as you receive a packet inside the network driver. 156 00:12:20,920 --> 00:12:25,380 So, before even allocating SKBs, you run your eBPF program, 157 00:12:25,620 --> 00:12:30,860 and you decide if you want to leave the packet flowing through the network stack, 158 00:12:30,980 --> 00:12:32,900 or you want to just drop it. 159 00:12:33,300 --> 00:12:37,640 And if we take a look at one of the drivers that implemented XDP, 160 00:12:37,860 --> 00:12:44,420 we can see how the XDP drop actions is actually similar to what we are already doing with user space offload. 161 00:12:44,660 --> 00:12:46,660 Because, basically, there is nothing to do with it. 162 00:12:46,680 --> 00:12:51,160 If you want to drop the packet, you just leave, you just do nothing. 163 00:12:51,320 --> 00:12:55,200 You just leave the packet buffer where it is in the network card ring, 164 00:12:55,300 --> 00:12:56,640 and you go to the next packet. 165 00:12:56,820 --> 00:13:03,540 So, there is no memory allocation, the allocation cost at all. 166 00:13:04,600 --> 00:13:08,000 Yeah, so XDP has the same advantages as user space offload. 167 00:13:08,180 --> 00:13:09,920 There is no kernel processing involved, 168 00:13:10,100 --> 00:13:13,580 and there is no memory allocation and allocation cost, 169 00:13:13,740 --> 00:13:16,220 no DMMA map and map cost, 170 00:13:16,220 --> 00:13:17,660 which is a very expensive operation. 171 00:13:18,100 --> 00:13:20,760 But also, it has a couple of other advantages, 172 00:13:20,860 --> 00:13:25,460 because you can use eBPF to program your filtering logic, 173 00:13:25,640 --> 00:13:27,800 and there is no need to re-inject packets, 174 00:13:28,000 --> 00:13:31,420 because if a packet is not going to be dropped, 175 00:13:31,820 --> 00:13:34,600 it will just go through the network stack the usual way. 176 00:13:35,460 --> 00:13:39,120 So, let me spend a couple of words about eBPF. 177 00:13:39,480 --> 00:13:42,840 So, eBPF is kind of new. 178 00:13:42,880 --> 00:13:45,220 I think it is two years old technology. 179 00:13:45,220 --> 00:13:48,200 In the Linux kernel, which is gaining more and more traction 180 00:13:48,200 --> 00:13:51,420 in multiple subsystems in the Linux kernel, 181 00:13:51,580 --> 00:13:54,060 for example, in the tracing subsystem. 182 00:13:54,380 --> 00:13:58,920 And it's an extension to the classical BPF, 183 00:13:59,000 --> 00:14:01,460 and it's close to a real CPU architecture, 184 00:14:01,840 --> 00:14:05,040 and in fact, it's also jitted on many different architectures. 185 00:14:05,260 --> 00:14:08,020 But the great things of eBPF is that 186 00:14:08,020 --> 00:14:12,160 it provides safe memory access guarantees and time-bounded execution. 187 00:14:12,640 --> 00:14:14,820 So, when you load an eBPF program, 188 00:14:14,820 --> 00:14:17,820 in your kernel, you know that it will be as safe 189 00:14:17,820 --> 00:14:19,340 as running a program in user space, 190 00:14:19,540 --> 00:14:22,760 because the program cannot access random region in the kernel, 191 00:14:22,960 --> 00:14:25,340 and the program is guaranteed to terminate, 192 00:14:25,460 --> 00:14:28,240 because no backward jumps are allowed. 193 00:14:28,680 --> 00:14:31,140 In fact, every time you load an eBPF program, 194 00:14:31,680 --> 00:14:34,120 the kernel will run a verifier, 195 00:14:34,380 --> 00:14:38,740 and if your program does not meet any of these guarantees, 196 00:14:38,980 --> 00:14:40,180 it is just rejected. 197 00:14:40,960 --> 00:14:44,200 And also, eBPF provides shared maps 198 00:14:44,200 --> 00:14:48,560 with user space, so you can have some kind of state 199 00:14:48,560 --> 00:14:52,340 shared between your XDP program and user space. 200 00:14:52,780 --> 00:14:56,680 And another great thing is that there is an LLVM backend compiler, 201 00:14:57,540 --> 00:15:00,080 so basically you can write your C program 202 00:15:00,080 --> 00:15:03,160 and compile it to eBPF and then load it in the kernel, 203 00:15:03,300 --> 00:15:04,480 which is super handy. 204 00:15:05,000 --> 00:15:08,240 And, okay, so this is not an XDP tutorial, 205 00:15:08,420 --> 00:15:12,360 but I just wanted to show you a quick sample of an XDP program. 206 00:15:12,360 --> 00:15:15,380 In this case, we are... 207 00:15:15,380 --> 00:15:17,300 This is a super simple example. 208 00:15:18,040 --> 00:15:21,460 An XDP program is the function that is called on each packet. 209 00:15:21,680 --> 00:15:23,480 It receives as input a context, 210 00:15:23,640 --> 00:15:26,140 which is just a couple of pointers 211 00:15:26,140 --> 00:15:28,000 to the begin and the end of the packet. 212 00:15:28,480 --> 00:15:31,340 And then we can just access the packet 213 00:15:31,340 --> 00:15:33,340 using the Linux kernel data structures 214 00:15:33,340 --> 00:15:34,580 that are already there. 215 00:15:34,940 --> 00:15:38,100 And so an important thing to notice 216 00:15:38,100 --> 00:15:41,520 is that we are actually making sure 217 00:15:41,520 --> 00:15:46,980 that the program is not reading past the buffers, 218 00:15:47,000 --> 00:15:48,020 the packet buffer boundaries. 219 00:15:48,300 --> 00:15:51,200 Otherwise, it would be not possible, 220 00:15:51,260 --> 00:15:53,680 not even possible to load the kernel, the program, 221 00:15:53,880 --> 00:15:55,760 because the kernel would comply. 222 00:15:56,640 --> 00:15:58,640 And then we can go on and check 223 00:15:58,640 --> 00:16:00,340 that the packet is an AP packet 224 00:16:00,340 --> 00:16:02,900 and access the AP header and make sure, again, 225 00:16:03,000 --> 00:16:05,020 that we are not writing past the buffers 226 00:16:05,020 --> 00:16:10,940 and return an action based on the filtering logic that we use. 227 00:16:11,920 --> 00:16:14,100 Okay, the second thing is maps. 228 00:16:14,300 --> 00:16:15,500 So I talked about maps, 229 00:16:15,620 --> 00:16:17,520 and they are super simple to use. 230 00:16:17,680 --> 00:16:18,680 So you define it. 231 00:16:18,740 --> 00:16:20,880 You define the size of the key of the values 232 00:16:20,880 --> 00:16:22,120 and the size of the map. 233 00:16:22,500 --> 00:16:24,580 And then using BPF helpers, 234 00:16:24,620 --> 00:16:28,320 you can just access a specific key 235 00:16:28,320 --> 00:16:29,400 and set the value, 236 00:16:29,560 --> 00:16:32,420 and so it's just like a normal hash table, 237 00:16:32,540 --> 00:16:34,120 and it's shared with user space. 238 00:16:35,480 --> 00:16:38,180 And the great thing is that we can, of course, 239 00:16:38,260 --> 00:16:39,780 auto-generate XDP programs 240 00:16:39,780 --> 00:16:41,400 because it's just C. 241 00:16:41,520 --> 00:16:43,540 So it's easy to write a script 242 00:16:43,540 --> 00:16:46,960 and actually generate C code for you automatically. 243 00:16:47,320 --> 00:16:49,940 And in this case, I'm generating the same, 244 00:16:50,800 --> 00:16:53,540 the program for the same puff signature 245 00:16:53,540 --> 00:16:55,620 I showed you before with BPF tools. 246 00:16:55,820 --> 00:17:00,040 But instead of, like, outputting cryptic BPF bytecode, 247 00:17:00,140 --> 00:17:01,860 we can output actual C code 248 00:17:01,860 --> 00:17:04,980 and then compile it to eBPF and just load it. 249 00:17:05,160 --> 00:17:08,140 So I will not go through the whole code, 250 00:17:08,220 --> 00:17:10,240 but you can just, 251 00:17:10,240 --> 00:17:12,520 you can access different header, 252 00:17:12,720 --> 00:17:13,500 the IP header, 253 00:17:13,660 --> 00:17:16,400 and the TCP fields that you are interested in. 254 00:17:17,760 --> 00:17:20,240 So if you are curious and you want to try it, 255 00:17:20,340 --> 00:17:22,080 the first thing to keep in mind 256 00:17:22,080 --> 00:17:24,400 is that XDP is a new technology, as I said, 257 00:17:24,400 --> 00:17:27,380 so it requires supporting drivers. 258 00:17:27,820 --> 00:17:33,920 So as initially only the Mellanox card supported it, 259 00:17:34,000 --> 00:17:36,100 and now that at each kernel release, 260 00:17:36,180 --> 00:17:39,580 there are new drivers that get support for XDP. 261 00:17:40,240 --> 00:17:42,440 But starting from Linux 4.12, 262 00:17:43,300 --> 00:17:46,340 there is a new feature called generic XDP, 263 00:17:46,520 --> 00:17:50,460 so even if you don't have one of these nice network cards, 264 00:17:50,580 --> 00:17:52,780 you can just run XDP on your laptop 265 00:17:52,780 --> 00:17:55,420 and just play with it and see how it works. 266 00:17:56,240 --> 00:17:59,600 There are some samples in the kernel directory, 267 00:17:59,840 --> 00:18:01,980 so in slash samples slash BPF, 268 00:18:02,020 --> 00:18:04,780 you will find some XDP programs, 269 00:18:05,040 --> 00:18:08,020 and there are also a couple of libraries 270 00:18:08,020 --> 00:18:10,100 that will help you load, 271 00:18:10,240 --> 00:18:12,180 and manage the XDP programs. 272 00:18:13,460 --> 00:18:15,540 And that's all for me. 273 00:18:16,220 --> 00:18:17,400 So questions? 274 00:18:24,060 --> 00:18:24,900 Yes? 275 00:18:28,020 --> 00:18:30,680 How many filters can you load with XDP? 276 00:18:32,860 --> 00:18:34,540 So you... 277 00:18:34,540 --> 00:18:35,420 Okay. 278 00:18:35,520 --> 00:18:37,740 How many filters can you load with XDP? 279 00:18:38,120 --> 00:18:39,960 XDP uses eBPF. 280 00:18:40,240 --> 00:18:44,720 eBPF has an art code size of 4096 instructions, 281 00:18:45,540 --> 00:18:49,480 so as long as you can stay in that size of the program, 282 00:18:49,720 --> 00:18:53,180 you can chain multiple XDP functions, 283 00:18:53,600 --> 00:18:54,560 you can do whatever you want. 284 00:18:54,740 --> 00:18:57,460 You can even change that limit if you know what you're doing. 285 00:18:57,780 --> 00:19:01,480 But the idea is that you should try to keep the eBPF program short 286 00:19:01,480 --> 00:19:03,860 because it's running in kernel space, 287 00:19:04,120 --> 00:19:07,240 so you don't want to hang the whole kernel while processing packets. 288 00:19:08,900 --> 00:19:13,820 Do you make a distinction for V4 packets and V6 packets? 289 00:19:14,000 --> 00:19:16,080 Are those two separate programs or is it the same program? 290 00:19:17,120 --> 00:19:18,760 This is up to you, 291 00:19:18,840 --> 00:19:20,080 but you can, for example, 292 00:19:20,280 --> 00:19:22,540 start processing the different header 293 00:19:22,540 --> 00:19:25,560 and then check which version of IP you're dealing with 294 00:19:25,560 --> 00:19:27,360 and then call another function 295 00:19:27,360 --> 00:19:28,620 because you can... 296 00:19:28,620 --> 00:19:29,300 it's just C, 297 00:19:29,400 --> 00:19:31,640 so you can chain multiple functions 298 00:19:31,640 --> 00:19:33,100 as you would write in C. 299 00:19:37,240 --> 00:19:39,960 Did you explore mangle and raw before going this whole route? 300 00:19:40,200 --> 00:19:43,480 Did you explore mangle and raw tables and IP tables 301 00:19:43,480 --> 00:19:46,920 before jumping out and doing the direct? 302 00:19:47,980 --> 00:19:49,700 If I did... 303 00:19:49,700 --> 00:19:51,540 Are the mangle and raw chains 304 00:19:51,540 --> 00:19:54,460 that happened before processing... 305 00:19:54,460 --> 00:19:54,560 No. 306 00:19:54,680 --> 00:19:59,140 The two IP tables chain happened after XDP. 307 00:19:59,380 --> 00:19:59,580 Okay. 308 00:20:04,440 --> 00:20:05,080 Okay. 309 00:20:08,100 --> 00:20:09,420 No more questions, 310 00:20:09,700 --> 00:20:11,600 so thank you.