1use std::marker::PhantomData;
34
35use bit_set::BitSet;
36
37use crate::logging::log_warn;
38
39const U32_BITS_USIZE: usize = u32::BITS as usize;
41
42#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
44pub struct ModernGroup(pub u32);
45
46impl Into<usize> for ModernGroup {
47 fn into(self) -> usize {
48 let ModernGroup(group) = self;
49 group.try_into().expect("expected usize >= u32")
50 }
51}
52
53#[derive(Debug)]
56pub struct NoMappingFromModernToLegacyGroupError;
57
58impl TryFrom<ModernGroup> for SingleLegacyGroup {
59 type Error = NoMappingFromModernToLegacyGroupError;
60
61 fn try_from(
62 ModernGroup(group): ModernGroup,
63 ) -> Result<SingleLegacyGroup, NoMappingFromModernToLegacyGroupError> {
64 let group = 1 << group;
65 if group == 0 {
66 Err(NoMappingFromModernToLegacyGroupError)
67 } else {
68 Ok(SingleLegacyGroup(group))
69 }
70 }
71}
72
73#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
76pub struct LegacyGroups(pub u32);
77
78#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
80pub struct SingleLegacyGroup(u32);
81
82impl SingleLegacyGroup {
83 pub fn inner(&self) -> u32 {
85 let SingleLegacyGroup(inner) = self;
86 *inner
87 }
88}
89
90#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
92pub struct MultipleBitsSetError;
93
94impl TryFrom<u32> for SingleLegacyGroup {
95 type Error = MultipleBitsSetError;
96 fn try_from(value: u32) -> Result<Self, Self::Error> {
97 (value.count_ones() <= 1).then_some(SingleLegacyGroup(value)).ok_or(MultipleBitsSetError)
98 }
99}
100
101pub(crate) trait MulticastCapableNetlinkFamily {
103 fn is_valid_group(group: &ModernGroup) -> bool;
105}
106
107fn legacy_to_modern<F: MulticastCapableNetlinkFamily>(
111 group: SingleLegacyGroup,
112) -> Option<ModernGroup> {
113 let modern_group = ModernGroup(group.inner().ilog2() + 1);
114 F::is_valid_group(&modern_group).then_some(modern_group)
115}
116
117#[derive(Debug)]
123pub(crate) struct MulticastGroupMemberships<F: MulticastCapableNetlinkFamily> {
124 family: PhantomData<F>,
126
127 memberships: BitSet,
131}
132
133#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
135pub struct InvalidModernGroupError;
136
137#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
138pub(crate) enum Mutation {
139 None,
140 Add(ModernGroup),
141 Del(ModernGroup),
142}
143
144#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
146pub struct InvalidLegacyGroupsError;
147
148impl<F: MulticastCapableNetlinkFamily> MulticastGroupMemberships<F> {
149 pub(crate) fn new() -> MulticastGroupMemberships<F> {
151 MulticastGroupMemberships { family: PhantomData, memberships: Default::default() }
152 }
153
154 pub(crate) fn member_of_group(&self, group: ModernGroup) -> bool {
156 self.memberships.contains(group.into())
157 }
158
159 pub(crate) fn add_membership(
163 &mut self,
164 group: ModernGroup,
165 ) -> Result<bool, InvalidModernGroupError> {
166 let MulticastGroupMemberships { family: _, memberships } = self;
167 if !F::is_valid_group(&group) {
168 return Err(InvalidModernGroupError);
169 }
170 let was_absent = memberships.insert(group.into());
171 return Ok(was_absent);
172 }
173
174 pub(crate) fn del_membership(
178 &mut self,
179 group: ModernGroup,
180 ) -> Result<bool, InvalidModernGroupError> {
181 let MulticastGroupMemberships { family: _, memberships } = self;
182 if !F::is_valid_group(&group) {
183 return Err(InvalidModernGroupError);
184 }
185 let was_present = memberships.remove(group.into());
186 return Ok(was_present);
187 }
188
189 pub(crate) fn set_legacy_memberships(
196 &mut self,
197 LegacyGroups(requested_groups): LegacyGroups,
198 ) -> Result<Vec<Mutation>, InvalidLegacyGroupsError> {
199 crate::logging::log_debug!("set_legacy_memberships");
200 let MulticastGroupMemberships { family: _, memberships } = self;
201
202 let mut mutations = [Mutation::None; U32_BITS_USIZE];
203 for i in 0..U32_BITS_USIZE {
205 let raw_legacy_group = 1 << i;
206 let legacy_group = raw_legacy_group
207 .try_into()
208 .expect("raw_legacy_group unexpectedly had multiple bits set");
209 let modern_group = legacy_to_modern::<F>(legacy_group);
210 let is_member_of_group = requested_groups & raw_legacy_group != 0;
211 mutations[i] = match (modern_group, is_member_of_group) {
212 (Some(modern_group), true) => Mutation::Add(modern_group),
213 (Some(modern_group), false) => Mutation::Del(modern_group),
214 (None, true) => {
215 log_warn!(
216 "failed to join legacy groups ({:?}) because of invalid group: {:?}",
217 requested_groups,
218 legacy_group
219 );
220 return Err(InvalidLegacyGroupsError);
221 }
222 (None, false) => Mutation::None,
223 };
224 }
225
226 let mut return_mutations = Vec::new();
227 for mutation in mutations {
229 match mutation {
230 Mutation::None => {}
231 Mutation::Add(group) => {
232 crate::logging::log_debug!("mutation: add {group:?}");
233 let was_absent = memberships.insert(group.into());
234 if was_absent {
235 return_mutations.push(Mutation::Add(group));
236 }
237 }
238 Mutation::Del(group) => {
239 crate::logging::log_debug!("mutation: del {group:?}");
240 let was_present = memberships.remove(group.into());
241 if was_present {
242 return_mutations.push(Mutation::Del(group));
243 }
244 }
245 }
246 }
247 Ok(return_mutations)
248 }
249
250 pub(crate) fn iter_groups(&self) -> impl Iterator<Item = ModernGroup> + '_ {
251 self.memberships.into_iter().map(|n: usize| {
252 let n = u32::try_from(n).expect("all ModernGroups fit in u32");
253 ModernGroup(n)
254 })
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 use crate::protocol_family::testutil::{
263 FakeProtocolFamily, INVALID_LEGACY_GROUP, INVALID_MODERN_GROUP, LEGACY_GROUP1,
264 LEGACY_GROUP2, LEGACY_GROUP3, MODERN_GROUP1, MODERN_GROUP2, MODERN_GROUP3,
265 };
266
267 #[test]
268 fn test_single_legacy_groups() {
269 assert_eq!(0.try_into(), Ok(SingleLegacyGroup(0)));
270 assert_eq!(0x00010000.try_into(), Ok(SingleLegacyGroup(0x00010000)));
271 assert_eq!(
272 <u32 as TryInto<SingleLegacyGroup>>::try_into(0x00010100),
273 Err(MultipleBitsSetError {})
274 );
275 }
276
277 #[test]
278 fn test_add_del_membership() {
279 let mut memberships = MulticastGroupMemberships::<FakeProtocolFamily>::new();
280
281 assert!(!memberships.member_of_group(MODERN_GROUP1));
282 assert!(!memberships.member_of_group(MODERN_GROUP2));
283 assert!(!memberships.member_of_group(MODERN_GROUP3));
284
285 let changed = memberships.add_membership(MODERN_GROUP1).expect("failed to add");
287 assert!(changed, "should have changed group memberships");
288 assert!(memberships.member_of_group(MODERN_GROUP1));
289 assert!(!memberships.member_of_group(MODERN_GROUP2));
290 assert!(!memberships.member_of_group(MODERN_GROUP3));
291 let changed = memberships.add_membership(MODERN_GROUP2).expect("failed to add");
293 assert!(changed, "should have changed group memberships");
294 let changed = memberships.add_membership(MODERN_GROUP3).expect("failed to add");
295 assert!(changed, "should have changed group memberships");
296 assert!(memberships.member_of_group(MODERN_GROUP1));
297 assert!(memberships.member_of_group(MODERN_GROUP2));
298 assert!(memberships.member_of_group(MODERN_GROUP3));
299 let changed = memberships.del_membership(MODERN_GROUP1).expect("failed to del");
301 assert!(changed, "should have changed group memberships");
302 assert!(!memberships.member_of_group(MODERN_GROUP1));
303 assert!(memberships.member_of_group(MODERN_GROUP2));
304 assert!(memberships.member_of_group(MODERN_GROUP3));
305 let changed = memberships.del_membership(MODERN_GROUP2).expect("failed to del");
307 assert!(changed, "should have changed group memberships");
308 let changed = memberships.del_membership(MODERN_GROUP3).expect("failed to del");
309 assert!(changed, "should have changed group memberships");
310 assert!(!memberships.member_of_group(MODERN_GROUP1));
311 assert!(!memberships.member_of_group(MODERN_GROUP2));
312 assert!(!memberships.member_of_group(MODERN_GROUP3));
313 assert_eq!(
315 memberships.add_membership(INVALID_MODERN_GROUP),
316 Err(InvalidModernGroupError {})
317 );
318 assert_eq!(
319 memberships.del_membership(INVALID_MODERN_GROUP),
320 Err(InvalidModernGroupError {})
321 );
322 }
323
324 #[test]
325 fn test_legacy_memberships() {
326 let mut memberships = MulticastGroupMemberships::<FakeProtocolFamily>::new();
327
328 assert!(!memberships.member_of_group(MODERN_GROUP1));
329 assert!(!memberships.member_of_group(MODERN_GROUP2));
330 assert!(!memberships.member_of_group(MODERN_GROUP3));
331
332 let mutations = memberships
334 .set_legacy_memberships(LegacyGroups(LEGACY_GROUP1))
335 .expect("failed to set legacy groups");
336 let expected_mutations = [Mutation::Add(MODERN_GROUP1)];
337 assert_eq!(mutations, expected_mutations);
338 assert!(memberships.member_of_group(MODERN_GROUP1));
339 assert!(!memberships.member_of_group(MODERN_GROUP2));
340 assert!(!memberships.member_of_group(MODERN_GROUP3));
341 let mutations = memberships
343 .set_legacy_memberships(LegacyGroups(LEGACY_GROUP1 | LEGACY_GROUP2 | LEGACY_GROUP3))
344 .expect("failed to set legacy groups");
345 let expected_mutations = [Mutation::Add(MODERN_GROUP2), Mutation::Add(MODERN_GROUP3)];
346 assert_eq!(mutations, expected_mutations);
347 assert!(memberships.member_of_group(MODERN_GROUP1));
348 assert!(memberships.member_of_group(MODERN_GROUP2));
349 assert!(memberships.member_of_group(MODERN_GROUP3));
350 let mutations = memberships
352 .set_legacy_memberships(LegacyGroups(LEGACY_GROUP2 | LEGACY_GROUP3))
353 .expect("failed to set legacy_groups");
354 let expected_mutations = [Mutation::Del(MODERN_GROUP1)];
355 assert_eq!(mutations, expected_mutations);
356 assert!(!memberships.member_of_group(MODERN_GROUP1));
357 assert!(memberships.member_of_group(MODERN_GROUP2));
358 assert!(memberships.member_of_group(MODERN_GROUP3));
359 let mutations = memberships
361 .set_legacy_memberships(LegacyGroups(0))
362 .expect("failed to set legacy groups");
363 let expected_mutations = [Mutation::Del(MODERN_GROUP2), Mutation::Del(MODERN_GROUP3)];
364 assert_eq!(mutations, expected_mutations);
365 assert!(!memberships.member_of_group(MODERN_GROUP1));
366 assert!(!memberships.member_of_group(MODERN_GROUP2));
367 assert!(!memberships.member_of_group(MODERN_GROUP3));
368 assert_eq!(
370 memberships.set_legacy_memberships(LegacyGroups(INVALID_LEGACY_GROUP)),
371 Err(InvalidLegacyGroupsError {})
372 );
373 }
374
375 #[test]
376 fn test_legacy_and_modern_memberships() {
377 let mut memberships = MulticastGroupMemberships::<FakeProtocolFamily>::new();
378
379 assert!(!memberships.member_of_group(MODERN_GROUP1));
380 assert!(!memberships.member_of_group(MODERN_GROUP2));
381
382 let _: Vec<Mutation> = memberships
384 .set_legacy_memberships(LegacyGroups(LEGACY_GROUP1 | LEGACY_GROUP2))
385 .expect("failed to set legacy groups");
386 assert!(memberships.member_of_group(MODERN_GROUP1));
387 assert!(memberships.member_of_group(MODERN_GROUP2));
388 let _: bool = memberships.del_membership(MODERN_GROUP1).expect("failed to del");
389 assert!(!memberships.member_of_group(MODERN_GROUP1));
390 assert!(memberships.member_of_group(MODERN_GROUP2));
391 let _: bool = memberships.del_membership(MODERN_GROUP2).expect("failed to del");
392 assert!(!memberships.member_of_group(MODERN_GROUP1));
393 assert!(!memberships.member_of_group(MODERN_GROUP2));
394
395 let _: bool = memberships.add_membership(MODERN_GROUP1).expect("failed to add");
397 let _: bool = memberships.add_membership(MODERN_GROUP2).expect("failed to add");
398 assert!(memberships.member_of_group(MODERN_GROUP1));
399 assert!(memberships.member_of_group(MODERN_GROUP2));
400 let _: Vec<Mutation> = memberships
401 .set_legacy_memberships(LegacyGroups(LEGACY_GROUP2))
402 .expect("failed to set legacy groups");
403 assert!(!memberships.member_of_group(MODERN_GROUP1));
404 assert!(memberships.member_of_group(MODERN_GROUP2));
405 let _: Vec<Mutation> = memberships
406 .set_legacy_memberships(LegacyGroups(0))
407 .expect("failed to set legacy groups");
408 assert!(!memberships.member_of_group(MODERN_GROUP1));
409 assert!(!memberships.member_of_group(MODERN_GROUP2));
410 }
411}