netlink_packet_ipvs/ctrl/
mod.rs1use 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
20pub mod nlas;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum IpvsCtrlCmd {
26 Unspec,
27 NewService, SetService, DelService, GetService, NewDest, SetDest, DelDest, GetDest, }
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#[derive(Clone, Debug, PartialEq, Eq)]
83pub struct IpvsServiceCtrl {
84 pub cmd: IpvsCtrlCmd,
86 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, })
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}