netlink_packet_ipvs/ctrl/
mod.rs

1// SPDX-License-Identifier: MIT
2
3//! Generic netlink controller implementation
4//!
5//! This module provides the definition of the controller packet.
6//! It also serves as an example for creating a generic family.
7
8use self::nlas::*;
9use crate::constants::*;
10use anyhow::Context;
11use netlink_packet_core::{
12    NetlinkMessage, NLM_F_ACK, NLM_F_DUMP, NLM_F_REQUEST,
13};
14use netlink_packet_generic::ctrl::{nlas::GenlCtrlAttrs, GenlCtrl};
15use netlink_packet_generic::GenlMessage;
16use netlink_packet_generic::{traits::*, GenlHeader};
17use netlink_packet_utils::{nla::NlasIterator, traits::*, DecodeError};
18use std::convert::{TryFrom, TryInto};
19
20/// Netlink attributes for this family
21pub mod nlas;
22
23/// Command code definition of Netlink controller (nlctrl) family
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum IpvsCtrlCmd {
26    Unspec,
27    NewService, /* add service */
28    SetService, /* modify service */
29    DelService, /* delete service */
30    GetService, /* get service info */
31
32    NewDest, /* add destination */
33    SetDest, /* modify destination */
34    DelDest, /* delete destination */
35    GetDest, /* get destination info */
36}
37
38impl From<IpvsCtrlCmd> for u8 {
39    fn from(cmd: IpvsCtrlCmd) -> u8 {
40        use IpvsCtrlCmd::*;
41        match cmd {
42            NewService => IPVS_CMD_NEW_SERVICE,
43            SetService => IPVS_CMD_SET_SERVICE,
44            DelService => IPVS_CMD_DEL_SERVICE,
45            GetService => IPVS_CMD_GET_SERVICE,
46
47            NewDest => IPVS_CMD_NEW_DEST,
48            SetDest => IPVS_CMD_SET_DEST,
49            DelDest => IPVS_CMD_DEL_DEST,
50            GetDest => IPVS_CMD_GET_DEST,
51            Unspec => IPVS_CMD_UNSPEC,
52        }
53    }
54}
55
56impl TryFrom<u8> for IpvsCtrlCmd {
57    type Error = DecodeError;
58
59    fn try_from(value: u8) -> Result<Self, Self::Error> {
60        use IpvsCtrlCmd::*;
61        Ok(match value {
62            IPVS_CMD_NEW_SERVICE => NewService,
63            IPVS_CMD_SET_SERVICE => SetService,
64            IPVS_CMD_DEL_SERVICE => DelService,
65            IPVS_CMD_GET_SERVICE => GetService,
66
67            IPVS_CMD_NEW_DEST => NewDest,
68            IPVS_CMD_SET_DEST => SetDest,
69            IPVS_CMD_DEL_DEST => DelDest,
70            IPVS_CMD_GET_DEST => GetDest,
71            IPVS_CMD_UNSPEC => Unspec,
72            cmd => {
73                return Err(DecodeError::from(format!(
74                    "Unknown control command: {cmd}"
75                )))
76            }
77        })
78    }
79}
80
81/// Payload of generic netlink controller
82#[derive(Clone, Debug, PartialEq, Eq)]
83pub struct IpvsServiceCtrl {
84    /// Command code of this message
85    pub cmd: IpvsCtrlCmd,
86    /// Netlink attributes in this message
87    pub nlas: Vec<IpvsCtrlAttrs>,
88
89    pub family_id: u16,
90}
91
92pub trait Nlas<'a, T> {
93    fn nlas(&'a self) -> &'a [T];
94}
95impl<'a> Nlas<'a, IpvsCtrlAttrs> for IpvsServiceCtrl {
96    fn nlas(&'a self) -> &'a [IpvsCtrlAttrs] {
97        self.nlas.as_slice()
98    }
99}
100impl<'a> Nlas<'a, GenlCtrlAttrs> for GenlCtrl {
101    fn nlas(&'a self) -> &'a [GenlCtrlAttrs] {
102        self.nlas.as_slice()
103    }
104}
105impl IpvsServiceCtrl {
106    pub fn serialize(self, dump: bool) -> Vec<u8> {
107        let genlmsg = GenlMessage::from_payload(self);
108        let mut nlmsg = NetlinkMessage::from(genlmsg);
109        nlmsg.header.flags = NLM_F_REQUEST | NLM_F_ACK;
110        if dump {
111            nlmsg.header.flags |= NLM_F_DUMP;
112        }
113        nlmsg.finalize();
114        let mut txbuf = vec![0u8; nlmsg.buffer_len()];
115        nlmsg.serialize(&mut txbuf);
116        txbuf
117    }
118}
119
120impl GenlFamily for IpvsServiceCtrl {
121    fn family_name() -> &'static str {
122        "IPVS"
123    }
124
125    fn family_id(&self) -> u16 {
126        self.family_id
127    }
128
129    fn command(&self) -> u8 {
130        self.cmd.into()
131    }
132
133    fn version(&self) -> u8 {
134        1
135    }
136}
137
138impl Emitable for IpvsServiceCtrl {
139    fn emit(&self, buffer: &mut [u8]) {
140        self.nlas.as_slice().emit(buffer);
141    }
142
143    fn buffer_len(&self) -> usize {
144        self.nlas.as_slice().buffer_len()
145    }
146}
147
148impl ParseableParametrized<[u8], GenlHeader> for IpvsServiceCtrl {
149    fn parse_with_param(
150        buf: &[u8],
151        header: GenlHeader,
152    ) -> Result<Self, DecodeError> {
153        Ok(Self {
154            cmd: header.cmd.try_into()?,
155            nlas: parse_ctrlnlas(buf)?,
156            family_id: 999, // FIXME what to do here - probably buf[0..2]?
157                            // seems like this value is not used for anything
158        })
159    }
160}
161
162fn parse_ctrlnlas(buf: &[u8]) -> Result<Vec<IpvsCtrlAttrs>, DecodeError> {
163    let nlas = NlasIterator::new(buf)
164        .map(|nla| nla.and_then(|nla| IpvsCtrlAttrs::parse(&nla)))
165        .collect::<Result<Vec<_>, _>>()
166        .context("failed to parse control message attributes")?;
167
168    Ok(nlas)
169}