@push.rocks/smartnftables 4.3.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/rust/src/owner.rs CHANGED
@@ -302,7 +302,13 @@ impl Owner {
302
302
  }
303
303
  Ok(())
304
304
  }
305
+ /// Whether `graph` is `prepared`'s compiled graph. LEGACY(<=4.4.x): this
306
+ /// includes the untyped sets of a release before typed sets; with the next
307
+ /// major it becomes exact agreement alone.
305
308
  fn matches(&self, graph: &Graph, prepared: &Prepared) -> Result<bool> {
309
+ Ok(self.agreement(graph, prepared)? != Agreement::Different)
310
+ }
311
+ fn agreement(&self, graph: &Graph, prepared: &Prepared) -> Result<Agreement> {
306
312
  let program = prepared.program(&self.identity.table_name)?;
307
313
  let expected_chains: Vec<_> = program
308
314
  .iter()
@@ -336,21 +342,8 @@ impl Owner {
336
342
  }
337
343
  result
338
344
  };
339
- // Element order is the set backend's; element keys are the identity.
340
- let mut expected_sets = std::collections::BTreeMap::<String, (Vec<u8>, Vec<Vec<u8>>)>::new();
341
- for (kind, attrs) in &program {
342
- match kind {
343
- 9 => {
344
- expected_sets.insert(wire::text(attrs, 2)?, (set_identity(attrs)?, Vec::new()));
345
- }
346
- 12 => {
347
- let entry = expected_sets
348
- .get_mut(&wire::text(attrs, 2)?)
349
- .ok_or(Error::Invalid)?;
350
- entry.1.extend(element_keys(&wire::attrs(&wire::one(attrs, 3)?.value)?)?);
351
- }
352
- _ => {}
353
- }
345
+ if expected_chains != actual_chains || regroup(expected_rules) != regroup(actual_rules) {
346
+ return Ok(Agreement::Different);
354
347
  }
355
348
  let mut actual_sets = std::collections::BTreeMap::new();
356
349
  for (attrs, keys) in &graph.sets {
@@ -361,12 +354,22 @@ impl Owner {
361
354
  return Err(Error::Conflict);
362
355
  }
363
356
  }
364
- for entry in expected_sets.values_mut().chain(actual_sets.values_mut()) {
357
+ for entry in actual_sets.values_mut() {
365
358
  entry.1.sort();
366
359
  }
367
- Ok(expected_chains == actual_chains
368
- && regroup(expected_rules) == regroup(actual_rules)
369
- && expected_sets == actual_sets)
360
+ if expected_sets(&program, false)? == actual_sets {
361
+ return Ok(Agreement::Exact);
362
+ }
363
+ // LEGACY(<=4.4.x): kernel state applied before typed sets carries every
364
+ // set with key and data type 0 and no userdata, which Linux stores and
365
+ // dumps but never interprets, so it enforces exactly the same graph.
366
+ // Such a graph is adopted, inspected and released as this graph, and
367
+ // reconciliation always replaces it. Remove with the next major.
368
+ Ok(if expected_sets(&program, true)? == actual_sets {
369
+ Agreement::Untyped
370
+ } else {
371
+ Agreement::Different
372
+ })
370
373
  }
371
374
  fn adopt(&mut self, graph: Graph, transition: &Transition) -> Result<Graph> {
372
375
  self.binding(&graph, transition.previous.as_ref())?;
@@ -464,13 +467,18 @@ impl Owner {
464
467
  let mut operations = Vec::new();
465
468
  let generation = if let Some(graph) = graph {
466
469
  let graph = self.adopt(graph, transition)?;
467
- if self.matches(&graph, &transition.target)? {
470
+ let target = self.agreement(&graph, &transition.target)?;
471
+ if target == Agreement::Exact {
468
472
  transition.target.validate_interfaces()?;
469
473
  return self.applied(&graph, transition.target.clone());
470
474
  }
471
- let previous = transition.previous.as_ref().ok_or(Error::Conflict)?;
472
- if !self.matches(&graph, &previous.prepared)? {
473
- return Err(Error::Conflict);
475
+ // LEGACY(<=4.4.x): the target's own untyped graph is never already
476
+ // applied; it is replaced like a previous graph, in the same batch.
477
+ if target == Agreement::Different {
478
+ let previous = transition.previous.as_ref().ok_or(Error::Conflict)?;
479
+ if !self.matches(&graph, &previous.prepared)? {
480
+ return Err(Error::Conflict);
481
+ }
474
482
  }
475
483
  for rule in &graph.rules {
476
484
  operations.push((
@@ -533,7 +541,7 @@ impl Owner {
533
541
  self.binding(&graph, transition.previous.as_ref())?;
534
542
  if wire::number(&graph.table, 2)? != 6
535
543
  || wire::number(&graph.table, 7)? != self.socket()?.port
536
- || !self.matches(&graph, &transition.target)?
544
+ || self.agreement(&graph, &transition.target)? != Agreement::Exact
537
545
  {
538
546
  return Err(Error::Conflict);
539
547
  }
@@ -668,6 +676,61 @@ impl Owner {
668
676
  }
669
677
  }
670
678
 
679
+ /// How a kernel graph agrees with a compiled one.
680
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
681
+ enum Agreement {
682
+ /// Every chain, rule, set and element, with every set's types.
683
+ Exact,
684
+ /// LEGACY(<=4.4.x): the same graph with untyped sets. Remove with the next
685
+ /// major.
686
+ Untyped,
687
+ Different,
688
+ }
689
+
690
+ /// Sets by name, each with its identity and sorted element keys.
691
+ type Sets = std::collections::BTreeMap<String, (Vec<u8>, Vec<Vec<u8>>)>;
692
+ /// The compiled graph's sets. LEGACY(<=4.4.x): `untyped` declares them as a
693
+ /// release before typed sets did; remove the parameter with the next major.
694
+ fn expected_sets(program: &[(u16, Vec<Attr>)], untyped: bool) -> Result<Sets> {
695
+ // Element order is the set backend's; element keys are the identity.
696
+ let mut sets = Sets::new();
697
+ for (kind, attrs) in program {
698
+ match kind {
699
+ 9 => {
700
+ let identity = if untyped {
701
+ set_identity(&untyped_set(attrs))?
702
+ } else {
703
+ set_identity(attrs)?
704
+ };
705
+ sets.insert(wire::text(attrs, 2)?, (identity, Vec::new()));
706
+ }
707
+ 12 => {
708
+ let entry = sets
709
+ .get_mut(&wire::text(attrs, 2)?)
710
+ .ok_or(Error::Invalid)?;
711
+ entry.1.extend(element_keys(&wire::attrs(&wire::one(attrs, 3)?.value)?)?);
712
+ }
713
+ _ => {}
714
+ }
715
+ }
716
+ for entry in sets.values_mut() {
717
+ entry.1.sort();
718
+ }
719
+ Ok(sets)
720
+ }
721
+ /// LEGACY(<=4.4.x): a set declaration as releases before typed sets wrote it:
722
+ /// key and data type 0 and no userdata. Remove with the next major.
723
+ pub(super) fn untyped_set(attributes: &[Attr]) -> Vec<Attr> {
724
+ attributes
725
+ .iter()
726
+ .filter(|attribute| attribute.id() != 13)
727
+ .map(|attribute| match attribute.id() {
728
+ 4 | 6 => Attr::u32(attribute.id(), 0),
729
+ _ => attribute.clone(),
730
+ })
731
+ .collect()
732
+ }
733
+
671
734
  fn chain_identity(attributes: &[Attr]) -> Result<Vec<u8>> {
672
735
  let mut identity = Vec::new();
673
736
  for attribute in attributes {
@@ -681,9 +744,10 @@ fn chain_identity(attributes: &[Attr]) -> Result<Vec<u8>> {
681
744
  serde_json::to_vec(&wire::canonical(&identity, false)?).map_err(|_| Error::Protocol)
682
745
  }
683
746
  /// A set is its table, name, flags, key type and key length, a map's data type
684
- /// and length, and the field lengths of a concatenation. The handle, the
685
- /// informational backend type and count, the transaction ID and an empty
686
- /// description are not identity; anything else rejects.
747
+ /// and length, the field lengths of a concatenation and its userdata (byte
748
+ /// orders and `typeof` descriptions). The handle, the informational backend
749
+ /// type and count, the transaction ID and an empty description are not
750
+ /// identity; anything else rejects.
687
751
  fn set_identity(attributes: &[Attr]) -> Result<Vec<u8>> {
688
752
  let mut identity = Vec::new();
689
753
  for attribute in attributes {
@@ -694,13 +758,17 @@ fn set_identity(attributes: &[Attr]) -> Result<Vec<u8>> {
694
758
  identity.push(Attr::bytes(9, fields));
695
759
  }
696
760
  }
697
- 1..=7 => identity.push(attribute.clone()),
761
+ 1..=7 | 13 => identity.push(attribute.clone()),
698
762
  _ => return Err(Error::Conflict),
699
763
  }
700
764
  }
701
765
  for id in [1, 2, 3, 4, 5] {
702
766
  wire::one(&identity, id)?;
703
767
  }
768
+ // At most one userdata: a typed set carries it, a legacy untyped one not.
769
+ if identity.iter().filter(|attribute| attribute.id() == 13).count() > 1 {
770
+ return Err(Error::Conflict);
771
+ }
704
772
  // A map carries its data type and length, and nothing else does.
705
773
  let map = wire::number(&identity, 3)? & 8 != 0;
706
774
  for id in [6, 7] {