@@ -100,7 +100,12 @@ pub unsafe trait Pod: Sized {
100100/// Configures TX checksum offload when setting TX metadata via [`Packet::set_tx_metadata`]
101101pub enum CsumOffload {
102102 /// Requests checksum offload
103- Request ( libc:: xdp:: xsk_tx_request ) ,
103+ Request {
104+ /// The offset from the start of the packet where the checksum calculation should start
105+ start : u16 ,
106+ /// The offset from `start` where the checksum should be stored
107+ offset : u16 ,
108+ } ,
104109 /// Offload is not requested
105110 None ,
106111}
@@ -169,12 +174,34 @@ impl Packet {
169174 }
170175
171176 /// The number of initialized/valid bytes in the packet
177+ ///
178+ /// # Examples
179+ ///
180+ /// ```
181+ /// # let mut buf = [0u8; 2 * 1024];
182+ /// # let mut packet = xdp::Packet::testing_new(&mut buf);
183+ ///
184+ /// assert_eq!(0, packet.len());
185+ /// packet.insert(0, &[2; 21]).expect("failed to insert slice");
186+ /// assert_eq!(21, packet.len());
187+ /// ```
172188 #[ inline]
173189 pub fn len ( & self ) -> usize {
174190 self . tail - self . head
175191 }
176192
177193 /// True if the packet is empty
194+ ///
195+ /// # Examples
196+ ///
197+ /// ```
198+ /// # let mut buf = [0u8; 2 * 1024];
199+ /// # let mut packet = xdp::Packet::testing_new(&mut buf);
200+ ///
201+ /// assert!(packet.is_empty());
202+ /// packet.insert(0, &[1]).expect("failed to insert slice");
203+ /// assert!(!packet.is_empty());
204+ /// ```
178205 #[ inline]
179206 pub fn is_empty ( & self ) -> bool {
180207 self . head == self . tail
@@ -184,29 +211,54 @@ impl Packet {
184211 ///
185212 /// Note that this never includes the [`libc::xdp::XDP_PACKET_HEADROOM`]
186213 /// part of every packet
214+ ///
215+ /// # Examples
216+ ///
217+ /// ```
218+ /// let mut umem = xdp::Umem::map(
219+ /// xdp::umem::UmemCfgBuilder::default().build().unwrap()
220+ /// ).expect("failed to map Umem");
221+ ///
222+ /// unsafe {
223+ /// let packet = umem.alloc().expect("failed to allocate packet");
224+ /// // The default size is 4k (page size)
225+ /// assert_eq!(packet.capacity(), 4 * 1024 - xdp::libc::xdp::XDP_PACKET_HEADROOM as usize);
226+ /// }
227+ /// ```
187228 #[ inline]
188229 pub fn capacity ( & self ) -> usize {
189230 self . capacity
190231 }
191232
192233 /// Resets the tail of this packet, causing it to become empty
234+ ///
235+ /// # Examples
236+ ///
237+ /// ```
238+ /// # let mut buf = [0u8; 2 * 1024];
239+ /// # let mut packet = xdp::Packet::testing_new(&mut buf);
240+ ///
241+ /// assert!(packet.is_empty());
242+ /// packet.insert(0, &[2; 21]).expect("failed to insert slice");
243+ /// packet.clear();
244+ /// assert!(packet.is_empty());
245+ /// ```
193246 #[ inline]
194247 pub fn clear ( & mut self ) {
195248 self . tail = self . head ;
196249 }
197250
198- /// If true, this packet is partial , and the next packet in the RX continues
199- /// this packet, until this returns fals
251+ /// If true, this packet is fragmented , and the next packet in the queue
252+ /// continues this packet, until this returns `false`
200253 #[ inline]
201254 pub fn is_continued ( & self ) -> bool {
202255 ( self . options & libc:: xdp:: XdpPktOptions :: XDP_PKT_CONTD ) != 0
203256 }
204257
258+ // TODO: Create a different type to indicate checksum since it's not going
259+ // to change so the user can choose at init time whether they want checksum
260+ // offload or not
205261 /// Checks if the NIC this packet is being sent on supports tx checksum offload
206- ///
207- /// TODO: Create a different type to indicate checksum since it's not going
208- /// to change so the user can choose at init time whether they want checksum
209- /// offload or not
210262 #[ inline]
211263 pub fn can_offload_checksum ( & self ) -> bool {
212264 ( self . options & libc:: InternalXdpFlags :: SUPPORTS_CHECKSUM_OFFLOAD ) != 0
@@ -219,6 +271,38 @@ impl Packet {
219271 /// to copy the entirety of the packet data up or down.
220272 ///
221273 /// Adjusting the head down requires that headroom was configured for the [`crate::Umem`]
274+ ///
275+ /// # Examples
276+ ///
277+ /// ```
278+ /// let mut umem = xdp::Umem::map(
279+ /// xdp::umem::UmemCfgBuilder {
280+ /// head_room: 20,
281+ /// ..Default::default()
282+ /// }.build().unwrap()
283+ /// ).expect("failed to map Umem");
284+ ///
285+ /// unsafe {
286+ /// let mut packet = umem.alloc().expect("failed to allocate packet");
287+ ///
288+ /// // We can't extend the head past the tail, so first insert some data
289+ /// packet.insert(0, &[0xff; 33]).unwrap();
290+ /// assert_eq!(33, packet.len());
291+ ///
292+ /// // Adjust the head up to match the tail, making the packet empty
293+ /// packet.adjust_head(33).unwrap();
294+ /// assert!(packet.is_empty());
295+ ///
296+ /// // When using alloc, the head is already adjust to the headroom, the
297+ /// // same as the kernel would do when receiving a packet, so we can
298+ /// // adjust the head down further
299+ /// packet.adjust_head(-53).unwrap();
300+ /// assert_eq!(53, packet.len());
301+ ///
302+ /// // ...but no further
303+ /// assert!(packet.adjust_head(-1).is_err());
304+ /// }
305+ /// ```
222306 #[ inline]
223307 pub fn adjust_head ( & mut self , diff : i32 ) -> Result < ( ) , PacketError > {
224308 if diff < 0 {
@@ -247,6 +331,32 @@ impl Packet {
247331 ///
248332 /// This method is the equivalent of [`bpf_xdp_adjust_tail`](https://docs.ebpf.io/linux/helper-function/bpf_xdp_adjust_tail/),
249333 /// and allows extending or truncating the data portion of a packet
334+ ///
335+ /// # Examples
336+ ///
337+ /// ```
338+ /// let mut umem = xdp::Umem::map(
339+ /// xdp::umem::UmemCfgBuilder {
340+ /// head_room: 20,
341+ /// ..Default::default()
342+ /// }.build().unwrap()
343+ /// ).expect("failed to map Umem");
344+ ///
345+ /// unsafe {
346+ /// let mut packet = umem.alloc().expect("failed to allocate packet");
347+ /// packet.insert(0, &[0xff; 10]).unwrap();
348+ /// assert_eq!(10, packet.len());
349+ ///
350+ /// for _ in 0..10 {
351+ /// packet.adjust_tail(-1).expect("failed to reduce tail");
352+ /// }
353+ ///
354+ /// assert!(packet.is_empty());
355+ ///
356+ /// packet.adjust_tail(10).expect("failed to extend the tail");
357+ /// assert_eq!(&packet[..10], &[0xff; 10]);
358+ /// }
359+ /// ```
250360 #[ inline]
251361 pub fn adjust_tail ( & mut self , diff : i32 ) -> Result < ( ) , PacketError > {
252362 if diff < 0 {
@@ -277,6 +387,40 @@ impl Packet {
277387 ///
278388 /// - The offset is not within bounds
279389 /// - The offset + size of `T` is not within bounds
390+ ///
391+ /// # Examples
392+ ///
393+ /// ```
394+ /// use xdp::packet::net_types;
395+ /// use std::net::Ipv4Addr;
396+ /// # use xdp::packet::Pod;
397+ /// # let mut umem = xdp::Umem::map(
398+ /// # xdp::umem::UmemCfgBuilder {
399+ /// # head_room: 20,
400+ /// # ..Default::default()
401+ /// # }.build().unwrap()
402+ /// # ).expect("failed to map Umem");
403+ /// # let mut packet = unsafe {
404+ /// # let mut packet = umem.alloc().expect("failed to allocate packet");
405+ /// # packet.adjust_tail(34).unwrap();
406+ /// # packet.write(0, net_types::EthHdr {
407+ /// # source: net_types::MacAddress([1; 6]),
408+ /// # destination: net_types::MacAddress([2; 6]),
409+ /// # ether_type: net_types::EtherType::Ipv4 }
410+ /// # ).unwrap();
411+ /// # let mut ip = net_types::Ipv4Hdr::zeroed();
412+ /// # ip.reset(64, net_types::IpProto::Udp);
413+ /// # ip.source = u32::from_be_bytes([100, 1, 2, 100]).into();
414+ /// # ip.destination = u32::from_be_bytes([200, 2, 1, 200]).into();
415+ /// # packet.write(net_types::EthHdr::LEN, ip).unwrap();
416+ /// # assert_eq!(packet.len(), net_types::EthHdr::LEN + net_types::Ipv4Hdr::LEN);
417+ /// # packet
418+ /// # };
419+ /// // Read an Ipv4 header, which directly follows an Ethernet II header
420+ /// let ip_hdr = packet.read::<net_types::Ipv4Hdr>(net_types::EthHdr::LEN).unwrap();
421+ /// assert_eq!(ip_hdr.source.host(), Ipv4Addr::new(100, 1, 2, 100).to_bits());
422+ /// assert_eq!(ip_hdr.destination.host(), Ipv4Addr::new(200, 2, 1, 200).to_bits());
423+ /// ```
280424 #[ inline]
281425 pub fn read < T : Pod > ( & self , offset : usize ) -> Result < T , PacketError > {
282426 let start = self . head + offset;
@@ -309,6 +453,50 @@ impl Packet {
309453 ///
310454 /// - The offset is not within bounds
311455 /// - The offset + size of `T` is not within bounds
456+ ///
457+ /// # Examples
458+ ///
459+ /// ```
460+ /// use xdp::packet::net_types;
461+ /// use std::net::Ipv4Addr;
462+ /// # use xdp::packet::Pod;
463+ /// # let mut umem = xdp::Umem::map(
464+ /// # xdp::umem::UmemCfgBuilder {
465+ /// # head_room: 0,
466+ /// # ..Default::default()
467+ /// # }.build().unwrap()
468+ /// # ).expect("failed to map Umem");
469+ /// # let mut packet = unsafe {
470+ /// # umem.alloc().expect("failed to allocate packet")
471+ /// # };
472+ /// // Extend the tail so we have enough space for the writes
473+ /// packet.adjust_tail(42).unwrap();
474+ ///
475+ /// packet.write(0, net_types::EthHdr {
476+ /// source: net_types::MacAddress([1; 6]),
477+ /// destination: net_types::MacAddress([2; 6]),
478+ /// ether_type: net_types::EtherType::Ipv4 }
479+ /// ).expect("failed to write ethhdr");
480+ ///
481+ /// let mut ip = net_types::Ipv4Hdr::zeroed();
482+ /// ip.reset(64, net_types::IpProto::Udp);
483+ /// ip.source = u32::from_be_bytes([100, 1, 2, 100]).into();
484+ /// ip.destination = u32::from_be_bytes([200, 2, 1, 200]).into();
485+ /// ip.total_length = ((net_types::Ipv4Hdr::LEN + net_types::UdpHdr::LEN + 5) as u16).into();
486+ /// packet.write(net_types::EthHdr::LEN, ip).expect("failed to write ip hdr");
487+ ///
488+ /// packet.write(net_types::EthHdr::LEN + net_types::Ipv4Hdr::LEN, net_types::UdpHdr {
489+ /// source: 50000.into(),
490+ /// destination: 80.into(),
491+ /// length: ((net_types::UdpHdr::LEN + 5) as u16).into(),
492+ /// check: 0,
493+ /// }).expect("failed to write ip hdr");
494+ ///
495+ /// packet.insert(
496+ /// net_types::EthHdr::LEN + net_types::Ipv4Hdr::LEN + net_types::UdpHdr::LEN,
497+ /// &[0xf0; 5]
498+ /// ).unwrap();
499+ /// ```
312500 #[ inline]
313501 pub fn write < T : Pod > ( & mut self , offset : usize , item : T ) -> Result < ( ) , PacketError > {
314502 let start = self . head + offset;
@@ -344,6 +532,28 @@ impl Packet {
344532 ///
345533 /// - The offset is not within bounds
346534 /// - The offset + `N` is not within bounds
535+ ///
536+ /// # Examples
537+ ///
538+ /// ```
539+ /// # use xdp::packet::Pod;
540+ /// # let mut umem = xdp::Umem::map(
541+ /// # xdp::umem::UmemCfgBuilder {
542+ /// # head_room: 0,
543+ /// # ..Default::default()
544+ /// # }.build().unwrap()
545+ /// # ).expect("failed to map Umem");
546+ /// # let mut packet = unsafe {
547+ /// # umem.alloc().expect("failed to allocate packet")
548+ /// # };
549+ /// // Insert a u32
550+ /// packet.insert(0, &0xaabbccddu32.to_ne_bytes()).unwrap();
551+ ///
552+ /// let mut bytes = [0u8; 4];
553+ /// packet.array_at_offset(0, &mut bytes).unwrap();
554+ ///
555+ /// assert_eq!(u32::from_ne_bytes(bytes), 0xaabbccddu32);
556+ /// ```
347557 #[ inline]
348558 pub fn array_at_offset < const N : usize > (
349559 & self ,
@@ -377,6 +587,36 @@ impl Packet {
377587 ///
378588 /// - The offset is not within bounds
379589 /// - The offset + `slice.len()` would exceed the capacity
590+ ///
591+ /// # Examples
592+ ///
593+ /// ```
594+ /// # use xdp::packet::Pod;
595+ /// # let mut umem = xdp::Umem::map(
596+ /// # xdp::umem::UmemCfgBuilder {
597+ /// # head_room: 0,
598+ /// # ..Default::default()
599+ /// # }.build().unwrap()
600+ /// # ).expect("failed to map Umem");
601+ /// # let mut packet = unsafe {
602+ /// # umem.alloc().expect("failed to allocate packet")
603+ /// # };
604+ /// // Insert a u32
605+ /// packet.insert(0, &0xf0f1f2f3u32.to_ne_bytes()).unwrap();
606+ ///
607+ /// // Insert a u64
608+ /// packet.insert(0, &u64::MAX.to_ne_bytes()).unwrap();
609+ ///
610+ /// let mut bytes = [0u8; 8];
611+ /// packet.array_at_offset(0, &mut bytes).unwrap();
612+ ///
613+ /// assert_eq!(u64::from_ne_bytes(bytes), u64::MAX);
614+ ///
615+ /// let mut bytes = [0u8; 4];
616+ /// packet.array_at_offset(8, &mut bytes).unwrap();
617+ ///
618+ /// assert_eq!(u32::from_ne_bytes(bytes), 0xf0f1f2f3);
619+ /// ```
380620 #[ inline]
381621 pub fn insert ( & mut self , offset : usize , slice : & [ u8 ] ) -> Result < ( ) , PacketError > {
382622 if self . tail + slice. len ( ) > self . capacity {
@@ -454,9 +694,12 @@ impl Packet {
454694 unsafe {
455695 let mut tx_meta = std:: mem:: zeroed :: < xdp:: xsk_tx_metadata > ( ) ;
456696
457- if let CsumOffload :: Request ( csum_req ) = csum {
697+ if let CsumOffload :: Request { start , offset } = csum {
458698 tx_meta. flags |= xdp:: XdpTxFlags :: XDP_TXMD_FLAGS_CHECKSUM ;
459- tx_meta. offload . request = csum_req;
699+ tx_meta. offload . request = xdp:: xsk_tx_request {
700+ csum_start : start,
701+ csum_offset : offset,
702+ } ;
460703 }
461704
462705 if request_timestamp {
0 commit comments