1use std::{
4 fmt, io,
5 os::fd::AsRawFd,
6 sync::{Arc, PoisonError},
7};
8
9use futures::{Stream, StreamExt, channel::mpsc::UnboundedReceiver};
10use genetlink::{GenetlinkHandle, message::RawGenlMessage};
11use netlink_packet_core::{
12 NLM_F_ACK, NLM_F_DUMP, NLM_F_DUMP_INTR, NLM_F_MULTIPART, NLM_F_REQUEST,
13 NetlinkMessage, NetlinkPayload,
14};
15use netlink_packet_generic::GenlMessage;
16use netlink_packet_l2tp::{L2tpAttribute, L2tpMessage};
17use netlink_proto::{
18 Connection,
19 sys::{AsyncSocket, SocketAddr},
20};
21
22use crate::{
23 Events, L2tpIfName, L2tpIfNameExt, L2tpVersion, NetNs, PseudowireType,
24 SessionConfig, SessionHandle, SessionId, SessionInfo, SessionModify,
25 SessionStats, TunnelConfig, TunnelHandle, TunnelId, TunnelInfo,
26 TunnelSocket, TunnelStats,
27 link::LinkMonitor,
28 netlink::{self, SessionRef},
29};
30
31const EVENTS_GROUP: &str = "l2tp";
34
35type Unsolicited =
36 UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>;
37
38#[derive(Clone)]
40pub struct L2tpHandle {
41 inner: Arc<L2tpInner>,
42}
43
44struct L2tpInner {
45 genl: GenetlinkHandle,
46 family: std::sync::Mutex<Option<FamilyInfo>>,
49 netns: NetNs,
51}
52
53impl L2tpInner {
54 fn cached_family(&self) -> Option<FamilyInfo> {
55 *self.family.lock().unwrap_or_else(PoisonError::into_inner)
56 }
57
58 fn set_family(&self, family: FamilyInfo) {
59 *self.family.lock().unwrap_or_else(PoisonError::into_inner) =
60 Some(family);
61 }
62}
63
64#[derive(Debug, Clone, Copy)]
65struct FamilyInfo {
66 id: u16,
67 events_group: Option<u32>,
68}
69
70impl fmt::Debug for L2tpHandle {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.debug_struct("L2tpHandle")
73 .field("family", &self.inner.cached_family())
74 .field("netns", &self.inner.netns)
75 .finish_non_exhaustive()
76 }
77}
78
79fn open_connection(
81 netns: &NetNs,
82) -> crate::Result<(Connection<RawGenlMessage>, GenetlinkHandle, Unsolicited)> {
83 fn open()
84 -> io::Result<(Connection<RawGenlMessage>, GenetlinkHandle, Unsolicited)>
85 {
86 std::panic::catch_unwind(genetlink::new_connection).map_err(|_| {
90 io::Error::other(
91 "tokio runtime with I/O enabled is required for L2tpHandle",
92 )
93 })?
94 }
95
96 let runtime = tokio::runtime::Handle::current();
100 Ok(netns.run_if_needed(move || {
101 let _guard = runtime.enter();
102 open()
103 })??)
104}
105
106impl L2tpHandle {
107 pub async fn new() -> crate::Result<Self> {
128 Self::connect(None).await
129 }
130
131 pub async fn new_in(netns: &NetNs) -> crate::Result<Self> {
138 Self::connect(Some(netns.try_clone()?)).await
139 }
140
141 async fn connect(netns: Option<NetNs>) -> crate::Result<Self> {
142 let runtime = tokio::runtime::Handle::try_current().map_err(|_| {
143 io::Error::other("tokio runtime is required for L2tpHandle")
144 })?;
145 let netns = match netns {
146 Some(netns) => netns,
147 None => NetNs::current()?,
148 };
149 let (mut connection, genl, _unsolicited) = open_connection(&netns)?;
150 connection.set_forward_ack(true);
151 connection.set_forward_done(true);
152 runtime.spawn(connection);
153
154 Ok(Self {
155 inner: Arc::new(L2tpInner {
156 genl,
157 family: std::sync::Mutex::new(None),
158 netns,
159 }),
160 })
161 }
162
163 pub async fn create_tunnel(
182 &self,
183 config: TunnelConfig,
184 socket: TunnelSocket,
185 ) -> crate::Result<TunnelHandle> {
186 socket.configure(&config.encapsulation)?;
187 if let Some(conn_id) = socket.conn_id()
188 && conn_id != config.tunnel_id.0
189 {
190 return Err(crate::Error::TunnelIdMismatch {
191 socket: TunnelId(conn_id),
192 config: config.tunnel_id,
193 });
194 }
195 let message =
196 netlink::encode_tunnel_create(&config, Some(socket.as_raw_fd()))?;
197 let handle = self.clone();
198 run_creation(async move {
199 handle.send_ack(message).await?;
200 Ok(TunnelHandle {
201 tunnel_id: config.tunnel_id,
202 socket: Some(socket),
203 auto_delete: true,
204 handle,
205 })
206 })
207 .await
208 }
209
210 pub async fn create_unmanaged_tunnel(
227 &self,
228 config: TunnelConfig,
229 ) -> crate::Result<TunnelHandle> {
230 let message = netlink::encode_tunnel_create(&config, None)?;
231 let handle = self.clone();
232 run_creation(async move {
233 handle.send_ack(message).await?;
234 Ok(TunnelHandle {
235 tunnel_id: config.tunnel_id,
236 socket: None,
237 auto_delete: true,
238 handle,
239 })
240 })
241 .await
242 }
243
244 pub async fn open_tunnel(
251 &self,
252 tunnel_id: TunnelId,
253 ) -> crate::Result<TunnelHandle> {
254 self.get_tunnel(tunnel_id).await?;
255 Ok(TunnelHandle {
256 tunnel_id,
257 socket: None,
258 auto_delete: false,
259 handle: self.clone(),
260 })
261 }
262
263 pub async fn create_session(
281 &self,
282 config: SessionConfig,
283 ) -> crate::Result<SessionHandle> {
284 let message = netlink::encode_session_create(&config)?;
285 let handle = self.clone();
286 let monitor = match config.pseudowire_type {
289 PseudowireType::Eth | PseudowireType::EthVlan => {
290 match LinkMonitor::open(&self.inner.netns) {
291 Ok(monitor) => Some(monitor),
292 Err(err) => {
293 log::debug!(
294 "l2tp: cannot watch link registrations, the \
295 interface index will be looked up by name: {err}"
296 );
297 None
298 }
299 }
300 }
301 _ => None,
302 };
303 run_creation(async move {
304 if let Some(id) = [config.session_id, config.peer_session_id]
308 .into_iter()
309 .find(|id| u16::try_from(id.0).is_err())
310 && handle.get_tunnel(config.tunnel_id).await?.version
311 == L2tpVersion::V2
312 {
313 return Err(crate::Error::V2IdTooLarge(id.0));
314 }
315 handle.send_ack(message).await?;
316 handle.get_created_session(config, monitor).await
317 })
318 .await
319 }
320
321 async fn get_created_session(
322 &self,
323 config: SessionConfig,
324 monitor: Option<LinkMonitor>,
325 ) -> crate::Result<SessionHandle> {
326 let mut session = SessionHandle {
329 tunnel_id: config.tunnel_id,
330 session_id: config.session_id,
331 ifname: None,
332 ifindex: None,
333 auto_delete: true,
334 handle: self.clone(),
335 };
336 match self.get_session(config.tunnel_id, config.session_id).await {
337 Ok(info) => {
338 session.ifname = info.ifname;
339 session.ifindex = match (monitor, &info.ifname) {
340 (Some(monitor), Some(ifname)) => {
341 self.registered_index(&monitor, ifname)
342 }
343 (None, Some(ifname)) => self.index_by_name(ifname),
344 (_, None) => None,
345 };
346 Ok(session)
347 }
348 Err(err) => {
349 let _ = session.delete().await;
350 Err(err)
351 }
352 }
353 }
354
355 fn registered_index(
358 &self,
359 monitor: &LinkMonitor,
360 ifname: &L2tpIfName,
361 ) -> Option<u32> {
362 match monitor.registered_index(ifname) {
363 Ok(Some(index)) => return Some(index),
364 Ok(None) => log::debug!(
365 "l2tp: no registration notification for {ifname:?}; looking \
366 the index up by name"
367 ),
368 Err(err) => log::debug!(
369 "l2tp: link notifications were lost ({err}); looking the \
370 index of {ifname:?} up by name"
371 ),
372 }
373 match crate::socket::interface_index(monitor.as_raw_fd(), ifname) {
375 Ok(index) => Some(index),
376 Err(err) => {
377 log::debug!("l2tp: cannot resolve {ifname:?}: {err}");
378 None
379 }
380 }
381 }
382
383 fn index_by_name(&self, ifname: &L2tpIfName) -> Option<u32> {
386 let name = *ifname;
387 match self.inner.netns.run_if_needed(move || name.index()) {
388 Ok(Ok(index)) => Some(index),
389 Ok(Err(err)) => {
390 log::debug!("l2tp: cannot resolve {ifname:?}: {err}");
391 None
392 }
393 Err(err) => {
394 log::debug!(
395 "l2tp: cannot enter the namespace to resolve {ifname:?}: \
396 {err}"
397 );
398 None
399 }
400 }
401 }
402
403 pub async fn open_session(
409 &self,
410 tunnel_id: TunnelId,
411 session_id: SessionId,
412 ) -> crate::Result<SessionHandle> {
413 let info = self.get_session(tunnel_id, session_id).await?;
414 Ok(SessionHandle {
415 tunnel_id,
416 session_id,
417 ifindex: info.ifname.as_ref().and_then(|n| self.index_by_name(n)),
418 ifname: info.ifname,
419 auto_delete: false,
420 handle: self.clone(),
421 })
422 }
423
424 pub async fn open_session_by_ifname(
431 &self,
432 ifname: &L2tpIfName,
433 ) -> crate::Result<SessionHandle> {
434 let info = self.get_session_by_ifname(ifname).await?;
435 Ok(SessionHandle {
436 tunnel_id: info.tunnel_id,
437 session_id: info.session_id,
438 ifindex: info.ifname.as_ref().and_then(|n| self.index_by_name(n)),
439 ifname: info.ifname,
440 auto_delete: false,
441 handle: self.clone(),
442 })
443 }
444
445 pub async fn get_tunnel(
447 &self,
448 tunnel_id: TunnelId,
449 ) -> crate::Result<TunnelInfo> {
450 let replies = self
451 .send_and_collect(
452 netlink::encode_tunnel_get(tunnel_id),
453 NLM_F_REQUEST,
454 )
455 .await?;
456 let attrs = first_attributes(&replies, "empty reply to tunnel get")?;
457 netlink::decode_tunnel_info(attrs)
458 }
459
460 pub async fn get_session(
462 &self,
463 tunnel_id: TunnelId,
464 session_id: SessionId,
465 ) -> crate::Result<SessionInfo> {
466 self.get_session_ref(SessionRef::Ids(tunnel_id, session_id))
467 .await
468 }
469
470 pub async fn get_session_by_ifname(
483 &self,
484 ifname: &L2tpIfName,
485 ) -> crate::Result<SessionInfo> {
486 self.get_session_ref(SessionRef::IfName(*ifname)).await
487 }
488
489 async fn get_session_ref(
490 &self,
491 session: SessionRef,
492 ) -> crate::Result<SessionInfo> {
493 let replies = self
494 .send_and_collect(
495 netlink::encode_session_get(session),
496 NLM_F_REQUEST,
497 )
498 .await?;
499 let attrs = first_attributes(&replies, "empty reply to session get")?;
500 netlink::decode_session_info(attrs)
501 }
502
503 pub async fn list_tunnels(&self) -> crate::Result<Vec<TunnelInfo>> {
509 let replies = self
510 .send_and_collect(
511 netlink::encode_tunnel_get_dump(),
512 NLM_F_REQUEST | NLM_F_DUMP,
513 )
514 .await?;
515 let mut out = Vec::with_capacity(replies.len());
516 for reply in replies {
517 out.push(netlink::decode_tunnel_info(&reply.payload.attributes)?);
518 }
519 Ok(out)
520 }
521
522 pub async fn list_sessions(
524 &self,
525 tunnel_id: TunnelId,
526 ) -> crate::Result<Vec<SessionInfo>> {
527 let mut sessions = self.list_all_sessions().await?;
529 sessions.retain(|session| session.tunnel_id == tunnel_id);
530 Ok(sessions)
531 }
532
533 pub async fn list_all_sessions(&self) -> crate::Result<Vec<SessionInfo>> {
539 let replies = self
540 .send_and_collect(
541 netlink::encode_session_get_dump(),
542 NLM_F_REQUEST | NLM_F_DUMP,
543 )
544 .await?;
545 let mut out = Vec::with_capacity(replies.len());
546 for reply in replies {
547 out.push(netlink::decode_session_info(&reply.payload.attributes)?);
548 }
549 Ok(out)
550 }
551
552 pub async fn delete_tunnel(
566 &self,
567 tunnel_id: TunnelId,
568 ) -> crate::Result<()> {
569 self.send_ack(netlink::encode_tunnel_delete(tunnel_id))
570 .await?;
571 self.wait_tunnel_removed(tunnel_id).await
572 }
573
574 async fn wait_tunnel_removed(
575 &self,
576 tunnel_id: TunnelId,
577 ) -> crate::Result<()> {
578 const POLLS: u32 = 200;
579 const INTERVAL: std::time::Duration =
580 std::time::Duration::from_millis(10);
581 if self.tunnel_removed(tunnel_id).await? {
583 return Ok(());
584 }
585 let (tick_tx, mut tick_rx) = tokio::sync::mpsc::unbounded_channel();
589 std::thread::Builder::new()
590 .name("l2tp-delete-wait".to_string())
591 .spawn(move || {
592 loop {
593 std::thread::sleep(INTERVAL);
594 if tick_tx.send(()).is_err() {
595 break;
596 }
597 }
598 })?;
599 for _ in 1..POLLS {
600 if tick_rx.recv().await.is_none() {
601 return Err(crate::Error::other("the deletion wait stopped"));
602 }
603 if self.tunnel_removed(tunnel_id).await? {
604 return Ok(());
605 }
606 }
607 Err(crate::Error::DeletionPending(tunnel_id))
608 }
609
610 async fn tunnel_removed(&self, tunnel_id: TunnelId) -> crate::Result<bool> {
611 match self.get_tunnel(tunnel_id).await {
612 Ok(_) => Ok(false),
613 Err(err) if err.raw_os_error() == Some(libc::ENODEV) => Ok(true),
614 Err(err) => Err(err),
615 }
616 }
617
618 pub async fn delete_session(
620 &self,
621 tunnel_id: TunnelId,
622 session_id: SessionId,
623 ) -> crate::Result<()> {
624 self.send_ack(netlink::encode_session_delete(SessionRef::Ids(
625 tunnel_id, session_id,
626 )))
627 .await
628 }
629
630 pub async fn delete_session_by_ifname(
635 &self,
636 ifname: &L2tpIfName,
637 ) -> crate::Result<()> {
638 self.send_ack(netlink::encode_session_delete(SessionRef::IfName(
639 *ifname,
640 )))
641 .await
642 }
643
644 pub async fn tunnel_stats(
646 &self,
647 tunnel_id: TunnelId,
648 ) -> crate::Result<TunnelStats> {
649 let replies = self
650 .send_and_collect(
651 netlink::encode_tunnel_get(tunnel_id),
652 NLM_F_REQUEST,
653 )
654 .await?;
655 let attrs = first_attributes(&replies, "empty reply to tunnel get")?;
656 netlink::decode_tunnel_stats(attrs)
657 }
658
659 pub async fn session_stats(
661 &self,
662 tunnel_id: TunnelId,
663 session_id: SessionId,
664 ) -> crate::Result<SessionStats> {
665 self.session_stats_ref(SessionRef::Ids(tunnel_id, session_id))
666 .await
667 }
668
669 pub async fn session_stats_by_ifname(
675 &self,
676 ifname: &L2tpIfName,
677 ) -> crate::Result<SessionStats> {
678 self.session_stats_ref(SessionRef::IfName(*ifname)).await
679 }
680
681 async fn session_stats_ref(
682 &self,
683 session: SessionRef,
684 ) -> crate::Result<SessionStats> {
685 let replies = self
686 .send_and_collect(
687 netlink::encode_session_get(session),
688 NLM_F_REQUEST,
689 )
690 .await?;
691 let attrs = first_attributes(&replies, "empty reply to session get")?;
692 netlink::decode_session_stats(attrs)
693 }
694
695 pub async fn modify_session(
697 &self,
698 tunnel_id: TunnelId,
699 session_id: SessionId,
700 params: SessionModify,
701 ) -> crate::Result<()> {
702 self.send_ack(netlink::encode_session_modify(
703 SessionRef::Ids(tunnel_id, session_id),
704 ¶ms,
705 ))
706 .await
707 }
708
709 pub async fn modify_session_by_ifname(
715 &self,
716 ifname: &L2tpIfName,
717 params: SessionModify,
718 ) -> crate::Result<()> {
719 self.send_ack(netlink::encode_session_modify(
720 SessionRef::IfName(*ifname),
721 ¶ms,
722 ))
723 .await
724 }
725
726 pub async fn events(&self) -> crate::Result<Events> {
753 let runtime = tokio::runtime::Handle::try_current().map_err(|_| {
754 io::Error::other("tokio runtime is required for events")
755 })?;
756 let family = self.resolve_family().await?;
757 let group = family.events_group.ok_or_else(|| {
758 crate::Error::FamilyResolution(format!(
759 "the l2tp family has no `{EVENTS_GROUP}` multicast group"
760 ))
761 })?;
762 let (mut connection, genl, receiver) =
763 open_connection(&self.inner.netns)?;
764 let socket = connection.socket_mut().socket_mut();
769 socket.bind_auto()?;
770 socket.add_membership(group)?;
771 drop(genl);
773 let task = runtime.spawn(connection);
774 Ok(Events::new(receiver, task, family.id))
775 }
776
777 async fn resolve_family(&self) -> crate::Result<FamilyInfo> {
778 match self.inner.cached_family() {
779 Some(family) => Ok(family),
780 None => self.refresh_family().await,
781 }
782 }
783
784 async fn refresh_family(&self) -> crate::Result<FamilyInfo> {
788 self.inner.genl.clear_family_cache().await;
789 let family = self
790 .inner
791 .genl
792 .resolve_family::<L2tpMessage>()
793 .await
794 .map_err(|e| crate::Error::FamilyResolution(e.to_string()))?;
795 let info = FamilyInfo {
796 id: family.id,
797 events_group: family.multicast_groups.get(EVENTS_GROUP).copied(),
798 };
799 self.inner.set_family(info);
800 Ok(info)
801 }
802
803 async fn send_ack(&self, payload: L2tpMessage) -> crate::Result<()> {
804 let _ = self
805 .send_and_collect(payload, NLM_F_REQUEST | NLM_F_ACK)
806 .await?;
807 Ok(())
808 }
809
810 async fn send_and_collect(
811 &self,
812 payload: L2tpMessage,
813 flags: u16,
814 ) -> crate::Result<Vec<GenlMessage<L2tpMessage>>> {
815 let family_id = self.resolve_family().await?.id;
816 match self.send_to_family(payload.clone(), flags, family_id).await {
817 Err(err) if err.raw_os_error() == Some(libc::ENOENT) => {
821 let refreshed = self.refresh_family().await?.id;
822 if refreshed == family_id {
823 return Err(err);
824 }
825 log::debug!(
826 "l2tp: family id {family_id} became {refreshed}; retrying"
827 );
828 self.send_to_family(payload, flags, refreshed).await
829 }
830 result => result,
831 }
832 }
833
834 async fn send_to_family(
835 &self,
836 payload: L2tpMessage,
837 flags: u16,
838 family_id: u16,
839 ) -> crate::Result<Vec<GenlMessage<L2tpMessage>>> {
840 let cmd = payload.cmd;
841 log::debug!("l2tp: sending {cmd:?} with flags {flags:#06x}");
842 let mut genl = GenlMessage::from_payload(payload);
843 genl.set_resolved_family_id(family_id);
844
845 let mut request = NetlinkMessage::from(genl);
846 request.header.flags = flags;
847 request.finalize();
848
849 let mut handle = self.inner.genl.clone();
850 let mut stream = handle.send_request(request).map_err(to_io_error)?;
851
852 match collect_responses(&mut stream, flags).await {
853 Ok(replies) => {
854 log::trace!("l2tp: {cmd:?} returned {} replies", replies.len());
855 Ok(replies)
856 }
857 Err(err) => {
858 log::debug!("l2tp: {cmd:?} failed: {err}");
859 Err(err)
860 }
861 }
862 }
863}
864
865async fn collect_responses<S>(
866 stream: S,
867 flags: u16,
868) -> crate::Result<Vec<GenlMessage<L2tpMessage>>>
869where
870 S: Stream<
871 Item = Result<
872 NetlinkMessage<GenlMessage<L2tpMessage>>,
873 netlink_packet_core::DecodeError,
874 >,
875 >,
876{
877 futures::pin_mut!(stream);
878 let expect_ack = flags & NLM_F_ACK != 0;
879 let mut expect_done = flags & NLM_F_DUMP == NLM_F_DUMP;
880 let mut responses = Vec::new();
881 while let Some(item) = stream.next().await {
882 let message = item?;
883 if message.header.flags & NLM_F_DUMP_INTR != 0 {
884 return Err(io::Error::new(
886 io::ErrorKind::Interrupted,
887 "netlink dump was interrupted by concurrent changes",
888 )
889 .into());
890 }
891 let multipart = message.header.flags & NLM_F_MULTIPART != 0;
892 match message.payload {
893 NetlinkPayload::InnerMessage(inner) => {
894 responses.push(inner);
895 expect_done |= multipart;
896 if !expect_ack && !expect_done {
897 return Ok(responses);
898 }
899 }
900 NetlinkPayload::Error(err) => {
901 if let Some(code) = err.code {
902 return Err(crate::Error::KernelError {
903 code: normalize_errno(code.get()),
904 message: err.to_string(),
905 });
906 }
907 if expect_ack && !expect_done {
908 return Ok(responses);
909 }
910 }
911 NetlinkPayload::Done(done) => {
912 if done.code != 0 {
913 return Err(crate::Error::KernelError {
914 code: normalize_errno(done.code),
915 message: format!("netlink dump failed: {}", done.code),
916 });
917 }
918 if expect_done {
919 return Ok(responses);
920 }
921 return Err(crate::Error::UnexpectedReply(
922 "unexpected netlink DONE".to_string(),
923 ));
924 }
925 NetlinkPayload::Overrun(_) => {
926 return Err(crate::Error::Netlink(
927 "netlink overrun: reply was truncated".to_string(),
928 ));
929 }
930 _ => {}
931 }
932 }
933 Err(io::Error::new(
934 io::ErrorKind::UnexpectedEof,
935 "netlink reply stream closed before request completion",
936 )
937 .into())
938}
939
940struct CreationResult<T> {
941 value: Option<crate::Result<T>>,
942 runtime: tokio::runtime::Handle,
943}
944
945impl<T> Drop for CreationResult<T> {
946 fn drop(&mut self) {
947 let _guard = self.runtime.enter();
951 drop(self.value.take());
952 }
953}
954
955async fn run_creation<F, T>(creation: F) -> crate::Result<T>
961where
962 F: std::future::Future<Output = crate::Result<T>> + Send + 'static,
963 T: Send + 'static,
964{
965 let runtime = tokio::runtime::Handle::try_current().map_err(|_| {
966 io::Error::other("tokio runtime is required for creation")
967 })?;
968 let cleanup_runtime = runtime.clone();
969 let mut result = runtime
970 .spawn(async move {
971 CreationResult {
972 value: Some(creation.await),
973 runtime: cleanup_runtime,
974 }
975 })
976 .await
977 .map_err(|err| io::Error::other(err.to_string()))?;
978 result.value.take().unwrap_or_else(|| {
979 Err(crate::Error::other("creation task lost its result"))
980 })
981}
982
983pub(crate) async fn run_cleanup<F>(cleanup: F) -> crate::Result<()>
986where
987 F: std::future::Future<Output = crate::Result<()>> + Send + 'static,
988{
989 let runtime = tokio::runtime::Handle::try_current().map_err(|_| {
990 io::Error::other("tokio runtime is required for deletion")
991 })?;
992 runtime
993 .spawn(cleanup)
994 .await
995 .map_err(|err| io::Error::other(err.to_string()))?
996}
997
998fn first_attributes<'a>(
999 replies: &'a [GenlMessage<L2tpMessage>],
1000 context: &str,
1001) -> crate::Result<&'a [L2tpAttribute]> {
1002 replies
1003 .first()
1004 .map(|msg| msg.payload.attributes.as_slice())
1005 .ok_or_else(|| crate::Error::UnexpectedReply(context.to_string()))
1006}
1007
1008fn to_io_error(err: genetlink::GenetlinkError) -> crate::Error {
1009 io::Error::other(err.to_string()).into()
1010}
1011
1012fn normalize_errno(code: i32) -> i32 {
1013 if code < 0 { -code } else { code }
1014}
1015
1016#[cfg(test)]
1017mod tests {
1018 use netlink_packet_core::{DoneMessage, ErrorMessage};
1019 use netlink_packet_l2tp::L2tpCmd;
1020
1021 use super::*;
1022
1023 type Reply = NetlinkMessage<GenlMessage<L2tpMessage>>;
1024
1025 fn reply() -> Reply {
1026 NetlinkMessage::from(GenlMessage::from_payload(L2tpMessage::new(
1027 L2tpCmd::TunnelGet,
1028 )))
1029 }
1030
1031 fn ack() -> Reply {
1032 NetlinkMessage::new(
1033 Default::default(),
1034 NetlinkPayload::Error(ErrorMessage::default()),
1035 )
1036 }
1037
1038 fn done(code: i32) -> Reply {
1039 let mut message = DoneMessage::default();
1040 message.code = code;
1041 NetlinkMessage::new(Default::default(), NetlinkPayload::Done(message))
1042 }
1043
1044 fn collect(
1045 messages: Vec<Reply>,
1046 flags: u16,
1047 ) -> crate::Result<Vec<GenlMessage<L2tpMessage>>> {
1048 futures::executor::block_on(collect_responses(
1049 futures::stream::iter(messages.into_iter().map(Ok)),
1050 flags,
1051 ))
1052 }
1053
1054 pub(super) const TEST_FAMILY_ID: u16 = 1234;
1055
1056 pub(super) fn test_handle(genl: GenetlinkHandle) -> L2tpHandle {
1057 L2tpHandle {
1058 inner: Arc::new(L2tpInner {
1059 genl,
1060 family: std::sync::Mutex::new(Some(FamilyInfo {
1061 id: TEST_FAMILY_ID,
1062 events_group: None,
1063 })),
1064 netns: NetNs::current().unwrap(),
1065 }),
1066 }
1067 }
1068
1069 #[test]
1070 fn missing_ack_or_dump_completion_is_an_error() {
1071 for flags in [
1072 NLM_F_REQUEST,
1073 NLM_F_REQUEST | NLM_F_ACK,
1074 NLM_F_REQUEST | NLM_F_DUMP,
1075 ] {
1076 let err = collect(vec![], flags).unwrap_err();
1077 assert_eq!(err.kind(), Some(io::ErrorKind::UnexpectedEof));
1078 }
1079 assert!(collect(vec![reply()], NLM_F_REQUEST | NLM_F_ACK).is_err());
1081 let mut partial = reply();
1083 partial.header.flags = NLM_F_MULTIPART;
1084 assert!(
1085 collect(vec![partial.clone()], NLM_F_REQUEST | NLM_F_DUMP).is_err()
1086 );
1087 assert!(collect(vec![partial], NLM_F_REQUEST).is_err());
1088 }
1089
1090 #[test]
1091 fn request_completion_matches_request_type() {
1092 assert!(
1093 collect(vec![ack()], NLM_F_REQUEST | NLM_F_ACK)
1094 .unwrap()
1095 .is_empty()
1096 );
1097 assert_eq!(collect(vec![reply()], NLM_F_REQUEST).unwrap().len(), 1);
1098 let mut partial = reply();
1099 partial.header.flags = NLM_F_MULTIPART;
1100 assert_eq!(
1101 collect(vec![partial, done(0)], NLM_F_REQUEST | NLM_F_DUMP)
1102 .unwrap()
1103 .len(),
1104 1
1105 );
1106 assert!(
1107 collect(vec![done(0)], NLM_F_REQUEST | NLM_F_DUMP)
1108 .unwrap()
1109 .is_empty()
1110 );
1111 assert!(collect(vec![ack()], NLM_F_REQUEST | NLM_F_DUMP).is_err());
1112 assert!(collect(vec![done(0)], NLM_F_REQUEST | NLM_F_ACK).is_err());
1113 }
1114
1115 #[test]
1116 fn dump_errors_and_interruptions_are_not_success() {
1117 assert_eq!(
1118 collect(vec![done(-libc::EIO)], NLM_F_REQUEST | NLM_F_DUMP)
1119 .unwrap_err()
1120 .raw_os_error(),
1121 Some(libc::EIO)
1122 );
1123 for mut message in [reply(), done(0)] {
1124 message.header.flags = NLM_F_DUMP_INTR;
1125 assert_eq!(
1126 collect(vec![message], NLM_F_REQUEST | NLM_F_DUMP)
1127 .unwrap_err()
1128 .kind(),
1129 Some(io::ErrorKind::Interrupted)
1130 );
1131 }
1132 }
1133
1134 #[test]
1135 fn kernel_ack_errors_are_preserved() {
1136 let mut error = ErrorMessage::default();
1137 error.code = std::num::NonZeroI32::new(-libc::EPERM);
1138 let message = NetlinkMessage::new(
1139 Default::default(),
1140 NetlinkPayload::Error(error),
1141 );
1142 assert_eq!(
1143 collect(vec![message], NLM_F_REQUEST | NLM_F_ACK)
1144 .unwrap_err()
1145 .raw_os_error(),
1146 Some(libc::EPERM)
1147 );
1148 }
1149
1150 #[test]
1151 fn deletion_continues_after_caller_cancellation() {
1152 let runtime = tokio::runtime::Builder::new_current_thread()
1153 .enable_all()
1154 .build()
1155 .unwrap();
1156 runtime.block_on(async {
1157 let (started_tx, started_rx) = tokio::sync::oneshot::channel();
1158 let (finish_tx, finish_rx) = tokio::sync::oneshot::channel();
1159 let (completed_tx, completed_rx) = tokio::sync::oneshot::channel();
1160 let mut deletion = Box::pin(run_cleanup(async move {
1161 started_tx.send(()).unwrap();
1162 finish_rx.await.unwrap();
1163 completed_tx.send(()).unwrap();
1164 Ok(())
1165 }));
1166 assert!(futures::poll!(deletion.as_mut()).is_pending());
1167 started_rx.await.unwrap();
1168 drop(deletion);
1169 finish_tx.send(()).unwrap();
1170 completed_rx
1171 .await
1172 .expect("deletion must finish after cancellation");
1173 });
1174 }
1175
1176 #[test]
1177 fn deletion_propagates_failure() {
1178 let runtime = tokio::runtime::Builder::new_current_thread()
1179 .enable_all()
1180 .build()
1181 .unwrap();
1182 runtime.block_on(async {
1183 let err = run_cleanup(async {
1184 Err(crate::Error::KernelError {
1185 code: libc::EPERM,
1186 message: "denied".into(),
1187 })
1188 })
1189 .await
1190 .unwrap_err();
1191 assert_eq!(err.raw_os_error(), Some(libc::EPERM));
1192 });
1193 }
1194
1195 #[test]
1196 fn connection_shutdown_does_not_acknowledge_request() {
1197 let runtime = tokio::runtime::Builder::new_current_thread()
1198 .enable_all()
1199 .build()
1200 .unwrap();
1201 runtime.block_on(async {
1202 let (connection, genl, _unsolicited) =
1203 match genetlink::new_connection() {
1204 Ok(connection) => connection,
1205 Err(err)
1206 if err.kind() == io::ErrorKind::PermissionDenied =>
1207 {
1208 return;
1209 }
1210 Err(err) => panic!("{err}"),
1211 };
1212 let handle = test_handle(genl);
1213 let mut request = Box::pin(handle.delete_tunnel(TunnelId(123)));
1214 assert!(futures::poll!(request.as_mut()).is_pending());
1215 drop(connection);
1217 assert_eq!(
1218 request.await.unwrap_err().kind(),
1219 Some(io::ErrorKind::UnexpectedEof)
1220 );
1221 });
1222 }
1223
1224 #[test]
1225 fn cancelled_session_lookup_keeps_cleanup_ownership() {
1226 let runtime = tokio::runtime::Builder::new_current_thread()
1227 .enable_all()
1228 .build()
1229 .unwrap();
1230 runtime.block_on(async {
1231 let (_connection, genl, _unsolicited) =
1232 match genetlink::new_connection() {
1233 Ok(connection) => connection,
1234 Err(err)
1235 if err.kind() == io::ErrorKind::PermissionDenied =>
1236 {
1237 return;
1238 }
1239 Err(err) => panic!("{err}"),
1240 };
1241 let handle = test_handle(genl);
1242 let mut lookup = Box::pin(handle.get_created_session(
1245 SessionConfig::eth(TunnelId(1), SessionId(2), SessionId(3)),
1246 None,
1247 ));
1248 assert!(futures::poll!(lookup.as_mut()).is_pending());
1249 drop(lookup);
1250 assert_eq!(Arc::strong_count(&handle.inner), 2);
1254 });
1255 }
1256
1257 #[test]
1258 fn normalize_errno_converts_negative_to_positive() {
1259 assert_eq!(normalize_errno(-libc::EEXIST), libc::EEXIST);
1260 assert_eq!(normalize_errno(-libc::EINVAL), libc::EINVAL);
1261 }
1262
1263 #[test]
1264 fn normalize_errno_keeps_non_negative_unchanged() {
1265 assert_eq!(normalize_errno(0), 0);
1266 assert_eq!(normalize_errno(libc::ENOENT), libc::ENOENT);
1267 }
1268
1269 #[test]
1270 fn new_fails_without_tokio_runtime() {
1271 let result = futures::executor::block_on(L2tpHandle::new());
1272 match result {
1273 Ok(_) => panic!("expected failure without tokio runtime"),
1274 Err(crate::Error::Io(e)) => {
1275 assert!(
1276 e.to_string().contains("tokio runtime is required"),
1277 "unexpected error message: {e}"
1278 );
1279 }
1280 Err(e) => panic!("unexpected error type: {e:?}"),
1281 }
1282 }
1283
1284 #[test]
1285 fn new_fails_without_io_driver() {
1286 let runtime = tokio::runtime::Builder::new_current_thread()
1288 .build()
1289 .unwrap();
1290 match runtime.block_on(L2tpHandle::new()) {
1291 Ok(_) => panic!("expected failure without an I/O driver"),
1292 Err(crate::Error::Io(e)) => {
1293 assert!(
1294 e.to_string().contains("I/O enabled"),
1295 "unexpected error message: {e}"
1296 );
1297 }
1298 Err(e) => panic!("unexpected error type: {e:?}"),
1299 }
1300 }
1301
1302 #[tokio::test]
1303 async fn events_subscription_joins_the_multicast_group() {
1304 let handle = L2tpHandle::new().await.unwrap();
1305 match handle.events().await {
1306 Ok(events) => drop(events),
1307 Err(crate::Error::FamilyResolution(_)) => {}
1309 Err(err) => panic!("unexpected error: {err:?}"),
1310 }
1311 }
1312
1313 #[tokio::test]
1314 async fn opening_unknown_objects_fails_without_a_handle() {
1315 fn refused(err: &crate::Error) -> bool {
1318 err.kind().is_some()
1319 || matches!(err, crate::Error::FamilyResolution(_))
1320 }
1321 let handle = L2tpHandle::new().await.unwrap();
1322 let err = handle.open_tunnel(TunnelId(u32::MAX)).await.unwrap_err();
1323 assert!(refused(&err), "{err:?}");
1324 let name = L2tpIfName::new("l2tp-no-such0").unwrap();
1325 let err = handle.open_session_by_ifname(&name).await.unwrap_err();
1326 assert!(refused(&err), "{err:?}");
1327 }
1328
1329 #[test]
1330 fn new_in_the_current_namespace_needs_no_setns_privileges() {
1331 let runtime = tokio::runtime::Builder::new_current_thread()
1332 .enable_all()
1333 .build()
1334 .unwrap();
1335 runtime.block_on(async {
1336 let netns = NetNs::current().unwrap();
1337 let handle = L2tpHandle::new_in(&netns).await.unwrap();
1338 assert!(handle.inner.netns.same_as(&netns).unwrap());
1339 });
1340 }
1341}
1342
1343#[cfg(test)]
1344mod creation_tests;