From b5b164de9049ce1724cabd594d1bae1df09ee04d Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 8 Jul 2025 10:22:56 -0400 Subject: [PATCH 01/20] Support protobuf fields. --- .gitmodules | 3 + Cargo.lock | 18 ++++ Cargo.toml | 2 + crates/hamgrd/Cargo.toml | 5 +- crates/hamgrd/src/actors/ha_scope.rs | 122 ++++++++++++++-------- crates/hamgrd/src/actors/ha_set.rs | 104 +++++++++++++++--- crates/hamgrd/src/actors/test.rs | 44 +++++--- crates/hamgrd/src/db_structs.rs | 33 +++--- crates/swss-common-bridge/Cargo.toml | 6 ++ crates/swss-common-bridge/src/consumer.rs | 101 ++++++++++++++---- test_utils/hamgrd/redis_data_set.cmd | 16 +-- 11 files changed, 331 insertions(+), 123 deletions(-) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..5ff32582 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "crates/sonic-dash-api-proto/sonic-dash-api"] + path = crates/sonic-dash-api-proto/sonic-dash-api + url = https://github.com/sonic-net/sonic-dash-api.git diff --git a/Cargo.lock b/Cargo.lock index d125a866..456e3e7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -791,10 +791,13 @@ dependencies = [ "anyhow", "chrono", "clap", + "hex", + "prost", "serde", "serde_json", "serde_with", "sonic-common", + "sonic-dash-api-proto", "sonicdb-derive", "swbus-actor", "swbus-config", @@ -1942,6 +1945,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "sonic-dash-api-proto" +version = "0.1.0" +dependencies = [ + "prost", + "prost-build", + "serde", +] + [[package]] name = "sonicdb-derive" version = "0.1.0" @@ -2144,6 +2156,12 @@ dependencies = [ name = "swss-common-bridge" version = "0.1.0" dependencies = [ + "anyhow", + "hex", + "prost", + "serde", + "serde_json", + "sonic-dash-api-proto", "swbus-actor", "swbus-edge", "swss-common", diff --git a/Cargo.toml b/Cargo.toml index 96d62d40..356c1124 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "crates/swss-common-bridge", "crates/container", "crates/sonicdb-derive", + "crates/sonic-dash-api-proto" ] exclude = [] @@ -96,6 +97,7 @@ swss-common = { version = "0.1.0", path = "crates/swss-common" } swss-common-testing = { version = "0.1.0", path = "crates/swss-common-testing" } swbus-actor = { version = "0.1.0", path = "crates/swbus-actor" } sonicdb-derive = { version = "0.1.0", path = "crates/sonicdb-derive" } +sonic-dash-api-proto = { version = "0.1.0", path = "crates/sonic-dash-api-proto" } # Dev dependencies criterion = "0.5" diff --git a/crates/hamgrd/Cargo.toml b/crates/hamgrd/Cargo.toml index 71fe852f..71b14d51 100644 --- a/crates/hamgrd/Cargo.toml +++ b/crates/hamgrd/Cargo.toml @@ -30,6 +30,7 @@ clap.workspace = true tracing.workspace = true chrono.workspace = true uuid.workspace = true - -[dev-dependencies] +sonic-dash-api-proto = { path = "../sonic-dash-api-proto" } +prost.workspace = true +hex = "0.4" serde_json.workspace = true diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index 267ae212..6b874f2a 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -3,11 +3,13 @@ use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use crate::{HaSetActor, VDpuActor}; use anyhow::Result; +use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; use std::collections::HashMap; use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, Actor, ActorMessage, Context, State, }; +use swss_common::CxxString; use swss_common::Table; use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; use swss_common_bridge::consumer::ConsumerBridge; @@ -157,6 +159,15 @@ impl HaScopeActor { // Implements internal action functions for HaScopeActor impl HaScopeActor { + fn desired_ha_state_to_ha_role(desired_ha_state: i32) -> String { + match DesiredHaState::try_from(desired_ha_state) { + Ok(DesiredHaState::HaStateActive) => "active".to_string(), + Ok(DesiredHaState::HaStateDead) => "dead".to_string(), + Ok(DesiredHaState::HaStateStandalone) => "standalone".to_string(), + Ok(DesiredHaState::HaStateUnspecified) | Err(_) => "unknown".to_string(), + } + } + fn register_to_vdpu_actor(&self, outgoing: &mut Outgoing, active: bool) -> Result<()> { if self.dash_ha_scope_config.is_none() { return Ok(()); @@ -185,39 +196,41 @@ impl HaScopeActor { let mut activate_role_requested = false; let mut flow_reconcile_requested = false; - if let Some(approved_ops) = dash_ha_scope_config.approved_pending_operation_ids.as_ref() { - if !approved_ops.is_empty() { - let pending_operations = self.get_pending_operations(internal, None)?; - for op_id in approved_ops { - let Some(op) = pending_operations.get(op_id) else { - // has been removed from pending list - continue; - }; - match op.as_str() { - "switchover" => { - // todo: this is for switch driven ha - } - "activate_role" => { - activate_role_requested = true; - } - "flow_reconcile" => { - flow_reconcile_requested = true; - } - "brainsplit_recover" => { - // todo: what's the action here? - } - _ => { - error!("Unknown operation type {}", op); - } + let approved_ops = dash_ha_scope_config + .ha_scope_config + .approved_pending_operation_ids + .clone(); + if !approved_ops.is_empty() { + let pending_operations = self.get_pending_operations(internal, None)?; + for op_id in approved_ops { + let Some(op) = pending_operations.get(&op_id) else { + // has been removed from pending list + continue; + }; + match op.as_str() { + "switchover" => { + // todo: this is for switch driven ha + } + "activate_role" => { + activate_role_requested = true; + } + "flow_reconcile" => { + flow_reconcile_requested = true; + } + "brainsplit_recover" => { + // todo: what's the action here? + } + _ => { + error!("Unknown operation type {}", op); } } } } let dash_ha_scope = DashHaScopeTable { - version: dash_ha_scope_config.version, - disable: dash_ha_scope_config.disable, - ha_role: dash_ha_scope_config.desired_ha_state.clone(), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ + version: dash_ha_scope_config.ha_scope_config.version.parse().unwrap(), + disable: dash_ha_scope_config.ha_scope_config.disabled, + ha_role: Self::desired_ha_state_to_ha_role(dash_ha_scope_config.ha_scope_config.desired_ha_state), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ flow_reconcile_requested, activate_role_requested, }; @@ -375,7 +388,9 @@ impl HaScopeActor { npu_ha_scope_state.local_ha_state_last_updated_reason = Some("dpu initiated".to_string()); // The target HA state in ASIC. This is the state that hamgrd generates and asking DPU to move to. - npu_ha_scope_state.local_target_asic_ha_state = Some(dash_ha_scope_config.desired_ha_state.clone()); + npu_ha_scope_state.local_target_asic_ha_state = Some(Self::desired_ha_state_to_ha_role( + dash_ha_scope_config.ha_scope_config.desired_ha_state, + )); // The HA state that ASIC acked. npu_ha_scope_state.local_acked_asic_ha_state = Some(dpu_ha_scope_state.ha_role.clone()); @@ -390,6 +405,24 @@ impl HaScopeActor { } } +fn decode_field_values_to_hascopeconfig( + field_values: &HashMap, +) -> Result { + use serde_json::Value; + + let mut json_map = serde_json::Map::new(); + for (k, v) in field_values { + let s = v.to_string_lossy(); + let value = match serde_json::from_str::(&s) { + Ok(val) => val, + Err(_) => Value::String(s.into_owned()), + }; + json_map.insert(k.clone(), value); + } + let json_value = Value::Object(json_map); + serde_json::from_value(json_value) +} + // Implements messages handlers for HaScopeActor impl HaScopeActor { /// Handles updates to the DASH_HA_SCOPE_CONFIG_TABLE. @@ -415,10 +448,12 @@ impl HaScopeActor { return Ok(()); } let first_time = self.dash_ha_scope_config.is_none(); - let dash_ha_scope_config: DashHaScopeConfigTable = swss_serde::from_field_values(&kfv.field_values)?; + let dash_ha_scope_config: HaScopeConfig = decode_field_values_to_hascopeconfig(&kfv.field_values)?; // Update internal config - self.dash_ha_scope_config = Some(dash_ha_scope_config); + self.dash_ha_scope_config = Some(DashHaScopeConfigTable { + ha_scope_config: dash_ha_scope_config, + }); if first_time { // Subscribe to the vDPU Actor for state updates. @@ -439,15 +474,14 @@ impl HaScopeActor { self.update_npu_ha_scope_state_ha_state(state)?; // need to update operation list if approved_pending_operation_ids is not empty - let approved_pending_operation_ids = match self + let approved_pending_operation_ids = self .dash_ha_scope_config .as_ref() .unwrap() + .ha_scope_config .approved_pending_operation_ids - { - Some(ref ids) => ids.clone(), - None => Vec::new(), - }; + .clone(); + if !approved_pending_operation_ids.is_empty() { self.update_npu_ha_scope_state_pending_operations(state, Vec::new(), approved_pending_operation_ids)?; } @@ -645,7 +679,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state disabled send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "1", "disable": "true", "desired_ha_state": "active", "approved_pending_operation_ids": "" }, + "field_values": {"version": "\"1\"", "disabled": "true", "desired_ha_state": "2", "approved_pending_operation_ids": "[]" }, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -678,7 +712,7 @@ mod test { // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state enabled send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "2", "disable": "false", "desired_ha_state": "active", "approved_pending_operation_ids": "" }, + "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": "[]" }, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -707,7 +741,10 @@ mod test { let db = crate::db_named(NpuDashHaScopeState::db_name()).await.unwrap(); let table = Table::new(db, NpuDashHaScopeState::table_name()).unwrap(); let npu_ha_scope_state: NpuDashHaScopeState = swss_serde::from_table(&table, &scope_id_in_state).unwrap(); - let op_id = npu_ha_scope_state.pending_operation_ids.unwrap().pop().unwrap(); + let op_id = format!( + "[\"{}\"]", + npu_ha_scope_state.pending_operation_ids.unwrap().pop().unwrap() + ); // continue the test to activate the role let mut npu_ha_scope_state4 = npu_ha_scope_state3.clone(); @@ -715,7 +752,7 @@ mod test { let npu_ha_scope_state_fvs4 = to_field_values(&npu_ha_scope_state4).unwrap(); let mut dpu_ha_state_state5 = make_dpu_ha_scope_state("active"); - dpu_ha_state_state5.ha_term = "2".to_string(); + dpu_ha_state_state5.ha_term = "active".to_string(); let mut npu_ha_scope_state5: NpuDashHaScopeState = npu_ha_scope_state4.clone(); update_npu_ha_scope_state_by_dpu_scope_state(&mut npu_ha_scope_state5, &dpu_ha_state_state5, "active"); let npu_ha_scope_state_fvs5 = to_field_values(&npu_ha_scope_state5).unwrap(); @@ -731,7 +768,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with activation approved send! { key: HaScopeActor::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "3", "disable": "false", "desired_ha_state": "active", "approved_pending_operation_ids": &op_id }, + "field_values": {"version": "\"3\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": &op_id }, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -772,7 +809,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with desired_ha_state = dead send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "2", "disable": "false", "desired_ha_state": "dead", "approved_pending_operation_ids": "" }, + "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "1", "approved_pending_operation_ids": "[]" }, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -782,7 +819,8 @@ mod test { // simulate delete of ha-scope entry send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Del", - "field_values": {"version": "2", "disable": "false", "desired_ha_state": "dead", "approved_pending_operation_ids": "" }}, + "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "1", "approved_pending_operation_ids": "[]" } + }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index 6cf2830f..3e978b9e 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -3,10 +3,13 @@ use crate::actors::{spawn_consumer_bridge_for_actor, DbBasedActor}; use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use anyhow::Result; +use sonic_dash_api_proto::ha_set_config::HaSetConfig; +use std::collections::HashMap; use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, Actor, ActorMessage, Context, State, }; +use swss_common::CxxString; use swss_common::Table; use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; use swss_common_bridge::consumer::ConsumerBridge; @@ -42,6 +45,24 @@ struct VDpuStateExt { is_primary: bool, } +fn decode_field_values_to_hasetconfig( + field_values: &HashMap, +) -> Result { + use serde_json::Value; + + let mut json_map = serde_json::Map::new(); + for (k, v) in field_values { + let s = v.to_string_lossy(); + let value = match serde_json::from_str::(&s) { + Ok(val) => val, + Err(_) => Value::String(s.into_owned()), + }; + json_map.insert(k.clone(), value); + } + let json_value = Value::Object(json_map); + serde_json::from_value(json_value) +} + impl HaSetActor { fn get_dash_global_config(incoming: &Incoming) -> Result { let kfv: KeyOpFieldValues = incoming.get(DashHaGlobalConfig::table_name())?.deserialize_data()?; @@ -76,11 +97,16 @@ impl HaSetActor { let global_cfg = Self::get_dash_global_config(incoming)?; let dash_ha_set = DashHaSetTable { - version: dash_ha_set_config.version.clone(), - vip_v4: dash_ha_set_config.vip_v4.clone(), - vip_v6: dash_ha_set_config.vip_v6.clone(), - owner: dash_ha_set_config.owner.clone(), - scope: dash_ha_set_config.scope.clone(), + version: dash_ha_set_config.ha_set_config.version.clone(), + vip_v4: dash_ha_set_config + .ha_set_config + .vip_v4 + .as_ref() + .map(ip_to_string) + .unwrap_or_default(), + vip_v6: dash_ha_set_config.ha_set_config.vip_v6.as_ref().map(ip_to_string), + owner: format!("{:?}", dash_ha_set_config.ha_set_config.owner).into(), + scope: format!("{:?}", dash_ha_set_config.ha_set_config.scope).into(), local_npu_ip: local_vdpu.dpu.npu_ipv4.clone(), local_ip: local_vdpu.dpu.pa_ipv4.clone(), peer_ip: remote_vdpu.dpu.pa_ipv4.clone(), @@ -91,6 +117,7 @@ impl HaSetActor { dp_channel_probe_interval_ms: global_cfg.dp_channel_probe_interval_ms, dp_channel_probe_fail_threshold: global_cfg.dp_channel_probe_fail_threshold, }; + Ok(Some(dash_ha_set)) } @@ -170,6 +197,7 @@ impl HaSetActor { let msg = ActorRegistration::new_actor_msg(active, RegistrationType::VDPUState, &self.id)?; dash_ha_set_config + .ha_set_config .vdpu_ids .iter() .map(|id: &String| id.trim()) @@ -197,17 +225,23 @@ impl HaSetActor { return Vec::new(); }; + let ref ha_set_cfg = ha_set_cfg.ha_set_config; let mut result = Vec::new(); // Collect all preferred (primary) vdpus first let mut seen = std::collections::HashSet::new(); - if let Some(prefered_vdpu_ids) = ha_set_cfg.preferred_vdpu_ids.as_ref() { - for id in prefered_vdpu_ids.iter().filter(|id| !id.is_empty()) { + if !ha_set_cfg.preferred_vdpu_id.is_empty() { + for id in ha_set_cfg + .preferred_vdpu_id + .split(',') + .map(str::trim) + .filter(|id| !id.is_empty()) + { result.push( self.get_vdpu(incoming, id) .map(|vdpu| VDpuStateExt { vdpu, is_primary: true }), ); - seen.insert(id); + seen.insert(id.to_string()); } } @@ -215,7 +249,7 @@ impl HaSetActor { for id in ha_set_cfg .vdpu_ids .iter() - .filter(|id| !id.is_empty() && !seen.contains(id)) + .filter(|id| !id.is_empty() && !seen.contains(*id)) { result.push(self.get_vdpu(incoming, id).map(|vdpu| VDpuStateExt { vdpu, @@ -257,8 +291,26 @@ impl HaSetActor { } let first_time = self.dash_ha_set_config.is_none(); - self.dash_ha_set_config = Some(swss_serde::from_field_values(&dpu_kfv.field_values)?); - let swss_key = format!("default:{}", self.dash_ha_set_config.as_ref().unwrap().vip_v4); + self.dash_ha_set_config = Some(DashHaSetConfigTable { + ha_set_config: decode_field_values_to_hasetconfig(&dpu_kfv.field_values).unwrap(), + }); + + let vip_v4_str = self + .dash_ha_set_config + .as_ref() + .unwrap() + .ha_set_config + .vip_v4 + .as_ref() + .map(|ip| { + if let Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) = &ip.ip { + std::net::Ipv4Addr::from(*addr).to_string() + } else { + "".to_string() + } + }); + + let swss_key = format!("default:{}", vip_v4_str.unwrap()); if !internal.has_entry(VnetRouteTunnelTable::table_name(), &swss_key) { let db = crate::db_named(VnetRouteTunnelTable::db_name()).await?; let table = Table::new_async(db, VnetRouteTunnelTable::table_name()).await?; @@ -358,6 +410,7 @@ impl Actor for HaSetActor { #[cfg(test)] mod test { + use crate::actors::KeyOperation; use crate::{ actors::{ ha_set::HaSetActor, @@ -365,13 +418,32 @@ mod test { vdpu::VDpuActor, DbBasedActor, }, - db_structs::{DashHaGlobalConfig, DashHaSetConfigTable, DashHaSetTable, VnetRouteTunnelTable}, + db_structs::*, ha_actor_messages::*, }; + use std::collections::HashMap; use std::time::Duration; + use swss_common::CxxString; + use swss_common::KeyOpFieldValues; use swss_common::SonicDbTable; use swss_common_testing::*; + fn protobuf_struct_to_json(cfg: &T) -> HashMap { + let json = serde_json::to_value(cfg).unwrap(); + let mut kfv = KeyOpFieldValues { + key: HaSetActor::table_name().to_string(), + operation: KeyOperation::Set, + field_values: HashMap::new(), + }; + kfv.field_values.clear(); + if let serde_json::Value::Object(map) = json { + for (k, v) in map { + kfv.field_values.insert(k, v.to_string().into()); + } + } + kfv.field_values.clone() + } + #[tokio::test] async fn ha_set_actor() { // To enable trace, set ENABLE_TRACE=1 to run test @@ -385,7 +457,7 @@ mod test { let global_cfg_fvs = serde_json::to_value(swss_serde::to_field_values(&global_cfg).unwrap()).unwrap(); let (ha_set_id, ha_set_cfg) = make_dpu_scope_ha_set_config(0, 0); - let ha_set_cfg_fvs = serde_json::to_value(swss_serde::to_field_values(&ha_set_cfg).unwrap()).unwrap(); + let ha_set_cfg_fvs = protobuf_struct_to_json(&ha_set_cfg); let dpu0 = make_local_dpu_actor_state(0, 0, true, None, None); let dpu1 = make_remote_dpu_actor_state(1, 0); let (vdpu0_id, vdpu0_state_obj) = make_vdpu_actor_state(true, &dpu0); @@ -444,7 +516,7 @@ mod test { // Verify that haset actor state is sent to ha-scope actor recv! { key: HaSetActorState::msg_key(&ha_set_id), data: { "up": true, "ha_set": &ha_set_obj }, addr: runtime.sp("ha-scope", &format!("vdpu0:{ha_set_id}")) }, - chkdb! { db: "APPL_DB", table: "VNET_ROUTE_TUNNEL_TABLE", key: &format!("default:{}", ha_set_cfg.vip_v4), data: expected_vnet_route }, + chkdb! { db: "APPL_DB", table: "VNET_ROUTE_TUNNEL_TABLE", key: &format!("default:{}", ip_to_string(&ha_set_cfg.vip_v4.unwrap())), data: expected_vnet_route }, // simulate delete of ha-set entry send! { key: HaSetActor::table_name(), data: { "key": HaSetActor::table_name(), "operation": "Del", "field_values": ha_set_cfg_fvs }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -470,7 +542,7 @@ mod test { let global_cfg_fvs = serde_json::to_value(swss_serde::to_field_values(&global_cfg).unwrap()).unwrap(); let (ha_set_id, ha_set_cfg) = make_dpu_scope_ha_set_config(2, 0); - let ha_set_cfg_fvs = serde_json::to_value(swss_serde::to_field_values(&ha_set_cfg).unwrap()).unwrap(); + let ha_set_cfg_fvs = protobuf_struct_to_json(&ha_set_cfg); let dpu0 = make_remote_dpu_actor_state(2, 0); let dpu1 = make_remote_dpu_actor_state(3, 0); let (vdpu0_id, vdpu0_state_obj) = make_vdpu_actor_state(true, &dpu0); @@ -517,7 +589,7 @@ mod test { // Simulate VDPU state update for vdpu1 (backup) send! { key: VDpuActorState::msg_key(&vdpu1_id), data: vdpu1_state, addr: runtime.sp("vdpu", &vdpu1_id) }, // Verify that the DASH_HA_SET_TABLE was updated - chkdb! { db: "APPL_DB", table: VnetRouteTunnelTable::table_name(), key: &format!("default:{}", ha_set_cfg.vip_v4), + chkdb! { db: "APPL_DB", table: VnetRouteTunnelTable::table_name(), key: &format!("default:{}", ip_to_string(&ha_set_cfg.vip_v4.unwrap())), data: expected_vnet_route }, // simulate delete of ha-set entry send! { key: HaSetActor::table_name(), data: { "key": HaSetActor::table_name(), "operation": "Del", "field_values": ha_set_cfg_fvs }, diff --git a/crates/hamgrd/src/actors/test.rs b/crates/hamgrd/src/actors/test.rs index 84ec6140..17bb4179 100644 --- a/crates/hamgrd/src/actors/test.rs +++ b/crates/hamgrd/src/actors/test.rs @@ -3,6 +3,7 @@ use crate::ha_actor_messages::*; use crate::RuntimeData; use anyhow::Result; use serde_json::Value; +use sonic_dash_api_proto::{ha_set_config::HaSetConfig, types::ip_address::Ip, types::*}; use std::{collections::HashMap, future::Future, time::Duration}; use std::{net::Ipv4Addr, net::Ipv6Addr, sync::Arc}; use swbus_actor::{ActorMessage, ActorRuntime}; @@ -386,26 +387,43 @@ pub fn make_vdpu_actor_state(up: bool, dpu_state: &DpuActorState) -> (String, VD ) } +pub fn string_to_ip(s: String) -> Option { + if s.is_empty() { + return None; + } + if let Ok(v4) = s.parse::() { + Some(IpAddress { + ip: Some(Ip::Ipv4(u32::from(v4))), + }) + } else if let Ok(v6) = s.parse::() { + Some(IpAddress { + ip: Some(Ip::Ipv6(v6.octets().to_vec())), + }) + } else { + None + } +} + /// Create a DashHaSetConfigTable for a given DPU /// The allocation scheme is as follows: /// switch_n/dpu_x and switch_n+1/dpu_x are in the same HA set, where n is even /// vdpu id is vdpu{switch id * 8}-{dpu} -pub fn make_dpu_scope_ha_set_config(switch: u16, dpu: u16) -> (String, DashHaSetConfigTable) { +pub fn make_dpu_scope_ha_set_config(switch: u16, dpu: u16) -> (String, HaSetConfig) { let switch_pair_id = switch / 2; let vdpu0_id = format!("vdpu{}-{dpu}", switch_pair_id * 2); let vdpu1_id = format!("vdpu{}-{dpu}", switch_pair_id * 2 + 1); - let ha_set = DashHaSetConfigTable { + let ha_set = HaSetConfig { version: "1".to_string(), - vip_v4: format!("3.2.{switch_pair_id}.{dpu}"), - vip_v6: Some(normalize_ipv6(&format!("3:2:{switch_pair_id}::{dpu}"))), + vip_v4: string_to_ip(format!("3.2.{switch_pair_id}.{dpu}")), + vip_v6: string_to_ip(normalize_ipv6(&format!("3:2:{switch_pair_id}::{dpu}"))), // dpu or switch - owner: Some("dpu".to_string()), + owner: HaOwner::OwnerController as i32, // dpu or eni - scope: Some("dpu".to_string()), + scope: HaScope::ScopeDpu as i32, vdpu_ids: vec![vdpu0_id.clone(), vdpu1_id.clone()], - pinned_vdpu_bfd_probe_states: None, - preferred_vdpu_ids: Some(vec![vdpu0_id]), - preferred_standalone_vdpu_index: Some(0), + pinned_vdpu_bfd_probe_states: vec!["".to_string()], + preferred_vdpu_id: vdpu0_id, + preferred_standalone_vdpu_index: 0, }; (format!("haset{switch_pair_id}-{dpu}"), ha_set) } @@ -416,10 +434,10 @@ pub fn make_dpu_scope_ha_set_obj(switch: u16, dpu: u16) -> (String, DashHaSetTab let global_cfg = make_dash_ha_global_config(); let ha_set = DashHaSetTable { version: "1".to_string(), - vip_v4: haset_cfg.vip_v4, - vip_v6: haset_cfg.vip_v6, - owner: haset_cfg.owner, - scope: haset_cfg.scope, + vip_v4: ip_to_string(&haset_cfg.vip_v4.unwrap()), + vip_v6: Some(ip_to_string(&haset_cfg.vip_v6.unwrap())), + owner: format!("{:?}", haset_cfg.owner).into(), + scope: format!("{:?}", haset_cfg.scope).into(), local_npu_ip: format!("10.0.{switch}.{dpu}"), local_ip: format!("18.0.{switch}.{dpu}"), peer_ip: format!("18.0.{}.{dpu}", switch_pair_id * 2 + 1), diff --git a/crates/hamgrd/src/db_structs.rs b/crates/hamgrd/src/db_structs.rs index eff1fb46..42532d79 100644 --- a/crates/hamgrd/src/db_structs.rs +++ b/crates/hamgrd/src/db_structs.rs @@ -2,6 +2,7 @@ use anyhow::{Context, Result}; use chrono::DateTime; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde_with::{formats::CommaSeparator, serde_as, skip_serializing_none, StringWithSeparator}; +use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig, types::*}; use sonicdb_derive::SonicDb; use swss_common::{DbConnector, Table}; use swss_serde::from_table; @@ -207,19 +208,7 @@ pub fn now_in_millis() -> i64 { #[derive(Serialize, Deserialize, SonicDb)] #[sonicdb(table_name = "DASH_HA_SET_CONFIG_TABLE", key_separator = ":", db_name = "APPL_DB")] pub struct DashHaSetConfigTable { - pub version: String, - pub vip_v4: String, - pub vip_v6: Option, - // dpu or switch - pub owner: Option, - // dpu or eni - pub scope: Option, - #[serde_as(as = "StringWithSeparator::")] - pub vdpu_ids: Vec, - pub pinned_vdpu_bfd_probe_states: Option, - #[serde_as(as = "Option>")] - pub preferred_vdpu_ids: Option>, - pub preferred_standalone_vdpu_index: Option, + pub ha_set_config: HaSetConfig, } /// @@ -281,11 +270,7 @@ pub struct VnetRouteTunnelTable { #[derive(Debug, Deserialize, Serialize, PartialEq, SonicDb)] #[sonicdb(table_name = "DASH_HA_SCOPE_CONFIG_TABLE", key_separator = ":", db_name = "APPL_DB")] pub struct DashHaScopeConfigTable { - pub version: u32, - pub disable: bool, - pub desired_ha_state: String, - #[serde_as(as = "Option>")] - pub approved_pending_operation_ids: Option>, + pub ha_scope_config: HaScopeConfig, } /// @@ -431,6 +416,18 @@ pub fn get_dpu_config_from_db(dpu_id: u32) -> Result { Err(anyhow::anyhow!("DPU entry not found for slot {}", dpu_id)) } +pub fn ip_to_string(ip: &IpAddress) -> String { + match &ip.ip { + Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) => std::net::Ipv4Addr::from(*addr).to_string(), + Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv6(addr)) => { + use std::net::Ipv6Addr; + let bytes: [u8; 16] = addr.clone().try_into().unwrap_or([0; 16]); + Ipv6Addr::from(bytes).to_string() + } + _ => "".to_string(), + } +} + #[cfg(test)] mod test { use super::*; diff --git a/crates/swss-common-bridge/Cargo.toml b/crates/swss-common-bridge/Cargo.toml index 0fd2bffc..b42b7806 100644 --- a/crates/swss-common-bridge/Cargo.toml +++ b/crates/swss-common-bridge/Cargo.toml @@ -14,6 +14,12 @@ swbus-edge = { path = "../swbus-edge" } tokio.workspace = true tokio-util.workspace = true swbus-actor = { path = "../swbus-actor" } +anyhow.workspace = true +sonic-dash-api-proto = { path = "../sonic-dash-api-proto" } +prost.workspace = true +hex = "0.4" +serde.workspace = true +serde_json.workspace = true [lints] workspace = true diff --git a/crates/swss-common-bridge/src/consumer.rs b/crates/swss-common-bridge/src/consumer.rs index 420c3aa1..86e5de59 100644 --- a/crates/swss-common-bridge/src/consumer.rs +++ b/crates/swss-common-bridge/src/consumer.rs @@ -1,3 +1,5 @@ +use prost::Message; +use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig}; use std::{collections::HashMap, future::Future, sync::Arc}; use swbus_actor::ActorMessage; use swbus_edge::{ @@ -40,6 +42,32 @@ impl ConsumerBridge { } } +pub fn parse_from_protobuf(kfv: &KeyOpFieldValues) -> anyhow::Result> { + let value_hex = match kfv.field_values.get("pb") { + Some(v) => v.to_str().ok(), + None => None, + }; + let value_hex = match value_hex { + Some(s) if !s.is_empty() => s, + _ => return Ok(None), + }; + let value_bytes = hex::decode(value_hex)?; + let config = T::decode(&*value_bytes)?; + Ok(Some(config)) +} + +pub fn convert_pb_to_json_fields(kfv: &mut KeyOpFieldValues) { + if let Some(cfg) = parse_from_protobuf::(kfv).unwrap_or(None) { + let json = serde_json::to_value(&cfg).unwrap(); + kfv.field_values.clear(); + if let serde_json::Value::Object(map) = json { + for (k, v) in map { + kfv.field_values.insert(k, v.to_string().into()); + } + } + } +} + pub fn spawn_consumer_bridge( rt: Arc, addr: ServicePath, @@ -52,10 +80,22 @@ where F: FnMut(&KeyOpFieldValues) -> (ServicePath, String) + Send + 'static, S: Fn(&KeyOpFieldValues) -> bool + Sync + Send + 'static, { + let table_name = table.get_table_name().to_owned(); let swbus = SimpleSwbusEdgeClient::new(rt, addr, false, false); tokio::task::spawn(async move { let mut table_cache = TableCache::default(); - let mut send_kfv = async |kfv: KeyOpFieldValues| { + let mut send_kfv = async |mut kfv: KeyOpFieldValues| { + // Decode protobuf and re-encode as JSON for tables that use protobuf + match table_name.as_str() { + "DASH_HA_SET_CONFIG_TABLE" => { + convert_pb_to_json_fields::(&mut kfv); + } + "DASH_HA_SCOPE_CONFIG_TABLE" => { + convert_pb_to_json_fields::(&mut kfv); + } + _ => {} + } + // Merge the kfv to get the whole table as an update let kfv = table_cache.merge_kfv(kfv); if !selector(&kfv) { @@ -142,6 +182,9 @@ pub trait ConsumerTable: Send + 'static { /// Dump the table, as if `pops()` returned everything again, for rehydration after a restart fn rehydrate(&mut self) -> impl Future> + Send; + + /// Return the table name for this instance + fn get_table_name(&self) -> &str; } macro_rules! rehydrate_body { @@ -170,29 +213,51 @@ macro_rules! rehydrate_body { }; } -macro_rules! impl_consumertable { - ($($t:ty [$can_rehydrate:tt])*) => { - $(impl ConsumerTable for $t { - async fn read_data(&mut self) { - <$t>::read_data_async(self) - .await - .expect(concat!(stringify!($t::read_data_async), " io error")); - } +macro_rules! impl_consumertable_methods { + ($t:ty, $can_rehydrate:tt) => { + async fn read_data(&mut self) { + <$t>::read_data_async(self) + .await + .expect(concat!(stringify!($t::read_data_async), " io error")); + } + async fn pops(&mut self) -> Vec { + <$t>::pops_async(self) + .await + .expect(concat!(stringify!($t::pops_async), " threw an exception")) + } + async fn rehydrate(&mut self) -> Vec { + rehydrate_body!($can_rehydrate, self) + } + }; +} - async fn pops(&mut self) -> Vec { - <$t>::pops_async(self) - .await - .expect(concat!(stringify!($t::pops_async), " threw an exception")) +macro_rules! impl_consumertable { + // $table_name_method: ident or _ (underscore) if not present + ($($t:ty [$can_rehydrate:tt $table_name_method:tt]),* $(,)?) => { + $( + impl ConsumerTable for $t { + fn get_table_name(&self) -> &str { + impl_consumertable!(@call_table_name self $table_name_method) + } + impl_consumertable_methods!($t, $can_rehydrate); } + )* + }; - async fn rehydrate(&mut self) -> Vec { - rehydrate_body!($can_rehydrate, self) - } - })* + // Call the method if not _, else return "" + (@call_table_name $self:ident _) => { + "" + }; + (@call_table_name $self:ident $method:ident) => { + $self.$method() }; } -impl_consumertable! { ConsumerStateTable[true] SubscriberStateTable[true] ZmqConsumerStateTable[false] } +impl_consumertable! { + ConsumerStateTable[true table_name], + SubscriberStateTable[true table_name], + ZmqConsumerStateTable[false _], +} #[cfg(test)] mod test { diff --git a/test_utils/hamgrd/redis_data_set.cmd b/test_utils/hamgrd/redis_data_set.cmd index 314a19da..fe9407d9 100644 --- a/test_utils/hamgrd/redis_data_set.cmd +++ b/test_utils/hamgrd/redis_data_set.cmd @@ -68,17 +68,5 @@ HSET DPU_STATE|dpu7 dpu_control_plane_state up HSET DPU_STATE|dpu7 dpu_data_plane_state up select 0 -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 version "1" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 vip_v4 "3.2.1.0" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 vip_v6 "" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 owner "dpu" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 scope "dpu" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 vdpu_ids "vdpu0,vdpu1" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 pinned_vdpu_bfd_probe_states "" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 preferred_vdpu_ids "vdpu0" -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 preferred_standalone_vdpu_index "0" - -HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 version "1" -HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 disable "true" -HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 desired_ha_state "active" -HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 approved_pending_operation_ids "" +HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 pb "0a013112050d0001020320012801320576647075303205766470753142057664707530" +HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 pb "0a013110011802" From fea71172089ebfc12000c3952d0c3e6eafe9d783 Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 8 Jul 2025 10:49:51 -0400 Subject: [PATCH 02/20] Add submodule. --- crates/sonic-dash-api-proto/Cargo.toml | 16 +++++++++ crates/sonic-dash-api-proto/build.rs | 41 ++++++++++++++++++++++ crates/sonic-dash-api-proto/sonic-dash-api | 1 + crates/sonic-dash-api-proto/src/lib.rs | 11 ++++++ 4 files changed, 69 insertions(+) create mode 100644 crates/sonic-dash-api-proto/Cargo.toml create mode 100644 crates/sonic-dash-api-proto/build.rs create mode 160000 crates/sonic-dash-api-proto/sonic-dash-api create mode 100644 crates/sonic-dash-api-proto/src/lib.rs diff --git a/crates/sonic-dash-api-proto/Cargo.toml b/crates/sonic-dash-api-proto/Cargo.toml new file mode 100644 index 00000000..f5aa0ad2 --- /dev/null +++ b/crates/sonic-dash-api-proto/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "sonic-dash-api-proto" +version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +documentation.workspace = true +keywords.workspace = true +edition.workspace = true + +[dependencies] +prost.workspace = true +serde.workspace = true + +[build-dependencies] +prost-build = "0.13" diff --git a/crates/sonic-dash-api-proto/build.rs b/crates/sonic-dash-api-proto/build.rs new file mode 100644 index 00000000..99216c44 --- /dev/null +++ b/crates/sonic-dash-api-proto/build.rs @@ -0,0 +1,41 @@ +fn main() { + let proto_path = "sonic-dash-api/proto".to_string(); + + let mut proto_config = prost_build::Config::new(); + + proto_config.type_attribute( + "dash.ha_scope_config.HaScopeConfig", + "#[derive(serde::Serialize, serde::Deserialize)]", + ); + + proto_config.type_attribute( + "dash.ha_set_config.HaSetConfig", + "#[derive(serde::Serialize, serde::Deserialize)]", + ); + + proto_config.type_attribute( + "dash.types.IpAddress", + "#[derive(serde::Serialize, serde::Deserialize)]", + ); + + proto_config + .compile_protos( + &[ + format!("{proto_path}/ha_set_config.proto"), + format!("{proto_path}/ha_scope_config.proto"), + format!("{proto_path}/types.proto"), + ], + &[proto_path], + ) + .unwrap(); + + // --- PATCH GENERATED CODE FOR SERDE ON ONEOF ENUMS --- + let out_dir = std::env::var("OUT_DIR").unwrap(); + let types_rs = std::path::Path::new(&out_dir).join("dash.types.rs"); + let content = std::fs::read_to_string(&types_rs).unwrap(); + let patched = content.replace( + "#[derive(Clone, PartialEq, ::prost::Oneof)]\n pub enum Ip {", + "#[derive(Clone, PartialEq, ::prost::Oneof)]\n #[derive(serde::Serialize, serde::Deserialize)]\n pub enum Ip {" + ); + std::fs::write(&types_rs, patched).unwrap(); +} diff --git a/crates/sonic-dash-api-proto/sonic-dash-api b/crates/sonic-dash-api-proto/sonic-dash-api new file mode 160000 index 00000000..2ed8ff6f --- /dev/null +++ b/crates/sonic-dash-api-proto/sonic-dash-api @@ -0,0 +1 @@ +Subproject commit 2ed8ff6fe4cd89a1814953fba47a0d769ec867f1 diff --git a/crates/sonic-dash-api-proto/src/lib.rs b/crates/sonic-dash-api-proto/src/lib.rs new file mode 100644 index 00000000..db741a5c --- /dev/null +++ b/crates/sonic-dash-api-proto/src/lib.rs @@ -0,0 +1,11 @@ +pub mod ha_scope_config { + include!(concat!(env!("OUT_DIR"), "/dash.ha_scope_config.rs")); +} + +pub mod ha_set_config { + include!(concat!(env!("OUT_DIR"), "/dash.ha_set_config.rs")); +} + +pub mod types { + include!(concat!(env!("OUT_DIR"), "/dash.types.rs")); +} From 23e93188fb84ac4bf71886549f5cf54e418b5b0f Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 10 Jul 2025 11:28:08 -0400 Subject: [PATCH 03/20] Use protobuf struct directly. --- Cargo.lock | 3 ++ crates/hamgrd/src/actors/ha_scope.rs | 50 ++++++++++------------- crates/hamgrd/src/actors/ha_set.rs | 55 ++++++++++---------------- crates/hamgrd/src/db_structs.rs | 20 +--------- crates/hamgrd/src/main.rs | 9 ++--- crates/sonic-dash-api-proto/Cargo.toml | 3 ++ crates/sonic-dash-api-proto/build.rs | 34 ++++++++++++++++ 7 files changed, 86 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 456e3e7d..13f7ce10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1952,6 +1952,9 @@ dependencies = [ "prost", "prost-build", "serde", + "sonic-common", + "sonicdb-derive", + "swss-common", ] [[package]] diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index 6b874f2a..c5a9b219 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -20,7 +20,7 @@ pub struct HaScopeActor { id: String, ha_scope_id: String, vdpu_id: String, - dash_ha_scope_config: Option, + dash_ha_scope_config: Option, bridges: Vec, // we need to keep track the previous dpu_ha_scope_state to detect state change dpu_ha_scope_state: Option, @@ -28,7 +28,7 @@ pub struct HaScopeActor { impl DbBasedActor for HaScopeActor { fn new(key: String) -> Result { - if let Some((vdpu_id, ha_scope_id)) = key.split_once(DashHaScopeConfigTable::key_separator()) { + if let Some((vdpu_id, ha_scope_id)) = key.split_once(HaScopeConfig::key_separator()) { Ok(HaScopeActor { id: key.to_string(), vdpu_id: vdpu_id.to_string(), @@ -43,7 +43,7 @@ impl DbBasedActor for HaScopeActor { } fn table_name() -> &'static str { - DashHaScopeConfigTable::table_name() + HaScopeConfig::table_name() } fn name() -> &'static str { @@ -196,10 +196,7 @@ impl HaScopeActor { let mut activate_role_requested = false; let mut flow_reconcile_requested = false; - let approved_ops = dash_ha_scope_config - .ha_scope_config - .approved_pending_operation_ids - .clone(); + let approved_ops = dash_ha_scope_config.approved_pending_operation_ids.clone(); if !approved_ops.is_empty() { let pending_operations = self.get_pending_operations(internal, None)?; for op_id in approved_ops { @@ -228,9 +225,9 @@ impl HaScopeActor { } let dash_ha_scope = DashHaScopeTable { - version: dash_ha_scope_config.ha_scope_config.version.parse().unwrap(), - disable: dash_ha_scope_config.ha_scope_config.disabled, - ha_role: Self::desired_ha_state_to_ha_role(dash_ha_scope_config.ha_scope_config.desired_ha_state), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ + version: dash_ha_scope_config.version.parse().unwrap(), + disable: dash_ha_scope_config.disabled, + ha_role: Self::desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ flow_reconcile_requested, activate_role_requested, }; @@ -388,9 +385,8 @@ impl HaScopeActor { npu_ha_scope_state.local_ha_state_last_updated_reason = Some("dpu initiated".to_string()); // The target HA state in ASIC. This is the state that hamgrd generates and asking DPU to move to. - npu_ha_scope_state.local_target_asic_ha_state = Some(Self::desired_ha_state_to_ha_role( - dash_ha_scope_config.ha_scope_config.desired_ha_state, - )); + npu_ha_scope_state.local_target_asic_ha_state = + Some(Self::desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state)); // The HA state that ASIC acked. npu_ha_scope_state.local_acked_asic_ha_state = Some(dpu_ha_scope_state.ha_role.clone()); @@ -451,9 +447,7 @@ impl HaScopeActor { let dash_ha_scope_config: HaScopeConfig = decode_field_values_to_hascopeconfig(&kfv.field_values)?; // Update internal config - self.dash_ha_scope_config = Some(DashHaScopeConfigTable { - ha_scope_config: dash_ha_scope_config, - }); + self.dash_ha_scope_config = Some(dash_ha_scope_config); if first_time { // Subscribe to the vDPU Actor for state updates. @@ -478,7 +472,6 @@ impl HaScopeActor { .dash_ha_scope_config .as_ref() .unwrap() - .ha_scope_config .approved_pending_operation_ids .clone(); @@ -623,11 +616,10 @@ mod test { vdpu::VDpuActor, DbBasedActor, }, - db_structs::{ - now_in_millis, DashHaScopeConfigTable, DashHaScopeTable, DpuDashHaScopeState, NpuDashHaScopeState, - }, + db_structs::{now_in_millis, DashHaScopeTable, DpuDashHaScopeState, NpuDashHaScopeState}, ha_actor_messages::*, }; + use sonic_dash_api_proto::ha_scope_config::HaScopeConfig; use std::time::Duration; use swss_common::{SonicDbTable, Table}; use swss_common_testing::*; @@ -678,10 +670,10 @@ mod test { #[rustfmt::skip] let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state disabled - send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Set", + send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", "field_values": {"version": "\"1\"", "disabled": "true", "desired_ha_state": "2", "approved_pending_operation_ids": "[]" }, }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, // Recv registration to vDPU and ha-set recv! { key: ActorRegistration::msg_key(RegistrationType::VDPUState, &scope_id), data: { "active": true }, addr: runtime.sp(VDpuActor::name(), &vdpu0_id) }, @@ -711,10 +703,10 @@ mod test { chkdb! { db: NpuDashHaScopeState::db_name(), table: NpuDashHaScopeState::table_name(), key: &scope_id_in_state, data: npu_ha_scope_state_fvs2 }, // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state enabled - send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Set", + send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": "[]" }, }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, // Recv update to DPU DASH_HA_SCOPE_TABLE with disabled = false recv! { key: &ha_set_id, data: { "key": &ha_set_id, "operation": "Set", @@ -770,7 +762,7 @@ mod test { send! { key: HaScopeActor::table_name(), data: { "key": &scope_id, "operation": "Set", "field_values": {"version": "\"3\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": &op_id }, }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, // Recv update to DPU DASH_HA_SCOPE_TABLE with activate_role_requested=true recv! { key: &ha_set_id, data: { "key": &ha_set_id, "operation": "Set", @@ -808,20 +800,20 @@ mod test { #[rustfmt::skip] let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with desired_ha_state = dead - send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Set", + send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "1", "approved_pending_operation_ids": "[]" }, }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, // Check NPU DASH_HA_SCOPE_STATE is updated with desired_ha_state = dead chkdb! { db: NpuDashHaScopeState::db_name(), table: NpuDashHaScopeState::table_name(), key: &scope_id_in_state, data: npu_ha_scope_state_fvs7, exclude: "pending_operation_list_last_updated_time_in_ms" }, // simulate delete of ha-scope entry - send! { key: DashHaScopeConfigTable::table_name(), data: { "key": &scope_id, "operation": "Del", + send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Del", "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "1", "approved_pending_operation_ids": "[]" } }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; test::run_commands(&runtime, runtime.sp(HaScopeActor::name(), &scope_id), &commands).await; diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index 3e978b9e..057c236a 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -17,7 +17,7 @@ use tracing::{debug, error, info, instrument}; pub struct HaSetActor { id: String, - dash_ha_set_config: Option, + dash_ha_set_config: Option, bridges: Vec, } @@ -32,7 +32,7 @@ impl DbBasedActor for HaSetActor { } fn table_name() -> &'static str { - DashHaSetConfigTable::table_name() + HaSetConfig::table_name() } fn name() -> &'static str { @@ -97,16 +97,11 @@ impl HaSetActor { let global_cfg = Self::get_dash_global_config(incoming)?; let dash_ha_set = DashHaSetTable { - version: dash_ha_set_config.ha_set_config.version.clone(), - vip_v4: dash_ha_set_config - .ha_set_config - .vip_v4 - .as_ref() - .map(ip_to_string) - .unwrap_or_default(), - vip_v6: dash_ha_set_config.ha_set_config.vip_v6.as_ref().map(ip_to_string), - owner: format!("{:?}", dash_ha_set_config.ha_set_config.owner).into(), - scope: format!("{:?}", dash_ha_set_config.ha_set_config.scope).into(), + version: dash_ha_set_config.version.clone(), + vip_v4: dash_ha_set_config.vip_v4.as_ref().map(ip_to_string).unwrap_or_default(), + vip_v6: dash_ha_set_config.vip_v6.as_ref().map(ip_to_string), + owner: format!("{:?}", dash_ha_set_config.owner).into(), + scope: format!("{:?}", dash_ha_set_config.scope).into(), local_npu_ip: local_vdpu.dpu.npu_ipv4.clone(), local_ip: local_vdpu.dpu.pa_ipv4.clone(), peer_ip: remote_vdpu.dpu.pa_ipv4.clone(), @@ -197,7 +192,6 @@ impl HaSetActor { let msg = ActorRegistration::new_actor_msg(active, RegistrationType::VDPUState, &self.id)?; dash_ha_set_config - .ha_set_config .vdpu_ids .iter() .map(|id: &String| id.trim()) @@ -225,7 +219,6 @@ impl HaSetActor { return Vec::new(); }; - let ref ha_set_cfg = ha_set_cfg.ha_set_config; let mut result = Vec::new(); // Collect all preferred (primary) vdpus first @@ -291,24 +284,15 @@ impl HaSetActor { } let first_time = self.dash_ha_set_config.is_none(); - self.dash_ha_set_config = Some(DashHaSetConfigTable { - ha_set_config: decode_field_values_to_hasetconfig(&dpu_kfv.field_values).unwrap(), - }); + self.dash_ha_set_config = Some(decode_field_values_to_hasetconfig(&dpu_kfv.field_values).unwrap()); - let vip_v4_str = self - .dash_ha_set_config - .as_ref() - .unwrap() - .ha_set_config - .vip_v4 - .as_ref() - .map(|ip| { - if let Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) = &ip.ip { - std::net::Ipv4Addr::from(*addr).to_string() - } else { - "".to_string() - } - }); + let vip_v4_str = self.dash_ha_set_config.as_ref().unwrap().vip_v4.as_ref().map(|ip| { + if let Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) = &ip.ip { + std::net::Ipv4Addr::from(*addr).to_string() + } else { + "".to_string() + } + }); let swss_key = format!("default:{}", vip_v4_str.unwrap()); if !internal.has_entry(VnetRouteTunnelTable::table_name(), &swss_key) { @@ -421,6 +405,7 @@ mod test { db_structs::*, ha_actor_messages::*, }; + use sonic_dash_api_proto::ha_set_config::HaSetConfig; use std::collections::HashMap; use std::time::Duration; use swss_common::CxxString; @@ -497,7 +482,7 @@ mod test { let commands = [ // Send DASH_HA_SET_CONFIG_TABLE config send! { key: HaSetActor::table_name(), data: { "key": HaSetActor::table_name(), "operation": "Set", "field_values": ha_set_cfg_fvs }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, recv! { key: ActorRegistration::msg_key(RegistrationType::VDPUState, &ha_set_id), data: { "active": true }, addr: runtime.sp(VDpuActor::name(), &vdpu0_id) }, recv! { key: ActorRegistration::msg_key(RegistrationType::VDPUState, &ha_set_id), data: { "active": true }, @@ -519,7 +504,7 @@ mod test { chkdb! { db: "APPL_DB", table: "VNET_ROUTE_TUNNEL_TABLE", key: &format!("default:{}", ip_to_string(&ha_set_cfg.vip_v4.unwrap())), data: expected_vnet_route }, // simulate delete of ha-set entry send! { key: HaSetActor::table_name(), data: { "key": HaSetActor::table_name(), "operation": "Del", "field_values": ha_set_cfg_fvs }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; test::run_commands(&runtime, runtime.sp(HaSetActor::name(), &ha_set_id), &commands).await; @@ -578,7 +563,7 @@ mod test { let commands = [ // Send DASH_HA_SET_CONFIG_TABLE config send! { key: HaSetActor::table_name(), data: { "key": HaSetActor::table_name(), "operation": "Set", "field_values": ha_set_cfg_fvs }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, recv! { key: ActorRegistration::msg_key(RegistrationType::VDPUState, &ha_set_id), data: { "active": true }, addr: runtime.sp(VDpuActor::name(), &vdpu0_id) }, recv! { key: ActorRegistration::msg_key(RegistrationType::VDPUState, &ha_set_id), data: { "active": true }, @@ -593,7 +578,7 @@ mod test { data: expected_vnet_route }, // simulate delete of ha-set entry send! { key: HaSetActor::table_name(), data: { "key": HaSetActor::table_name(), "operation": "Del", "field_values": ha_set_cfg_fvs }, - addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, + addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; test::run_commands(&runtime, runtime.sp(HaSetActor::name(), &ha_set_id), &commands).await; diff --git a/crates/hamgrd/src/db_structs.rs b/crates/hamgrd/src/db_structs.rs index 42532d79..958a808a 100644 --- a/crates/hamgrd/src/db_structs.rs +++ b/crates/hamgrd/src/db_structs.rs @@ -2,7 +2,7 @@ use anyhow::{Context, Result}; use chrono::DateTime; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde_with::{formats::CommaSeparator, serde_as, skip_serializing_none, StringWithSeparator}; -use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig, types::*}; +use sonic_dash_api_proto::types::*; use sonicdb_derive::SonicDb; use swss_common::{DbConnector, Table}; use swss_serde::from_table; @@ -202,15 +202,6 @@ pub fn now_in_millis() -> i64 { chrono::Utc::now().timestamp_millis() } -/// -#[serde_as] -#[skip_serializing_none] -#[derive(Serialize, Deserialize, SonicDb)] -#[sonicdb(table_name = "DASH_HA_SET_CONFIG_TABLE", key_separator = ":", db_name = "APPL_DB")] -pub struct DashHaSetConfigTable { - pub ha_set_config: HaSetConfig, -} - /// #[skip_serializing_none] #[derive(Serialize, Deserialize, Default, PartialEq, Eq, SonicDb)] @@ -264,15 +255,6 @@ pub struct VnetRouteTunnelTable { pub check_directly_connected: Option, } -/// -#[skip_serializing_none] -#[serde_as] -#[derive(Debug, Deserialize, Serialize, PartialEq, SonicDb)] -#[sonicdb(table_name = "DASH_HA_SCOPE_CONFIG_TABLE", key_separator = ":", db_name = "APPL_DB")] -pub struct DashHaScopeConfigTable { - pub ha_scope_config: HaScopeConfig, -} - /// #[skip_serializing_none] #[serde_as] diff --git a/crates/hamgrd/src/main.rs b/crates/hamgrd/src/main.rs index 57f00879..f11413cb 100644 --- a/crates/hamgrd/src/main.rs +++ b/crates/hamgrd/src/main.rs @@ -16,9 +16,8 @@ mod ha_actor_messages; use actors::spawn_zmq_producer_bridge; use actors::{dpu::DpuActor, ha_scope::HaScopeActor, ha_set::HaSetActor, vdpu::VDpuActor, DbBasedActor}; use anyhow::Result; -use db_structs::{ - BfdSessionTable, DashHaScopeConfigTable, DashHaScopeTable, DashHaSetConfigTable, DashHaSetTable, Dpu, VDpu, -}; +use db_structs::{BfdSessionTable, DashHaScopeTable, DashHaSetTable, Dpu, VDpu}; +use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig}; use std::any::Any; #[derive(Parser, Debug)] @@ -117,8 +116,8 @@ async fn start_actor_creators(edge_runtime: &Arc) -> Result = Vec::new(); bridges.append(&mut DpuActor::start_actor_creator(edge_runtime.clone()).await?); bridges.append(&mut VDpuActor::start_actor_creator::(edge_runtime.clone()).await?); - bridges.append(&mut HaSetActor::start_actor_creator::(edge_runtime.clone()).await?); - bridges.append(&mut HaScopeActor::start_actor_creator::(edge_runtime.clone()).await?); + bridges.append(&mut HaSetActor::start_actor_creator::(edge_runtime.clone()).await?); + bridges.append(&mut HaScopeActor::start_actor_creator::(edge_runtime.clone()).await?); Ok(bridges) } diff --git a/crates/sonic-dash-api-proto/Cargo.toml b/crates/sonic-dash-api-proto/Cargo.toml index f5aa0ad2..cf290e63 100644 --- a/crates/sonic-dash-api-proto/Cargo.toml +++ b/crates/sonic-dash-api-proto/Cargo.toml @@ -11,6 +11,9 @@ edition.workspace = true [dependencies] prost.workspace = true serde.workspace = true +sonicdb-derive.workspace = true +swss-common = { path = "../swss-common" } +sonic-common.workspace = true [build-dependencies] prost-build = "0.13" diff --git a/crates/sonic-dash-api-proto/build.rs b/crates/sonic-dash-api-proto/build.rs index 99216c44..39dcc08d 100644 --- a/crates/sonic-dash-api-proto/build.rs +++ b/crates/sonic-dash-api-proto/build.rs @@ -3,11 +3,45 @@ fn main() { let mut proto_config = prost_build::Config::new(); + proto_config.type_attribute( + "dash.ha_scope_config.HaScopeConfig", + "#[allow(unused_imports)] use sonicdb_derive::SonicDb;", + ); + + proto_config.type_attribute( + "dash.ha_scope_config.HaScopeConfig", + "#[allow(unused_imports)] use swss_common::{DbConnector, Table};", + ); + + proto_config.type_attribute("dash.ha_scope_config.HaScopeConfig", "#[derive(SonicDb)]"); + + proto_config.type_attribute( + "dash.ha_scope_config.HaScopeConfig", + "#[sonicdb(table_name = \"DASH_HA_SCOPE_CONFIG_TABLE\", key_separator = \":\", db_name = \"APPL_DB\")]", + ); + proto_config.type_attribute( "dash.ha_scope_config.HaScopeConfig", "#[derive(serde::Serialize, serde::Deserialize)]", ); + proto_config.type_attribute( + "dash.ha_set_config.HaSetConfig", + "#[allow(unused_imports)] use sonicdb_derive::SonicDb;", + ); + + proto_config.type_attribute( + "dash.ha_set_config.HaSetConfig", + "#[allow(unused_imports)] use swss_common::{DbConnector, Table};", + ); + + proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "#[derive(SonicDb)]"); + + proto_config.type_attribute( + "dash.ha_set_config.HaSetConfig", + "#[sonicdb(table_name = \"DASH_HA_SET_CONFIG_TABLE\", key_separator = \":\", db_name = \"APPL_DB\")]", + ); + proto_config.type_attribute( "dash.ha_set_config.HaSetConfig", "#[derive(serde::Serialize, serde::Deserialize)]", From a18a3b0bf1c590e48be3449cd923de9164d6dfed Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 10 Jul 2025 14:15:38 -0400 Subject: [PATCH 04/20] encode/decode to single json string. --- crates/hamgrd/src/actors.rs | 17 ++++++++---- crates/hamgrd/src/actors/ha_scope.rs | 32 +++++------------------ crates/hamgrd/src/actors/ha_set.rs | 30 +++------------------ crates/hamgrd/src/db_structs.rs | 11 +++++++- crates/swss-common-bridge/src/consumer.rs | 14 ++++------ 5 files changed, 37 insertions(+), 67 deletions(-) diff --git a/crates/hamgrd/src/actors.rs b/crates/hamgrd/src/actors.rs index 9c03766a..3027728e 100644 --- a/crates/hamgrd/src/actors.rs +++ b/crates/hamgrd/src/actors.rs @@ -144,22 +144,29 @@ where if let Some(Body::DataRequest(DataRequest { payload })) = &msg.body { match ActorMessage::deserialize(payload) { Ok(actor_msg) => { - let kfv: KeyOpFieldValues = actor_msg.deserialize_data().map_err(|_| { + let key: String = serde_json::from_value(actor_msg.data["key"].clone()).map_err(|_| { SwbusError::input( SwbusErrorCode::InvalidPayload, - "cannot decode as ActorMessage".to_string(), + "cannot decode ActorMessage key".to_string(), ) })?; + let operation: KeyOperation = + serde_json::from_value(actor_msg.data["operation"].clone()).map_err(|_| { + SwbusError::input( + SwbusErrorCode::InvalidPayload, + "cannot decode ActorMessage operation".to_string(), + ) + })?; - if kfv.operation == KeyOperation::Del { + if operation == KeyOperation::Del { return Err(SwbusError::input( SwbusErrorCode::NoRoute, "actor doesn't exist: won't create actor for DEL kfv".to_string(), )); } - let actor = (self.create_fn)(kfv.key.clone()).map_err(|e| { + let actor = (self.create_fn)(key.clone()).map_err(|e| { let mut sp = self.sp.clone(); - sp.resource_id = kfv.key.clone(); + sp.resource_id = key.clone(); SwbusError::input( SwbusErrorCode::Fail, format!("Failed to create actor {}. Error: {}", sp.to_swbusd_service_path(), e), diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index c5a9b219..383aaadb 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -9,7 +9,6 @@ use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, Actor, ActorMessage, Context, State, }; -use swss_common::CxxString; use swss_common::Table; use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; use swss_common_bridge::consumer::ConsumerBridge; @@ -401,24 +400,6 @@ impl HaScopeActor { } } -fn decode_field_values_to_hascopeconfig( - field_values: &HashMap, -) -> Result { - use serde_json::Value; - - let mut json_map = serde_json::Map::new(); - for (k, v) in field_values { - let s = v.to_string_lossy(); - let value = match serde_json::from_str::(&s) { - Ok(val) => val, - Err(_) => Value::String(s.into_owned()), - }; - json_map.insert(k.clone(), value); - } - let json_value = Value::Object(json_map); - serde_json::from_value(json_value) -} - // Implements messages handlers for HaScopeActor impl HaScopeActor { /// Handles updates to the DASH_HA_SCOPE_CONFIG_TABLE. @@ -444,7 +425,7 @@ impl HaScopeActor { return Ok(()); } let first_time = self.dash_ha_scope_config.is_none(); - let dash_ha_scope_config: HaScopeConfig = decode_field_values_to_hascopeconfig(&kfv.field_values)?; + let dash_ha_scope_config: HaScopeConfig = decode_from_json_string(&kfv.field_values)?; // Update internal config self.dash_ha_scope_config = Some(dash_ha_scope_config); @@ -671,7 +652,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state disabled send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "\"1\"", "disabled": "true", "desired_ha_state": "2", "approved_pending_operation_ids": "[]" }, + "field_values": {"json": "{\"version\":\"1\",\"disabled\":true,\"desired_ha_state\":2,\"approved_pending_operation_ids\":[]}"}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -704,7 +685,7 @@ mod test { // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state enabled send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": "[]" }, + "field_values": {"json": "{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":2,\"approved_pending_operation_ids\":[]}"}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -760,7 +741,8 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with activation approved send! { key: HaScopeActor::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "\"3\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": &op_id }, + "field_values": {"json": format!("{{\"version\":\"3\",\"disabled\":false,\"desired_ha_state\":2,\"approved_pending_operation_ids\":{}}}", &op_id)}, + // "field_values": {"version": "\"3\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": &op_id }, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -801,7 +783,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with desired_ha_state = dead send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "1", "approved_pending_operation_ids": "[]" }, + "field_values": {"json": "{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":1,\"approved_pending_operation_ids\":[]}"}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -811,7 +793,7 @@ mod test { // simulate delete of ha-scope entry send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Del", - "field_values": {"version": "\"2\"", "disabled": "false", "desired_ha_state": "1", "approved_pending_operation_ids": "[]" } + "field_values": {"json": "{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":1,\"approved_pending_operation_ids\":[]}"}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index 057c236a..bcd3e541 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -4,12 +4,10 @@ use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use anyhow::Result; use sonic_dash_api_proto::ha_set_config::HaSetConfig; -use std::collections::HashMap; use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, Actor, ActorMessage, Context, State, }; -use swss_common::CxxString; use swss_common::Table; use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; use swss_common_bridge::consumer::ConsumerBridge; @@ -45,24 +43,6 @@ struct VDpuStateExt { is_primary: bool, } -fn decode_field_values_to_hasetconfig( - field_values: &HashMap, -) -> Result { - use serde_json::Value; - - let mut json_map = serde_json::Map::new(); - for (k, v) in field_values { - let s = v.to_string_lossy(); - let value = match serde_json::from_str::(&s) { - Ok(val) => val, - Err(_) => Value::String(s.into_owned()), - }; - json_map.insert(k.clone(), value); - } - let json_value = Value::Object(json_map); - serde_json::from_value(json_value) -} - impl HaSetActor { fn get_dash_global_config(incoming: &Incoming) -> Result { let kfv: KeyOpFieldValues = incoming.get(DashHaGlobalConfig::table_name())?.deserialize_data()?; @@ -284,7 +264,7 @@ impl HaSetActor { } let first_time = self.dash_ha_set_config.is_none(); - self.dash_ha_set_config = Some(decode_field_values_to_hasetconfig(&dpu_kfv.field_values).unwrap()); + self.dash_ha_set_config = Some(decode_from_json_string(&dpu_kfv.field_values).unwrap()); let vip_v4_str = self.dash_ha_set_config.as_ref().unwrap().vip_v4.as_ref().map(|ip| { if let Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) = &ip.ip { @@ -414,18 +394,14 @@ mod test { use swss_common_testing::*; fn protobuf_struct_to_json(cfg: &T) -> HashMap { - let json = serde_json::to_value(cfg).unwrap(); + let json = serde_json::to_string(&cfg).unwrap(); let mut kfv = KeyOpFieldValues { key: HaSetActor::table_name().to_string(), operation: KeyOperation::Set, field_values: HashMap::new(), }; kfv.field_values.clear(); - if let serde_json::Value::Object(map) = json { - for (k, v) in map { - kfv.field_values.insert(k, v.to_string().into()); - } - } + kfv.field_values.insert("json".to_string(), json.into()); kfv.field_values.clone() } diff --git a/crates/hamgrd/src/db_structs.rs b/crates/hamgrd/src/db_structs.rs index 958a808a..73c9759d 100644 --- a/crates/hamgrd/src/db_structs.rs +++ b/crates/hamgrd/src/db_structs.rs @@ -4,7 +4,8 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde_with::{formats::CommaSeparator, serde_as, skip_serializing_none, StringWithSeparator}; use sonic_dash_api_proto::types::*; use sonicdb_derive::SonicDb; -use swss_common::{DbConnector, Table}; +use std::collections::HashMap; +use swss_common::{CxxString, DbConnector, Table}; use swss_serde::from_table; /// Format: "Tue Jun 04 09:00:00 PM UTC 2024" @@ -410,6 +411,14 @@ pub fn ip_to_string(ip: &IpAddress) -> String { } } +pub fn decode_from_json_string serde::Deserialize<'de>>( + field_values: &HashMap, +) -> Result { + let json_str = field_values.get("json").unwrap(); + let s = json_str.to_string_lossy().into_owned(); + serde_json::from_str(&s) +} + #[cfg(test)] mod test { use super::*; diff --git a/crates/swss-common-bridge/src/consumer.rs b/crates/swss-common-bridge/src/consumer.rs index 86e5de59..8dba5b4b 100644 --- a/crates/swss-common-bridge/src/consumer.rs +++ b/crates/swss-common-bridge/src/consumer.rs @@ -56,15 +56,11 @@ pub fn parse_from_protobuf(kfv: &KeyOpFieldValues) -> anyh Ok(Some(config)) } -pub fn convert_pb_to_json_fields(kfv: &mut KeyOpFieldValues) { +pub fn convert_pb_to_json(kfv: &mut KeyOpFieldValues) { if let Some(cfg) = parse_from_protobuf::(kfv).unwrap_or(None) { - let json = serde_json::to_value(&cfg).unwrap(); + let json = serde_json::to_string(&cfg).unwrap(); kfv.field_values.clear(); - if let serde_json::Value::Object(map) = json { - for (k, v) in map { - kfv.field_values.insert(k, v.to_string().into()); - } - } + kfv.field_values.insert("json".to_string(), json.into()); } } @@ -88,10 +84,10 @@ where // Decode protobuf and re-encode as JSON for tables that use protobuf match table_name.as_str() { "DASH_HA_SET_CONFIG_TABLE" => { - convert_pb_to_json_fields::(&mut kfv); + convert_pb_to_json::(&mut kfv); } "DASH_HA_SCOPE_CONFIG_TABLE" => { - convert_pb_to_json_fields::(&mut kfv); + convert_pb_to_json::(&mut kfv); } _ => {} } From c2f290338dbf93754722a9dbc00b54e05f358eea Mon Sep 17 00:00:00 2001 From: dypet Date: Fri, 11 Jul 2025 13:07:35 -0400 Subject: [PATCH 05/20] Use trait instead of matching on table name. --- Cargo.lock | 3 + crates/hamgrd/src/actors.rs | 6 +- crates/hamgrd/src/actors/dpu.rs | 4 +- crates/sonic-dash-api-proto/Cargo.toml | 2 + crates/sonic-dash-api-proto/build.rs | 8 +- crates/sonicdb-derive/src/lib.rs | 63 +++++++++++- crates/swss-common-bridge/Cargo.toml | 1 + crates/swss-common-bridge/src/consumer.rs | 118 +++++++--------------- crates/swss-common/src/lib.rs | 7 ++ 9 files changed, 119 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13f7ce10..7eca4543 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1949,9 +1949,11 @@ dependencies = [ name = "sonic-dash-api-proto" version = "0.1.0" dependencies = [ + "hex", "prost", "prost-build", "serde", + "serde_json", "sonic-common", "sonicdb-derive", "swss-common", @@ -2165,6 +2167,7 @@ dependencies = [ "serde", "serde_json", "sonic-dash-api-proto", + "sonicdb-derive", "swbus-actor", "swbus-edge", "swss-common", diff --git a/crates/hamgrd/src/actors.rs b/crates/hamgrd/src/actors.rs index 3027728e..aa798195 100644 --- a/crates/hamgrd/src/actors.rs +++ b/crates/hamgrd/src/actors.rs @@ -49,7 +49,7 @@ pub trait DbBasedActor: Actor { let sst = SubscriberStateTable::new_async(config_db, T::table_name(), None, None).await?; let addr = crate::common_bridge_sp::(&edge_runtime); let base_addr = edge_runtime.get_base_sp(); - Ok(vec![ConsumerBridge::spawn( + Ok(vec![ConsumerBridge::spawn::( edge_runtime.clone(), addr, sst, @@ -228,7 +228,7 @@ where if actor_id.is_some() { let sp = edge_runtime.new_sp(actor_name, actor_id.unwrap()); - Ok(ConsumerBridge::spawn( + Ok(ConsumerBridge::spawn::( edge_runtime, addr, sst, @@ -243,7 +243,7 @@ where )) } else { let base_addr = edge_runtime.get_base_sp(); - Ok(ConsumerBridge::spawn( + Ok(ConsumerBridge::spawn::( edge_runtime, addr, sst, diff --git a/crates/hamgrd/src/actors/dpu.rs b/crates/hamgrd/src/actors/dpu.rs index f1d42701..f919f9d5 100644 --- a/crates/hamgrd/src/actors/dpu.rs +++ b/crates/hamgrd/src/actors/dpu.rs @@ -92,7 +92,7 @@ impl DpuActor { let sst = SubscriberStateTable::new_async(config_db, Self::dpu_table_name(), None, None).await?; let addr = crate::common_bridge_sp::(&edge_runtime); let base_addr = edge_runtime.get_base_sp(); - bridges.push(ConsumerBridge::spawn( + bridges.push(ConsumerBridge::spawn::( edge_runtime.clone(), addr, sst, @@ -109,7 +109,7 @@ impl DpuActor { let sst = SubscriberStateTable::new_async(config_db, Self::remote_dpu_table_name(), None, None).await?; let addr = crate::common_bridge_sp::(&edge_runtime); let base_addr = edge_runtime.get_base_sp(); - bridges.push(ConsumerBridge::spawn( + bridges.push(ConsumerBridge::spawn::( edge_runtime.clone(), addr, sst, diff --git a/crates/sonic-dash-api-proto/Cargo.toml b/crates/sonic-dash-api-proto/Cargo.toml index cf290e63..178c78f4 100644 --- a/crates/sonic-dash-api-proto/Cargo.toml +++ b/crates/sonic-dash-api-proto/Cargo.toml @@ -14,6 +14,8 @@ serde.workspace = true sonicdb-derive.workspace = true swss-common = { path = "../swss-common" } sonic-common.workspace = true +hex = "0.4" +serde_json.workspace = true [build-dependencies] prost-build = "0.13" diff --git a/crates/sonic-dash-api-proto/build.rs b/crates/sonic-dash-api-proto/build.rs index 39dcc08d..97e13879 100644 --- a/crates/sonic-dash-api-proto/build.rs +++ b/crates/sonic-dash-api-proto/build.rs @@ -10,14 +10,14 @@ fn main() { proto_config.type_attribute( "dash.ha_scope_config.HaScopeConfig", - "#[allow(unused_imports)] use swss_common::{DbConnector, Table};", + "#[allow(unused_imports)] use swss_common::{DbConnector, Table, KeyOpFieldValues}; use prost::Message;", ); proto_config.type_attribute("dash.ha_scope_config.HaScopeConfig", "#[derive(SonicDb)]"); proto_config.type_attribute( "dash.ha_scope_config.HaScopeConfig", - "#[sonicdb(table_name = \"DASH_HA_SCOPE_CONFIG_TABLE\", key_separator = \":\", db_name = \"APPL_DB\")]", + "#[sonicdb(table_name = \"DASH_HA_SCOPE_CONFIG_TABLE\", key_separator = \":\", db_name = \"APPL_DB\", is_proto = \"true\",)]", ); proto_config.type_attribute( @@ -32,14 +32,14 @@ fn main() { proto_config.type_attribute( "dash.ha_set_config.HaSetConfig", - "#[allow(unused_imports)] use swss_common::{DbConnector, Table};", + "#[allow(unused_imports)] use swss_common::{DbConnector, Table, KeyOpFieldValues}; use prost::Message;", ); proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "#[derive(SonicDb)]"); proto_config.type_attribute( "dash.ha_set_config.HaSetConfig", - "#[sonicdb(table_name = \"DASH_HA_SET_CONFIG_TABLE\", key_separator = \":\", db_name = \"APPL_DB\")]", + "#[sonicdb(table_name = \"DASH_HA_SET_CONFIG_TABLE\", key_separator = \":\", db_name = \"APPL_DB\", is_proto = \"true\",)]", ); proto_config.type_attribute( diff --git a/crates/sonicdb-derive/src/lib.rs b/crates/sonicdb-derive/src/lib.rs index 17a2a979..c8225f13 100644 --- a/crates/sonicdb-derive/src/lib.rs +++ b/crates/sonicdb-derive/src/lib.rs @@ -15,6 +15,7 @@ pub fn serde_sonicdb_derive(input: TokenStream) -> TokenStream { let mut table_name: String = "".to_string(); let mut key_separator: char = 'a'; let mut db_name: String = "".to_string(); + let mut protobuf_encoded: bool = false; for attr in &input.attrs { if attr.path().is_ident("sonicdb") { attr.parse_nested_meta(|meta| { @@ -39,6 +40,14 @@ pub fn serde_sonicdb_derive(input: TokenStream) -> TokenStream { let s: LitStr = value.parse()?; db_name = s.value(); Ok(()) + } else if meta.path.is_ident("is_proto") { + let value = meta.value()?; // this parses the `=` + let proto_bool: LitStr = value.parse()?; + match proto_bool.value().to_lowercase().as_str() { + "true" => protobuf_encoded = true, + _ => protobuf_encoded = false, + } + Ok(()) } else { Err(meta.error("unknown attribute")) } @@ -72,6 +81,56 @@ pub fn serde_sonicdb_derive(input: TokenStream) -> TokenStream { } }; - // Return the generated code - TokenStream::from(expanded) + let expanded_proto = quote! { + impl swss_common::SonicDbTable for #struct_name { + fn key_separator() -> char { + #key_separator + } + + fn table_name() -> &'static str { + #table_name + } + + fn db_name() -> &'static str { + #db_name + } + + fn is_proto() -> bool { + true + } + + fn convert_pb_to_json(kfv: &mut KeyOpFieldValues) { + let value_hex = match kfv.field_values.get("pb") { + Some(v) => v.to_str().ok(), + None => None, + }; + let value_hex = match value_hex { + Some(s) if !s.is_empty() => s, + _ => return, + }; + let value_bytes = match hex::decode(value_hex) { + Ok(bytes) => bytes, + Err(_) => return, + }; + let config = match #struct_name::decode(&*value_bytes) { + Ok(cfg) => cfg, + Err(_) => return, + }; + + let json = match serde_json::to_string(&config) { + Ok(j) => j, + Err(_) => return, + }; + kfv.field_values.clear(); + kfv.field_values.insert("json".to_string(), json.into()); + } + } + }; + + if protobuf_encoded { + // If the struct is protobuf encoded, include the proto implementation + TokenStream::from(expanded_proto) + } else { + TokenStream::from(expanded) + } } diff --git a/crates/swss-common-bridge/Cargo.toml b/crates/swss-common-bridge/Cargo.toml index b42b7806..cc951ebe 100644 --- a/crates/swss-common-bridge/Cargo.toml +++ b/crates/swss-common-bridge/Cargo.toml @@ -20,6 +20,7 @@ prost.workspace = true hex = "0.4" serde.workspace = true serde_json.workspace = true +sonicdb-derive.workspace = true [lints] workspace = true diff --git a/crates/swss-common-bridge/src/consumer.rs b/crates/swss-common-bridge/src/consumer.rs index 8dba5b4b..2e11055e 100644 --- a/crates/swss-common-bridge/src/consumer.rs +++ b/crates/swss-common-bridge/src/consumer.rs @@ -1,5 +1,3 @@ -use prost::Message; -use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig}; use std::{collections::HashMap, future::Future, sync::Arc}; use swbus_actor::ActorMessage; use swbus_edge::{ @@ -8,7 +6,8 @@ use swbus_edge::{ SwbusEdgeRuntime, }; use swss_common::{ - ConsumerStateTable, FieldValues, KeyOpFieldValues, KeyOperation, SubscriberStateTable, Table, ZmqConsumerStateTable, + ConsumerStateTable, FieldValues, KeyOpFieldValues, KeyOperation, SonicDbTable, SubscriberStateTable, Table, + ZmqConsumerStateTable, }; use tokio::task::JoinHandle; use tokio_util::task::AbortOnDropHandle; @@ -23,7 +22,7 @@ impl ConsumerBridge { /// `dest_generator` is a function that takes a `&KeyOpFieldValues` read from `table` /// and generates the `ServicePath` address and `String` input table key that /// the data will be sent to. - pub fn spawn( + pub fn spawn( rt: Arc, addr: ServicePath, table: T, @@ -31,40 +30,19 @@ impl ConsumerBridge { selector: S, ) -> Self where + P: SonicDbTable, T: ConsumerTable, F: FnMut(&KeyOpFieldValues) -> (ServicePath, String) + Send + 'static, S: Fn(&KeyOpFieldValues) -> bool + Sync + Send + 'static, { - let task = spawn_consumer_bridge(rt, addr, table, dest_generator, selector); + let task = spawn_consumer_bridge::(rt, addr, table, dest_generator, selector); ConsumerBridge { _task: AbortOnDropHandle::new(task), } } } -pub fn parse_from_protobuf(kfv: &KeyOpFieldValues) -> anyhow::Result> { - let value_hex = match kfv.field_values.get("pb") { - Some(v) => v.to_str().ok(), - None => None, - }; - let value_hex = match value_hex { - Some(s) if !s.is_empty() => s, - _ => return Ok(None), - }; - let value_bytes = hex::decode(value_hex)?; - let config = T::decode(&*value_bytes)?; - Ok(Some(config)) -} - -pub fn convert_pb_to_json(kfv: &mut KeyOpFieldValues) { - if let Some(cfg) = parse_from_protobuf::(kfv).unwrap_or(None) { - let json = serde_json::to_string(&cfg).unwrap(); - kfv.field_values.clear(); - kfv.field_values.insert("json".to_string(), json.into()); - } -} - -pub fn spawn_consumer_bridge( +pub fn spawn_consumer_bridge( rt: Arc, addr: ServicePath, mut table: T, @@ -72,24 +50,17 @@ pub fn spawn_consumer_bridge( selector: S, ) -> JoinHandle<()> where + P: SonicDbTable, T: ConsumerTable, F: FnMut(&KeyOpFieldValues) -> (ServicePath, String) + Send + 'static, S: Fn(&KeyOpFieldValues) -> bool + Sync + Send + 'static, { - let table_name = table.get_table_name().to_owned(); let swbus = SimpleSwbusEdgeClient::new(rt, addr, false, false); tokio::task::spawn(async move { let mut table_cache = TableCache::default(); let mut send_kfv = async |mut kfv: KeyOpFieldValues| { - // Decode protobuf and re-encode as JSON for tables that use protobuf - match table_name.as_str() { - "DASH_HA_SET_CONFIG_TABLE" => { - convert_pb_to_json::(&mut kfv); - } - "DASH_HA_SCOPE_CONFIG_TABLE" => { - convert_pb_to_json::(&mut kfv); - } - _ => {} + if P::is_proto() { + P::convert_pb_to_json(&mut kfv); } // Merge the kfv to get the whole table as an update @@ -178,9 +149,6 @@ pub trait ConsumerTable: Send + 'static { /// Dump the table, as if `pops()` returned everything again, for rehydration after a restart fn rehydrate(&mut self) -> impl Future> + Send; - - /// Return the table name for this instance - fn get_table_name(&self) -> &str; } macro_rules! rehydrate_body { @@ -209,56 +177,35 @@ macro_rules! rehydrate_body { }; } -macro_rules! impl_consumertable_methods { - ($t:ty, $can_rehydrate:tt) => { - async fn read_data(&mut self) { - <$t>::read_data_async(self) - .await - .expect(concat!(stringify!($t::read_data_async), " io error")); - } - async fn pops(&mut self) -> Vec { - <$t>::pops_async(self) - .await - .expect(concat!(stringify!($t::pops_async), " threw an exception")) - } - async fn rehydrate(&mut self) -> Vec { - rehydrate_body!($can_rehydrate, self) - } - }; -} - macro_rules! impl_consumertable { - // $table_name_method: ident or _ (underscore) if not present - ($($t:ty [$can_rehydrate:tt $table_name_method:tt]),* $(,)?) => { - $( - impl ConsumerTable for $t { - fn get_table_name(&self) -> &str { - impl_consumertable!(@call_table_name self $table_name_method) - } - impl_consumertable_methods!($t, $can_rehydrate); + ($($t:ty [$can_rehydrate:tt])*) => { + $(impl ConsumerTable for $t { + async fn read_data(&mut self) { + <$t>::read_data_async(self) + .await + .expect(concat!(stringify!($t::read_data_async), " io error")); } - )* - }; - // Call the method if not _, else return "" - (@call_table_name $self:ident _) => { - "" - }; - (@call_table_name $self:ident $method:ident) => { - $self.$method() + async fn pops(&mut self) -> Vec { + <$t>::pops_async(self) + .await + .expect(concat!(stringify!($t::pops_async), " threw an exception")) + } + + async fn rehydrate(&mut self) -> Vec { + rehydrate_body!($can_rehydrate, self) + } + })* }; } -impl_consumertable! { - ConsumerStateTable[true table_name], - SubscriberStateTable[true table_name], - ZmqConsumerStateTable[false _], -} +impl_consumertable! { ConsumerStateTable[true] SubscriberStateTable[true] ZmqConsumerStateTable[false] } #[cfg(test)] mod test { use super::{spawn_consumer_bridge, ConsumerTable}; use crate::producer::ProducerTable; + use sonicdb_derive::SonicDb; use std::{sync::Arc, time::Duration}; use swbus_actor::ActorMessage; use swbus_edge::{ @@ -273,6 +220,13 @@ mod test { use swss_common_testing::{random_kfvs, random_zmq_endpoint, Redis}; use tokio::time::timeout; + #[derive(SonicDb)] + #[sonicdb(table_name = "MY_STRUCT", key_separator = ":", db_name = "db1")] + struct MyStruct { + _id1: String, + _attr1: Option, + } + #[tokio::test] async fn consumer_state_table_bridge() { let redis = Redis::start(); @@ -312,7 +266,7 @@ mod test { let swbus = SimpleSwbusEdgeClient::new(rt.clone(), sp("receiver"), true, false); // Spawn the bridge - let bridge = spawn_consumer_bridge( + let bridge = spawn_consumer_bridge::( rt.clone(), sp("mytable-bridge"), consumer_table, @@ -338,7 +292,7 @@ mod test { // Test rehydration if let Some(rehydrate_table) = rehydrate_table { // Spawn new bridge to rehydrate with - let _bridge_rehydrate = spawn_consumer_bridge( + let _bridge_rehydrate = spawn_consumer_bridge::( rt, sp("mytable-bridge"), rehydrate_table, diff --git a/crates/swss-common/src/lib.rs b/crates/swss-common/src/lib.rs index 27e8c545..5bcf7a27 100644 --- a/crates/swss-common/src/lib.rs +++ b/crates/swss-common/src/lib.rs @@ -23,4 +23,11 @@ pub trait SonicDbTable { fn key_separator() -> char; fn table_name() -> &'static str; fn db_name() -> &'static str; + fn is_proto() -> bool { + false + } + fn convert_pb_to_json(_kfv: &mut KeyOpFieldValues) { + // Default implementation does nothing. + // This can be overridden by the macro to convert protobuf to JSON. + } } From ac35e679b1a37baf8e73e398639de0d9c8fbcb1c Mon Sep 17 00:00:00 2001 From: dypet Date: Mon, 14 Jul 2025 12:51:12 -0400 Subject: [PATCH 06/20] testcase update. --- crates/hamgrd/src/actors/ha_scope.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index 383aaadb..5e79ffe7 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -725,7 +725,7 @@ mod test { let npu_ha_scope_state_fvs4 = to_field_values(&npu_ha_scope_state4).unwrap(); let mut dpu_ha_state_state5 = make_dpu_ha_scope_state("active"); - dpu_ha_state_state5.ha_term = "active".to_string(); + dpu_ha_state_state5.ha_term = "2".to_string(); let mut npu_ha_scope_state5: NpuDashHaScopeState = npu_ha_scope_state4.clone(); update_npu_ha_scope_state_by_dpu_scope_state(&mut npu_ha_scope_state5, &dpu_ha_state_state5, "active"); let npu_ha_scope_state_fvs5 = to_field_values(&npu_ha_scope_state5).unwrap(); @@ -742,7 +742,6 @@ mod test { // Send DASH_HA_SCOPE_CONFIG_TABLE with activation approved send! { key: HaScopeActor::table_name(), data: { "key": &scope_id, "operation": "Set", "field_values": {"json": format!("{{\"version\":\"3\",\"disabled\":false,\"desired_ha_state\":2,\"approved_pending_operation_ids\":{}}}", &op_id)}, - // "field_values": {"version": "\"3\"", "disabled": "false", "desired_ha_state": "2", "approved_pending_operation_ids": &op_id }, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, From 96634256a2a864ea73725b8563121bc462ca178f Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 15 Jul 2025 17:36:45 -0400 Subject: [PATCH 07/20] Update submodule in azure pipeline. --- azure-pipelines.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ab418a1e..5a2f5d59 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,6 +22,11 @@ stages: vmImage: 'ubuntu-22.04' steps: + - script: | + set -exuo pipefail + git submodule update --init + displayName: 'Update submodules' + - script: | set -exuo pipefail # dash-ha build deps From 44f701ed7efa508327be340e2429ffcf64f58ec0 Mon Sep 17 00:00:00 2001 From: dypet Date: Wed, 16 Jul 2025 11:03:54 -0400 Subject: [PATCH 08/20] update submodule in pipeline. --- azure-pipelines.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5a2f5d59..e7d4c21b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,10 +22,9 @@ stages: vmImage: 'ubuntu-22.04' steps: - - script: | - set -exuo pipefail - git submodule update --init - displayName: 'Update submodules' + - checkout: self + clean: true + submodules: true - script: | set -exuo pipefail From 623f11ff44064de65eefc3e80140f67b13e76963 Mon Sep 17 00:00:00 2001 From: dypet Date: Wed, 16 Jul 2025 13:00:51 -0400 Subject: [PATCH 09/20] fix formatting. --- crates/hamgrd/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hamgrd/src/main.rs b/crates/hamgrd/src/main.rs index 2a50b334..fcdc7360 100644 --- a/crates/hamgrd/src/main.rs +++ b/crates/hamgrd/src/main.rs @@ -20,8 +20,8 @@ use actors::spawn_zmq_producer_bridge; use actors::{dpu::DpuActor, ha_scope::HaScopeActor, ha_set::HaSetActor, vdpu::VDpuActor, DbBasedActor}; use anyhow::Result; use db_structs::{BfdSessionTable, DashHaScopeTable, DashHaSetTable, Dpu, VDpu}; -use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig}; use lazy_static::lazy_static; +use sonic_dash_api_proto::{ha_scope_config::HaScopeConfig, ha_set_config::HaSetConfig}; use std::any::Any; lazy_static! { From ea4d3ee3278c77cae7cce32dba79f2b5d762fb6d Mon Sep 17 00:00:00 2001 From: dypet Date: Wed, 16 Jul 2025 16:46:38 -0400 Subject: [PATCH 10/20] Address review comments. --- Cargo.lock | 3 + crates/hamgrd/src/actors/ha_scope.rs | 31 ++++------ crates/hamgrd/src/actors/ha_set.rs | 25 ++++++-- crates/hamgrd/src/actors/test.rs | 5 +- crates/hamgrd/src/db_structs.rs | 24 +------- crates/sonic-dash-api-proto/build.rs | 20 ++----- crates/sonic-dash-api-proto/src/lib.rs | 35 +++++++++++ crates/sonicdb-derive/src/lib.rs | 82 +++++++++++--------------- crates/swss-common/Cargo.toml | 3 + 9 files changed, 114 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e944adab..ac11becc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2149,10 +2149,13 @@ version = "0.1.0" dependencies = [ "bindgen", "getset", + "hex", "lazy_static", "libc", "paste", + "prost", "serde", + "serde_json", "swss-common-testing", "tokio", "tracing-subscriber", diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index c3886bdc..830e78a0 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -3,7 +3,9 @@ use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use crate::{HaSetActor, VDpuActor}; use anyhow::Result; -use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; +use sonic_dash_api_proto::decode_from_field_values; +use sonic_dash_api_proto::desired_ha_state_to_ha_role; +use sonic_dash_api_proto::ha_scope_config::HaScopeConfig; use std::collections::HashMap; use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, @@ -158,15 +160,6 @@ impl HaScopeActor { // Implements internal action functions for HaScopeActor impl HaScopeActor { - fn desired_ha_state_to_ha_role(desired_ha_state: i32) -> String { - match DesiredHaState::try_from(desired_ha_state) { - Ok(DesiredHaState::HaStateActive) => "active".to_string(), - Ok(DesiredHaState::HaStateDead) => "dead".to_string(), - Ok(DesiredHaState::HaStateStandalone) => "standalone".to_string(), - Ok(DesiredHaState::HaStateUnspecified) | Err(_) => "unknown".to_string(), - } - } - fn register_to_vdpu_actor(&self, outgoing: &mut Outgoing, active: bool) -> Result<()> { if self.dash_ha_scope_config.is_none() { return Ok(()); @@ -226,7 +219,7 @@ impl HaScopeActor { let dash_ha_scope = DashHaScopeTable { version: dash_ha_scope_config.version.parse().unwrap(), disable: dash_ha_scope_config.disabled, - ha_role: Self::desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ + ha_role: desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ flow_reconcile_requested, activate_role_requested, }; @@ -385,7 +378,7 @@ impl HaScopeActor { // The target HA state in ASIC. This is the state that hamgrd generates and asking DPU to move to. npu_ha_scope_state.local_target_asic_ha_state = - Some(Self::desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state)); + Some(desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state)); // The HA state that ASIC acked. npu_ha_scope_state.local_acked_asic_ha_state = Some(dpu_ha_scope_state.ha_role.clone()); @@ -425,7 +418,7 @@ impl HaScopeActor { return Ok(()); } let first_time = self.dash_ha_scope_config.is_none(); - let dash_ha_scope_config: HaScopeConfig = decode_from_json_string(&kfv.field_values)?; + let dash_ha_scope_config: HaScopeConfig = decode_from_field_values(&kfv.field_values)?; // Update internal config self.dash_ha_scope_config = Some(dash_ha_scope_config); @@ -600,7 +593,7 @@ mod test { db_structs::{now_in_millis, DashHaScopeTable, DpuDashHaScopeState, NpuDashHaScopeState}, ha_actor_messages::*, }; - use sonic_dash_api_proto::ha_scope_config::HaScopeConfig; + use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; use std::time::Duration; use swss_common::{SonicDbTable, Table}; use swss_common_testing::*; @@ -652,7 +645,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state disabled send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": "{\"version\":\"1\",\"disabled\":true,\"desired_ha_state\":2,\"approved_pending_operation_ids\":[]}"}, + "field_values": {"json": format!("{{\"version\":\"1\",\"disabled\":true,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateActive as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -685,7 +678,7 @@ mod test { // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state enabled send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": "{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":2,\"approved_pending_operation_ids\":[]}"}, + "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateActive as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -742,7 +735,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with activation approved send! { key: HaScopeActor::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": format!("{{\"version\":\"3\",\"disabled\":false,\"desired_ha_state\":2,\"approved_pending_operation_ids\":{}}}", &op_id)}, + "field_values": {"json": format!("{{\"version\":\"3\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":{}}}", DesiredHaState::HaStateActive as i32, &op_id)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -786,7 +779,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with desired_ha_state = dead send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": "{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":1,\"approved_pending_operation_ids\":[]}"}, + "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateDead as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -797,7 +790,7 @@ mod test { // simulate delete of ha-scope entry send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Del", - "field_values": {"json": "{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":1,\"approved_pending_operation_ids\":[]}"}, + "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateDead as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index cda0e984..0fab8e5f 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -3,7 +3,9 @@ use crate::actors::{spawn_consumer_bridge_for_actor, DbBasedActor}; use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use anyhow::Result; +use sonic_dash_api_proto::decode_from_field_values; use sonic_dash_api_proto::ha_set_config::HaSetConfig; +use sonic_dash_api_proto::ip_to_string; use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, Actor, ActorMessage, Context, State, @@ -80,8 +82,18 @@ impl HaSetActor { version: dash_ha_set_config.version.clone(), vip_v4: dash_ha_set_config.vip_v4.as_ref().map(ip_to_string).unwrap_or_default(), vip_v6: dash_ha_set_config.vip_v6.as_ref().map(ip_to_string), - owner: format!("{:?}", dash_ha_set_config.owner).into(), - scope: format!("{:?}", dash_ha_set_config.scope).into(), + owner: sonic_dash_api_proto::types::HaOwner::try_from(dash_ha_set_config.owner) + .map(|s| { + let name = s.as_str_name(); + name.strip_prefix("OWNER_").unwrap_or(name).to_lowercase() + }) + .ok(), + scope: sonic_dash_api_proto::types::HaScope::try_from(dash_ha_set_config.scope) + .map(|s| { + let name = s.as_str_name(); + name.strip_prefix("SCOPE_").unwrap_or(name).to_lowercase() + }) + .ok(), local_npu_ip: local_vdpu.dpu.npu_ipv4.clone(), local_ip: local_vdpu.dpu.pa_ipv4.clone(), peer_ip: remote_vdpu.dpu.pa_ipv4.clone(), @@ -264,7 +276,7 @@ impl HaSetActor { } let first_time = self.dash_ha_set_config.is_none(); - self.dash_ha_set_config = Some(decode_from_json_string(&dpu_kfv.field_values).unwrap()); + self.dash_ha_set_config = Some(decode_from_field_values(&dpu_kfv.field_values).unwrap()); let vip_v4_str = self.dash_ha_set_config.as_ref().unwrap().vip_v4.as_ref().map(|ip| { if let Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) = &ip.ip { @@ -386,6 +398,7 @@ mod test { ha_actor_messages::*, }; use sonic_dash_api_proto::ha_set_config::HaSetConfig; + use sonic_dash_api_proto::ip_to_string; use std::collections::HashMap; use std::time::Duration; use swss_common::CxxString; @@ -393,7 +406,7 @@ mod test { use swss_common::SonicDbTable; use swss_common_testing::*; - fn protobuf_struct_to_json(cfg: &T) -> HashMap { + fn protobuf_struct_to_kfv(cfg: &T) -> HashMap { let json = serde_json::to_string(&cfg).unwrap(); let mut kfv = KeyOpFieldValues { key: HaSetActor::table_name().to_string(), @@ -418,7 +431,7 @@ mod test { let global_cfg_fvs = serde_json::to_value(swss_serde::to_field_values(&global_cfg).unwrap()).unwrap(); let (ha_set_id, ha_set_cfg) = make_dpu_scope_ha_set_config(0, 0); - let ha_set_cfg_fvs = protobuf_struct_to_json(&ha_set_cfg); + let ha_set_cfg_fvs = protobuf_struct_to_kfv(&ha_set_cfg); let dpu0 = make_local_dpu_actor_state(0, 0, true, None, None); let dpu1 = make_remote_dpu_actor_state(1, 0); let (vdpu0_id, vdpu0_state_obj) = make_vdpu_actor_state(true, &dpu0); @@ -503,7 +516,7 @@ mod test { let global_cfg_fvs = serde_json::to_value(swss_serde::to_field_values(&global_cfg).unwrap()).unwrap(); let (ha_set_id, ha_set_cfg) = make_dpu_scope_ha_set_config(2, 0); - let ha_set_cfg_fvs = protobuf_struct_to_json(&ha_set_cfg); + let ha_set_cfg_fvs = protobuf_struct_to_kfv(&ha_set_cfg); let dpu0 = make_remote_dpu_actor_state(2, 0); let dpu1 = make_remote_dpu_actor_state(3, 0); let (vdpu0_id, vdpu0_state_obj) = make_vdpu_actor_state(true, &dpu0); diff --git a/crates/hamgrd/src/actors/test.rs b/crates/hamgrd/src/actors/test.rs index b6193514..7ecd17c6 100644 --- a/crates/hamgrd/src/actors/test.rs +++ b/crates/hamgrd/src/actors/test.rs @@ -3,6 +3,7 @@ use crate::ha_actor_messages::*; use crate::RuntimeData; use anyhow::Result; use serde_json::Value; +use sonic_dash_api_proto::ip_to_string; use sonic_dash_api_proto::{ha_set_config::HaSetConfig, types::ip_address::Ip, types::*}; use std::{collections::HashMap, future::Future, time::Duration}; use std::{net::Ipv4Addr, net::Ipv6Addr, sync::Arc}; @@ -451,8 +452,8 @@ pub fn make_dpu_scope_ha_set_obj(switch: u16, dpu: u16) -> (String, DashHaSetTab version: "1".to_string(), vip_v4: ip_to_string(&haset_cfg.vip_v4.unwrap()), vip_v6: Some(ip_to_string(&haset_cfg.vip_v6.unwrap())), - owner: format!("{:?}", haset_cfg.owner).into(), - scope: format!("{:?}", haset_cfg.scope).into(), + owner: Some("controller".to_string()), + scope: Some("dpu".to_string()), local_npu_ip: format!("10.0.{switch}.{dpu}"), local_ip: format!("18.0.{switch}.{dpu}"), peer_ip: format!("18.0.{}.{dpu}", switch_pair_id * 2 + 1), diff --git a/crates/hamgrd/src/db_structs.rs b/crates/hamgrd/src/db_structs.rs index 30e6c8c3..46add9a2 100644 --- a/crates/hamgrd/src/db_structs.rs +++ b/crates/hamgrd/src/db_structs.rs @@ -2,10 +2,8 @@ use anyhow::{Context, Result}; use chrono::DateTime; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde_with::{formats::CommaSeparator, serde_as, skip_serializing_none, StringWithSeparator}; -use sonic_dash_api_proto::types::*; use sonicdb_derive::SonicDb; -use std::collections::HashMap; -use swss_common::{CxxString, DbConnector, Table}; +use swss_common::{DbConnector, Table}; use swss_serde::from_table; /// Format: "Tue Jun 04 09:00:00 PM UTC 2024" @@ -424,26 +422,6 @@ pub fn get_dpu_config_from_db(dpu_id: u32) -> Result { Err(anyhow::anyhow!("DPU entry not found for slot {}", dpu_id)) } -pub fn ip_to_string(ip: &IpAddress) -> String { - match &ip.ip { - Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv4(addr)) => std::net::Ipv4Addr::from(*addr).to_string(), - Some(sonic_dash_api_proto::types::ip_address::Ip::Ipv6(addr)) => { - use std::net::Ipv6Addr; - let bytes: [u8; 16] = addr.clone().try_into().unwrap_or([0; 16]); - Ipv6Addr::from(bytes).to_string() - } - _ => "".to_string(), - } -} - -pub fn decode_from_json_string serde::Deserialize<'de>>( - field_values: &HashMap, -) -> Result { - let json_str = field_values.get("json").unwrap(); - let s = json_str.to_string_lossy().into_owned(); - serde_json::from_str(&s) -} - #[cfg(test)] mod test { use super::*; diff --git a/crates/sonic-dash-api-proto/build.rs b/crates/sonic-dash-api-proto/build.rs index 97e13879..4074201d 100644 --- a/crates/sonic-dash-api-proto/build.rs +++ b/crates/sonic-dash-api-proto/build.rs @@ -3,15 +3,9 @@ fn main() { let mut proto_config = prost_build::Config::new(); - proto_config.type_attribute( - "dash.ha_scope_config.HaScopeConfig", - "#[allow(unused_imports)] use sonicdb_derive::SonicDb;", - ); + proto_config.type_attribute("dash.ha_scope_config.HaScopeConfig", "use sonicdb_derive::SonicDb;"); - proto_config.type_attribute( - "dash.ha_scope_config.HaScopeConfig", - "#[allow(unused_imports)] use swss_common::{DbConnector, Table, KeyOpFieldValues}; use prost::Message;", - ); + proto_config.type_attribute("dash.ha_scope_config.HaScopeConfig", "use prost::Message;"); proto_config.type_attribute("dash.ha_scope_config.HaScopeConfig", "#[derive(SonicDb)]"); @@ -25,15 +19,9 @@ fn main() { "#[derive(serde::Serialize, serde::Deserialize)]", ); - proto_config.type_attribute( - "dash.ha_set_config.HaSetConfig", - "#[allow(unused_imports)] use sonicdb_derive::SonicDb;", - ); + proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "use sonicdb_derive::SonicDb;"); - proto_config.type_attribute( - "dash.ha_set_config.HaSetConfig", - "#[allow(unused_imports)] use swss_common::{DbConnector, Table, KeyOpFieldValues}; use prost::Message;", - ); + proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "use prost::Message;"); proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "#[derive(SonicDb)]"); diff --git a/crates/sonic-dash-api-proto/src/lib.rs b/crates/sonic-dash-api-proto/src/lib.rs index db741a5c..c21fb375 100644 --- a/crates/sonic-dash-api-proto/src/lib.rs +++ b/crates/sonic-dash-api-proto/src/lib.rs @@ -1,3 +1,9 @@ +use crate::ha_scope_config::DesiredHaState; +use crate::types::ip_address::Ip; +use crate::types::IpAddress; +use std::collections::HashMap; +use swss_common::CxxString; + pub mod ha_scope_config { include!(concat!(env!("OUT_DIR"), "/dash.ha_scope_config.rs")); } @@ -9,3 +15,32 @@ pub mod ha_set_config { pub mod types { include!(concat!(env!("OUT_DIR"), "/dash.types.rs")); } + +pub fn desired_ha_state_to_ha_role(desired_ha_state: i32) -> String { + match DesiredHaState::try_from(desired_ha_state) { + Ok(DesiredHaState::HaStateActive) => "active".to_string(), + Ok(DesiredHaState::HaStateDead) => "dead".to_string(), + Ok(DesiredHaState::HaStateStandalone) => "standalone".to_string(), + Ok(DesiredHaState::HaStateUnspecified) | Err(_) => "unknown".to_string(), + } +} + +pub fn ip_to_string(ip: &IpAddress) -> String { + match &ip.ip { + Some(Ip::Ipv4(addr)) => std::net::Ipv4Addr::from(*addr).to_string(), + Some(Ip::Ipv6(addr)) => { + use std::net::Ipv6Addr; + let bytes: [u8; 16] = addr.clone().try_into().unwrap_or([0; 16]); + Ipv6Addr::from(bytes).to_string() + } + _ => "".to_string(), + } +} + +pub fn decode_from_field_values serde::Deserialize<'de>>( + field_values: &HashMap, +) -> Result { + let json_str = field_values.get("json").unwrap(); + let s = json_str.to_string_lossy().into_owned(); + serde_json::from_str(&s) +} diff --git a/crates/sonicdb-derive/src/lib.rs b/crates/sonicdb-derive/src/lib.rs index cbfaf391..e1fe9785 100644 --- a/crates/sonicdb-derive/src/lib.rs +++ b/crates/sonicdb-derive/src/lib.rs @@ -76,51 +76,12 @@ pub fn serde_sonicdb_derive(input: TokenStream) -> TokenStream { panic!("Missing key_separator attribute"); } - let is_dpu_value = is_dpu; - - let expanded = quote! { - impl swss_common::SonicDbTable for #struct_name { - fn key_separator() -> char { - #key_separator - } - - fn table_name() -> &'static str { - #table_name - } - - fn db_name() -> &'static str { - #db_name - } - - fn is_dpu() -> bool { - #is_dpu_value - } - } - }; - - let expanded_proto = quote! { - impl swss_common::SonicDbTable for #struct_name { - fn key_separator() -> char { - #key_separator - } - - fn table_name() -> &'static str { - #table_name - } - - fn db_name() -> &'static str { - #db_name - } - - fn is_dpu() -> bool { - #is_dpu_value - } - + let convert_pb_to_json_impl = if protobuf_encoded { + quote! { fn is_proto() -> bool { true } - - fn convert_pb_to_json(kfv: &mut KeyOpFieldValues) { + fn convert_pb_to_json(kfv: &mut swss_common::KeyOpFieldValues) { let value_hex = match kfv.field_values.get("pb") { Some(v) => v.to_str().ok(), None => None, @@ -146,12 +107,37 @@ pub fn serde_sonicdb_derive(input: TokenStream) -> TokenStream { kfv.field_values.insert("json".to_string(), json.into()); } } + } else { + quote! { + fn is_proto() -> bool { + false + } + } }; - if protobuf_encoded { - // If the struct is protobuf encoded, include the proto implementation - TokenStream::from(expanded_proto) - } else { - TokenStream::from(expanded) - } + let is_dpu_value = is_dpu; + + let expanded = quote! { + impl swss_common::SonicDbTable for #struct_name { + fn key_separator() -> char { + #key_separator + } + + fn table_name() -> &'static str { + #table_name + } + + fn db_name() -> &'static str { + #db_name + } + + fn is_dpu() -> bool { + #is_dpu_value + } + + #convert_pb_to_json_impl + } + }; + + TokenStream::from(expanded) } diff --git a/crates/swss-common/Cargo.toml b/crates/swss-common/Cargo.toml index bfe17f2c..679d3cb4 100644 --- a/crates/swss-common/Cargo.toml +++ b/crates/swss-common/Cargo.toml @@ -21,6 +21,9 @@ serde.workspace = true getset.workspace = true lazy_static.workspace = true tracing-subscriber.workspace = true +serde_json.workspace = true +hex = "0.4" +prost.workspace = true [build-dependencies] bindgen = "0.70.1" From f57feeb9bba18644d51f798a171f5c09df8e8a06 Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 17 Jul 2025 10:34:43 -0400 Subject: [PATCH 11/20] revert actors.rs change. --- crates/hamgrd/src/actors.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/crates/hamgrd/src/actors.rs b/crates/hamgrd/src/actors.rs index 88609bda..dc4e815c 100644 --- a/crates/hamgrd/src/actors.rs +++ b/crates/hamgrd/src/actors.rs @@ -144,29 +144,22 @@ where if let Some(Body::DataRequest(DataRequest { payload })) = &msg.body { match ActorMessage::deserialize(payload) { Ok(actor_msg) => { - let key: String = serde_json::from_value(actor_msg.data["key"].clone()).map_err(|_| { + let kfv: KeyOpFieldValues = actor_msg.deserialize_data().map_err(|_| { SwbusError::input( SwbusErrorCode::InvalidPayload, - "cannot decode ActorMessage key".to_string(), + "cannot decode as ActorMessage".to_string(), ) })?; - let operation: KeyOperation = - serde_json::from_value(actor_msg.data["operation"].clone()).map_err(|_| { - SwbusError::input( - SwbusErrorCode::InvalidPayload, - "cannot decode ActorMessage operation".to_string(), - ) - })?; - if operation == KeyOperation::Del { + if kfv.operation == KeyOperation::Del { return Err(SwbusError::input( SwbusErrorCode::NoRoute, "actor doesn't exist: won't create actor for DEL kfv".to_string(), )); } - let actor = (self.create_fn)(key.clone()).map_err(|e| { + let actor = (self.create_fn)(kfv.key.clone()).map_err(|e| { let mut sp = self.sp.clone(); - sp.resource_id = key.clone(); + sp.resource_id = kfv.key.clone(); SwbusError::input( SwbusErrorCode::Fail, format!("Failed to create actor {}. Error: {}", sp.to_swbusd_service_path(), e), From e973669f14726b5f90f0c68be4cd8035e4c0343b Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 17 Jul 2025 12:12:09 -0400 Subject: [PATCH 12/20] Add consumer protobuf UT. --- crates/swss-common-bridge/src/consumer.rs | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/crates/swss-common-bridge/src/consumer.rs b/crates/swss-common-bridge/src/consumer.rs index 2e11055e..ba3e6a46 100644 --- a/crates/swss-common-bridge/src/consumer.rs +++ b/crates/swss-common-bridge/src/consumer.rs @@ -205,7 +205,9 @@ impl_consumertable! { ConsumerStateTable[true] SubscriberStateTable[true] ZmqCon mod test { use super::{spawn_consumer_bridge, ConsumerTable}; use crate::producer::ProducerTable; + use sonic_dash_api_proto::ha_set_config::HaSetConfig; use sonicdb_derive::SonicDb; + use std::collections::HashMap; use std::{sync::Arc, time::Duration}; use swbus_actor::ActorMessage; use swbus_edge::{ @@ -238,6 +240,14 @@ mod test { .unwrap(); } + #[tokio::test] + async fn consumer_state_proto_table_bridge() { + let redis = Redis::start(); + let pst = ProducerStateTable::new(redis.db_connector(), "mytable").unwrap(); + let cst = ConsumerStateTable::new(redis.db_connector(), "mytable", None, None).unwrap(); + timeout(Duration::from_secs(5), run_proto_test(cst, pst)).await.unwrap(); + } + #[tokio::test] async fn zmq_consumer_state_table_bridge() { let (zmq_endpoint, _deleter) = random_zmq_endpoint(); @@ -330,4 +340,58 @@ mod test { fn sp(s: &str) -> ServicePath { ServicePath::from_string(&format!("test.test.test/test/test/test/{s}")).unwrap() } + + async fn run_proto_test(consumer_table: C, mut producer_table: P) { + // Setup swbus + let mut swbus_edge = SwbusEdgeRuntime::new("".to_string(), sp("edge")); + swbus_edge.start().await.unwrap(); + let rt = Arc::new(swbus_edge); + + // Create edge client to receive updates from the bridge + let swbus = SimpleSwbusEdgeClient::new(rt.clone(), sp("receiver"), true, false); + + // Spawn the bridge + let bridge = spawn_consumer_bridge::( + rt.clone(), + sp("mytable-bridge"), + consumer_table, + |_| (sp("receiver"), "".into()), + |_| true, + ); + + // Send some updates we should receive + let kfvs = KeyOpFieldValues { + key: "haset0_0".to_string(), + operation: swss_common::KeyOperation::Set, + field_values: { + let mut map = HashMap::new(); + map.insert( + "pb".to_string(), + "0a013112050d0001020320012801320576647075303205766470753142057664707530" + .to_string() + .into(), + ); + map + }, + }; + + producer_table.apply_kfv(kfvs.clone()).await; + + let kfvs_expected = KeyOpFieldValues { + key: "haset0_0".to_string(), + operation: swss_common::KeyOperation::Set, + field_values: { + let mut map = HashMap::new(); + map.insert("json".to_string(), "{\"version\":\"1\",\"vip_v4\":{\"ip\":{\"Ipv4\":50462976}},\"vip_v6\":null,\"owner\":1,\"scope\":1,\"vdpu_ids\":[\"vdpu0\",\"vdpu1\"],\"pinned_vdpu_bfd_probe_states\":[],\"preferred_vdpu_id\":\"vdpu0\",\"preferred_standalone_vdpu_index\":0}".to_string().into()); + map + }, + }; + + // Receive the updates + let kfvs_received = receive_n_messages(1, &swbus).await; + + // Assert we received the decoded protobuf + assert_eq!(kfvs_expected, kfvs_received[0]); + bridge.abort(); + } } From 631ee0c622b085a7f0226aa881f4e80fe33ad522 Mon Sep 17 00:00:00 2001 From: dypet Date: Mon, 21 Jul 2025 17:50:47 -0400 Subject: [PATCH 13/20] update sonic-dash-api-proto swss-common. --- crates/sonic-dash-api-proto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/sonic-dash-api-proto/Cargo.toml b/crates/sonic-dash-api-proto/Cargo.toml index 178c78f4..9080faee 100644 --- a/crates/sonic-dash-api-proto/Cargo.toml +++ b/crates/sonic-dash-api-proto/Cargo.toml @@ -12,7 +12,7 @@ edition.workspace = true prost.workspace = true serde.workspace = true sonicdb-derive.workspace = true -swss-common = { path = "../swss-common" } +swss-common = { git = "https://github.com/sonic-net/sonic-swss-common.git", branch = "master" } sonic-common.workspace = true hex = "0.4" serde_json.workspace = true From 7a40bd2026c51d752f0c933b1b40c6c8ee690a7b Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 22 Jul 2025 14:00:06 -0400 Subject: [PATCH 14/20] Update for new protobuf changes. --- crates/hamgrd/src/actors/ha_scope.rs | 30 ++++++++++++++--------- crates/hamgrd/src/actors/ha_set.rs | 6 ----- crates/hamgrd/src/actors/test.rs | 7 ++---- crates/hamgrd/src/db_structs.rs | 2 -- crates/sonic-dash-api-proto/build.rs | 5 ++++ crates/sonic-dash-api-proto/src/lib.rs | 10 -------- crates/swss-common-bridge/src/consumer.rs | 4 +-- test_utils/hamgrd/redis_data_set.cmd | 4 +-- 8 files changed, 30 insertions(+), 38 deletions(-) diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index 830e78a0..246b39f0 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -4,8 +4,7 @@ use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationT use crate::{HaSetActor, VDpuActor}; use anyhow::Result; use sonic_dash_api_proto::decode_from_field_values; -use sonic_dash_api_proto::desired_ha_state_to_ha_role; -use sonic_dash_api_proto::ha_scope_config::HaScopeConfig; +use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; use std::collections::HashMap; use swbus_actor::{ state::{incoming::Incoming, internal::Internal, outgoing::Outgoing}, @@ -219,8 +218,11 @@ impl HaScopeActor { let dash_ha_scope = DashHaScopeTable { version: dash_ha_scope_config.version.parse().unwrap(), disable: dash_ha_scope_config.disabled, - ha_role: desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ - flow_reconcile_requested, + ha_role: format!( + "{}", + DesiredHaState::try_from(dash_ha_scope_config.desired_ha_state).unwrap() + ) + .to_lowercase(), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ flow_reconcile_requested, activate_role_requested, }; @@ -377,8 +379,13 @@ impl HaScopeActor { npu_ha_scope_state.local_ha_state_last_updated_reason = Some("dpu initiated".to_string()); // The target HA state in ASIC. This is the state that hamgrd generates and asking DPU to move to. - npu_ha_scope_state.local_target_asic_ha_state = - Some(desired_ha_state_to_ha_role(dash_ha_scope_config.desired_ha_state)); + npu_ha_scope_state.local_target_asic_ha_state = Some( + format!( + "{}", + DesiredHaState::try_from(dash_ha_scope_config.desired_ha_state).unwrap() + ) + .to_lowercase(), + ); // The HA state that ASIC acked. npu_ha_scope_state.local_acked_asic_ha_state = Some(dpu_ha_scope_state.ha_role.clone()); @@ -594,6 +601,7 @@ mod test { ha_actor_messages::*, }; use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; + use sonic_dash_api_proto::types::HaOwner; use std::time::Duration; use swss_common::{SonicDbTable, Table}; use swss_common_testing::*; @@ -645,7 +653,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state disabled send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": format!("{{\"version\":\"1\",\"disabled\":true,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateActive as i32)}, + "field_values": {"json": format!("{{\"version\":\"1\",\"disabled\":true,\"desired_ha_state\":{},\"owner\":{},\"ha_set_id\":\"test_id\",\"approved_pending_operation_ids\":[]}}", DesiredHaState::Active as i32, HaOwner::Dpu as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -678,7 +686,7 @@ mod test { // Send DASH_HA_SCOPE_CONFIG_TABLE to actor with admin state enabled send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateActive as i32)}, + "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"owner\":{},\"ha_set_id\":\"test_id\",\"approved_pending_operation_ids\":[]}}", DesiredHaState::Active as i32, HaOwner::Dpu as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -735,7 +743,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with activation approved send! { key: HaScopeActor::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": format!("{{\"version\":\"3\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":{}}}", DesiredHaState::HaStateActive as i32, &op_id)}, + "field_values": {"json": format!("{{\"version\":\"3\",\"disabled\":false,\"desired_ha_state\":{},\"owner\":{},\"ha_set_id\":\"test_id\",\"approved_pending_operation_ids\":{}}}", DesiredHaState::Active as i32, HaOwner::Dpu as i32, &op_id)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -779,7 +787,7 @@ mod test { let commands = [ // Send DASH_HA_SCOPE_CONFIG_TABLE with desired_ha_state = dead send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Set", - "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateDead as i32)}, + "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"owner\":{},\"ha_set_id\":\"test_id\",\"approved_pending_operation_ids\":[]}}", DesiredHaState::Dead as i32, HaOwner::Dpu as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, @@ -790,7 +798,7 @@ mod test { // simulate delete of ha-scope entry send! { key: HaScopeConfig::table_name(), data: { "key": &scope_id, "operation": "Del", - "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"approved_pending_operation_ids\":[]}}", DesiredHaState::HaStateDead as i32)}, + "field_values": {"json": format!("{{\"version\":\"2\",\"disabled\":false,\"desired_ha_state\":{},\"owner\":{},\"ha_set_id\":\"test_id\",\"approved_pending_operation_ids\":[]}}", DesiredHaState::Dead as i32, HaOwner::Dpu as i32)}, }, addr: crate::common_bridge_sp::(&runtime.get_swbus_edge()) }, ]; diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index 0fab8e5f..858e98c0 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -82,12 +82,6 @@ impl HaSetActor { version: dash_ha_set_config.version.clone(), vip_v4: dash_ha_set_config.vip_v4.as_ref().map(ip_to_string).unwrap_or_default(), vip_v6: dash_ha_set_config.vip_v6.as_ref().map(ip_to_string), - owner: sonic_dash_api_proto::types::HaOwner::try_from(dash_ha_set_config.owner) - .map(|s| { - let name = s.as_str_name(); - name.strip_prefix("OWNER_").unwrap_or(name).to_lowercase() - }) - .ok(), scope: sonic_dash_api_proto::types::HaScope::try_from(dash_ha_set_config.scope) .map(|s| { let name = s.as_str_name(); diff --git a/crates/hamgrd/src/actors/test.rs b/crates/hamgrd/src/actors/test.rs index 7ecd17c6..909774ba 100644 --- a/crates/hamgrd/src/actors/test.rs +++ b/crates/hamgrd/src/actors/test.rs @@ -432,10 +432,8 @@ pub fn make_dpu_scope_ha_set_config(switch: u16, dpu: u16) -> (String, HaSetConf version: "1".to_string(), vip_v4: string_to_ip(format!("3.2.{switch_pair_id}.{dpu}")), vip_v6: string_to_ip(normalize_ipv6(&format!("3:2:{switch_pair_id}::{dpu}"))), - // dpu or switch - owner: HaOwner::OwnerController as i32, // dpu or eni - scope: HaScope::ScopeDpu as i32, + scope: HaScope::Dpu as i32, vdpu_ids: vec![vdpu0_id.clone(), vdpu1_id.clone()], pinned_vdpu_bfd_probe_states: vec!["".to_string()], preferred_vdpu_id: vdpu0_id, @@ -452,8 +450,7 @@ pub fn make_dpu_scope_ha_set_obj(switch: u16, dpu: u16) -> (String, DashHaSetTab version: "1".to_string(), vip_v4: ip_to_string(&haset_cfg.vip_v4.unwrap()), vip_v6: Some(ip_to_string(&haset_cfg.vip_v6.unwrap())), - owner: Some("controller".to_string()), - scope: Some("dpu".to_string()), + scope: Some("ha_scope_dpu".to_string()), local_npu_ip: format!("10.0.{switch}.{dpu}"), local_ip: format!("18.0.{switch}.{dpu}"), peer_ip: format!("18.0.{}.{dpu}", switch_pair_id * 2 + 1), diff --git a/crates/hamgrd/src/db_structs.rs b/crates/hamgrd/src/db_structs.rs index 46add9a2..83654ca3 100644 --- a/crates/hamgrd/src/db_structs.rs +++ b/crates/hamgrd/src/db_structs.rs @@ -227,8 +227,6 @@ pub struct DashHaSetTable { pub vip_v4: String, // IPv4 Data path VIP. pub vip_v6: Option, - // Owner of HA state machine. It can be controller, switch. - pub owner: Option, // Scope of HA set. It can be dpu, eni. pub scope: Option, // The IP address of local NPU. It can be IPv4 or IPv6. Used for setting up the BFD session. diff --git a/crates/sonic-dash-api-proto/build.rs b/crates/sonic-dash-api-proto/build.rs index 4074201d..f43ae693 100644 --- a/crates/sonic-dash-api-proto/build.rs +++ b/crates/sonic-dash-api-proto/build.rs @@ -19,6 +19,11 @@ fn main() { "#[derive(serde::Serialize, serde::Deserialize)]", ); + proto_config.type_attribute( + "dash.ha_scope_config.DesiredHaState", + "#[derive(strum_macros::Display)]", + ); + proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "use sonicdb_derive::SonicDb;"); proto_config.type_attribute("dash.ha_set_config.HaSetConfig", "use prost::Message;"); diff --git a/crates/sonic-dash-api-proto/src/lib.rs b/crates/sonic-dash-api-proto/src/lib.rs index c21fb375..3d57dd43 100644 --- a/crates/sonic-dash-api-proto/src/lib.rs +++ b/crates/sonic-dash-api-proto/src/lib.rs @@ -1,4 +1,3 @@ -use crate::ha_scope_config::DesiredHaState; use crate::types::ip_address::Ip; use crate::types::IpAddress; use std::collections::HashMap; @@ -16,15 +15,6 @@ pub mod types { include!(concat!(env!("OUT_DIR"), "/dash.types.rs")); } -pub fn desired_ha_state_to_ha_role(desired_ha_state: i32) -> String { - match DesiredHaState::try_from(desired_ha_state) { - Ok(DesiredHaState::HaStateActive) => "active".to_string(), - Ok(DesiredHaState::HaStateDead) => "dead".to_string(), - Ok(DesiredHaState::HaStateStandalone) => "standalone".to_string(), - Ok(DesiredHaState::HaStateUnspecified) | Err(_) => "unknown".to_string(), - } -} - pub fn ip_to_string(ip: &IpAddress) -> String { match &ip.ip { Some(Ip::Ipv4(addr)) => std::net::Ipv4Addr::from(*addr).to_string(), diff --git a/crates/swss-common-bridge/src/consumer.rs b/crates/swss-common-bridge/src/consumer.rs index ba3e6a46..2d65012f 100644 --- a/crates/swss-common-bridge/src/consumer.rs +++ b/crates/swss-common-bridge/src/consumer.rs @@ -367,7 +367,7 @@ mod test { let mut map = HashMap::new(); map.insert( "pb".to_string(), - "0a013112050d0001020320012801320576647075303205766470753142057664707530" + "0a013112050d00010203220576647075302205766470753128013a057664707530" .to_string() .into(), ); @@ -382,7 +382,7 @@ mod test { operation: swss_common::KeyOperation::Set, field_values: { let mut map = HashMap::new(); - map.insert("json".to_string(), "{\"version\":\"1\",\"vip_v4\":{\"ip\":{\"Ipv4\":50462976}},\"vip_v6\":null,\"owner\":1,\"scope\":1,\"vdpu_ids\":[\"vdpu0\",\"vdpu1\"],\"pinned_vdpu_bfd_probe_states\":[],\"preferred_vdpu_id\":\"vdpu0\",\"preferred_standalone_vdpu_index\":0}".to_string().into()); + map.insert("json".to_string(), "{\"version\":\"1\",\"vip_v4\":{\"ip\":{\"Ipv4\":50462976}},\"vip_v6\":null,\"vdpu_ids\":[\"vdpu0\",\"vdpu1\"],\"scope\":1,\"pinned_vdpu_bfd_probe_states\":[],\"preferred_vdpu_id\":\"vdpu0\",\"preferred_standalone_vdpu_index\":0}".to_string().into()); map }, }; diff --git a/test_utils/hamgrd/redis_data_set.cmd b/test_utils/hamgrd/redis_data_set.cmd index fe9407d9..f05f8fd2 100644 --- a/test_utils/hamgrd/redis_data_set.cmd +++ b/test_utils/hamgrd/redis_data_set.cmd @@ -68,5 +68,5 @@ HSET DPU_STATE|dpu7 dpu_control_plane_state up HSET DPU_STATE|dpu7 dpu_data_plane_state up select 0 -HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 pb "0a013112050d0001020320012801320576647075303205766470753142057664707530" -HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 pb "0a013110011802" +HSET DASH_HA_SET_CONFIG_TABLE:haset0_0 pb "0a013112050d00010203220576647075302205766470753128013a057664707530" +HSET DASH_HA_SCOPE_CONFIG_TABLE:vdpu0:haset0_0 pb "0a01311001180122067465737469642802" From a5a5845d0f0c023974eccf1fe1483b99c1f0e89c Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 22 Jul 2025 14:24:06 -0400 Subject: [PATCH 15/20] Add strum. --- crates/sonic-dash-api-proto/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/sonic-dash-api-proto/Cargo.toml b/crates/sonic-dash-api-proto/Cargo.toml index 9080faee..5beb849f 100644 --- a/crates/sonic-dash-api-proto/Cargo.toml +++ b/crates/sonic-dash-api-proto/Cargo.toml @@ -16,6 +16,8 @@ swss-common = { git = "https://github.com/sonic-net/sonic-swss-common.git", bran sonic-common.workspace = true hex = "0.4" serde_json.workspace = true +strum = "0.26" +strum_macros = "0.26" [build-dependencies] prost-build = "0.13" From e5ca8acc763ceea1592da6e96591d3406867f8a3 Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 22 Jul 2025 14:28:38 -0400 Subject: [PATCH 16/20] Update sonic-dash-api to latest. --- crates/sonic-dash-api-proto/sonic-dash-api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/sonic-dash-api-proto/sonic-dash-api b/crates/sonic-dash-api-proto/sonic-dash-api index 2ed8ff6f..54ab2b98 160000 --- a/crates/sonic-dash-api-proto/sonic-dash-api +++ b/crates/sonic-dash-api-proto/sonic-dash-api @@ -1 +1 @@ -Subproject commit 2ed8ff6fe4cd89a1814953fba47a0d769ec867f1 +Subproject commit 54ab2b9895166fc928bf5d88180935eeac7a3dce From ae5447857cf34b804e8dd8876413e9e1761d4363 Mon Sep 17 00:00:00 2001 From: dypet Date: Tue, 22 Jul 2025 15:04:20 -0400 Subject: [PATCH 17/20] Move dependencies to workspace. --- Cargo.toml | 4 ++++ crates/hamgrd/Cargo.toml | 4 ++-- crates/hamgrd/src/actors/ha_scope.rs | 3 ++- crates/sonic-dash-api-proto/Cargo.toml | 10 +++++----- crates/swss-common-bridge/Cargo.toml | 4 ++-- crates/swss-common/Cargo.toml | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 41e8278e..d3cfb05b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,9 +69,12 @@ contracts = "0.6" derivative = "2" derive_builder = "0.20" getset = "0.1" +hex = "0.4" lazy_static = "1.4" owning_ref = "0.4" +prost-build = "0.13" strum = { version = "0.26", features = ["derive"] } +strum_macros = "0.26" regex = "1" dashmap = "6" itertools = "0.13" @@ -94,6 +97,7 @@ swss-serde = { version = "0.1.0", path = "crates/swss-serde" } swbus-actor = { version = "0.1.0", path = "crates/swbus-actor" } sonicdb-derive = { version = "0.1.0", path = "crates/sonicdb-derive" } sonic-dash-api-proto = { version = "0.1.0", path = "crates/sonic-dash-api-proto" } +swss-common = { git = "https://github.com/sonic-net/sonic-swss-common.git", branch = "master" } # Dev dependencies criterion = "0.5" diff --git a/crates/hamgrd/Cargo.toml b/crates/hamgrd/Cargo.toml index afca2855..9f13be4b 100644 --- a/crates/hamgrd/Cargo.toml +++ b/crates/hamgrd/Cargo.toml @@ -30,8 +30,8 @@ clap.workspace = true tracing.workspace = true chrono.workspace = true uuid.workspace = true -sonic-dash-api-proto = { path = "../sonic-dash-api-proto" } +sonic-dash-api-proto.workspace = true prost.workspace = true -hex = "0.4" +hex.workspace = true lazy_static.workspace = true serde_json.workspace = true diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index 246b39f0..b3a71b90 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -222,7 +222,8 @@ impl HaScopeActor { "{}", DesiredHaState::try_from(dash_ha_scope_config.desired_ha_state).unwrap() ) - .to_lowercase(), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ flow_reconcile_requested, + .to_lowercase(), /*todo, how switching_to_active is derived. Is it relevant to dpu driven mode */ + flow_reconcile_requested, activate_role_requested, }; diff --git a/crates/sonic-dash-api-proto/Cargo.toml b/crates/sonic-dash-api-proto/Cargo.toml index 5beb849f..2dc0b81e 100644 --- a/crates/sonic-dash-api-proto/Cargo.toml +++ b/crates/sonic-dash-api-proto/Cargo.toml @@ -12,12 +12,12 @@ edition.workspace = true prost.workspace = true serde.workspace = true sonicdb-derive.workspace = true -swss-common = { git = "https://github.com/sonic-net/sonic-swss-common.git", branch = "master" } +swss-common.workspace = true sonic-common.workspace = true -hex = "0.4" +hex.workspace = true serde_json.workspace = true -strum = "0.26" -strum_macros = "0.26" +strum.workspace = true +strum_macros.workspace = true [build-dependencies] -prost-build = "0.13" +prost-build.workspace = true diff --git a/crates/swss-common-bridge/Cargo.toml b/crates/swss-common-bridge/Cargo.toml index 72306ee4..7bcf8fab 100644 --- a/crates/swss-common-bridge/Cargo.toml +++ b/crates/swss-common-bridge/Cargo.toml @@ -15,9 +15,9 @@ tokio.workspace = true tokio-util.workspace = true swbus-actor = { path = "../swbus-actor" } anyhow.workspace = true -sonic-dash-api-proto = { path = "../sonic-dash-api-proto" } +sonic-dash-api-proto.workspace = true prost.workspace = true -hex = "0.4" +hex.workspace = true serde.workspace = true serde_json.workspace = true sonicdb-derive.workspace = true diff --git a/crates/swss-common/Cargo.toml b/crates/swss-common/Cargo.toml index 679d3cb4..8a32b094 100644 --- a/crates/swss-common/Cargo.toml +++ b/crates/swss-common/Cargo.toml @@ -22,7 +22,7 @@ getset.workspace = true lazy_static.workspace = true tracing-subscriber.workspace = true serde_json.workspace = true -hex = "0.4" +hex.workspace = true prost.workspace = true [build-dependencies] From f38557871787d4e7c9315ecb57d20533aecfbd62 Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 24 Jul 2025 13:35:16 -0400 Subject: [PATCH 18/20] remove swss-common changes. --- crates/swss-common/Cargo.toml | 34 ---------------------------------- crates/swss-common/src/lib.rs | 34 ---------------------------------- 2 files changed, 68 deletions(-) delete mode 100644 crates/swss-common/Cargo.toml delete mode 100644 crates/swss-common/src/lib.rs diff --git a/crates/swss-common/Cargo.toml b/crates/swss-common/Cargo.toml deleted file mode 100644 index 8a32b094..00000000 --- a/crates/swss-common/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "swss-common" -version.workspace = true -authors.workspace = true -license.workspace = true -repository.workspace = true -documentation.workspace = true -keywords.workspace = true -edition.workspace = true - -[lints] -workspace = true - -[features] -async = ["dep:tokio"] - -[dependencies] -libc = "0.2.158" -tokio = { version = "1", optional = true, features = ["net", "rt"] } -serde.workspace = true -getset.workspace = true -lazy_static.workspace = true -tracing-subscriber.workspace = true -serde_json.workspace = true -hex.workspace = true -prost.workspace = true - -[build-dependencies] -bindgen = "0.70.1" - -[dev-dependencies] -swss-common-testing = { path = "../swss-common-testing" } -paste = "1.0.15" -tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] } diff --git a/crates/swss-common/src/lib.rs b/crates/swss-common/src/lib.rs deleted file mode 100644 index f471a032..00000000 --- a/crates/swss-common/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -mod bindings { - #![allow(unused, non_snake_case, non_upper_case_globals, non_camel_case_types)] - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -} -mod types; - -pub use types::*; - -/// Rust wrapper around `swss::SonicDBConfig::initialize`. -pub fn sonic_db_config_initialize(path: &str) -> Result<(), Exception> { - let path = cstr(path); - unsafe { swss_try!(bindings::SWSSSonicDBConfig_initialize(path.as_ptr())) } -} - -/// Rust wrapper around `swss::SonicDBConfig::initializeGlobalConfig`. -pub fn sonic_db_config_initialize_global(path: &str) -> Result<(), Exception> { - let path = cstr(path); - unsafe { swss_try!(bindings::SWSSSonicDBConfig_initializeGlobalConfig(path.as_ptr())) } -} - -/// Trait for objects that can be stored in a Sonic DB table. -pub trait SonicDbTable { - fn key_separator() -> char; - fn table_name() -> &'static str; - fn db_name() -> &'static str; - fn is_proto() -> bool { - false - } - fn convert_pb_to_json(_kfv: &mut KeyOpFieldValues) { - // Default implementation does nothing. - // This can be overridden by the macro to convert protobuf to JSON. - } - fn is_dpu() -> bool; -} From 7663956102201b8aa8141b0bed607f5687550a5e Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 31 Jul 2025 10:39:45 -0400 Subject: [PATCH 19/20] fix merge conflict. --- crates/hamgrd/src/actors/ha_scope.rs | 2 +- crates/hamgrd/src/actors/ha_set.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index 0660f7da..fca417d5 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -217,7 +217,7 @@ impl HaScopeActor { let dash_ha_scope = DashHaScopeTable { version: dash_ha_scope_config.version.parse().unwrap(), - disable: dash_ha_scope_config.disabled, + disabled: dash_ha_scope_config.disabled, ha_role: format!( "{}", DesiredHaState::try_from(dash_ha_scope_config.desired_ha_state).unwrap() diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index e8c33c52..bb9fd330 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -163,6 +163,9 @@ impl HaSetActor { .vnet_name .ok_or(anyhow!("Missing vnet_name in global config"))?, self.dash_ha_set_config.as_ref().unwrap().vip_v4 + .as_ref() + .map(ip_to_string) + .unwrap_or_default() ); if !internal.has_entry(VnetRouteTunnelTable::table_name(), &swss_key) { From da1ae9dead52e3b3678ad90a465e48728990697c Mon Sep 17 00:00:00 2001 From: dypet Date: Thu, 31 Jul 2025 12:07:35 -0400 Subject: [PATCH 20/20] Move SonicDbTable to sonic-common crate. --- Cargo.lock | 10 +++++----- crates/hamgrd/src/actors.rs | 5 ++--- crates/hamgrd/src/actors/dpu.rs | 5 +++-- crates/hamgrd/src/actors/ha_scope.rs | 6 ++++-- crates/hamgrd/src/actors/ha_set.rs | 10 +++++++--- crates/hamgrd/src/actors/vdpu.rs | 5 +++-- crates/hamgrd/src/main.rs | 5 +++-- crates/sonic-common/src/lib.rs | 16 ++++++++++++++++ crates/sonicdb-derive/Cargo.toml | 1 + crates/sonicdb-derive/src/lib.rs | 2 +- crates/sonicdb-derive/tests/basic.rs | 2 +- crates/swbus-actor/Cargo.toml | 1 + crates/swbus-actor/src/state/outgoing.rs | 2 +- crates/swss-common-bridge/Cargo.toml | 1 + crates/swss-common-bridge/src/consumer.rs | 4 ++-- 15 files changed, 51 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f554b9e5..d07c256a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1951,6 +1951,8 @@ dependencies = [ "serde_json", "sonic-common", "sonicdb-derive", + "strum", + "strum_macros", "swss-common", ] @@ -1960,6 +1962,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", + "sonic-common", "swss-common", "syn 2.0.58", ] @@ -2006,6 +2009,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "sonic-common", "swbus-edge", "swss-common", "swss-common-testing", @@ -2144,14 +2148,9 @@ source = "git+https://github.com/sonic-net/sonic-swss-common.git?branch=master#9 dependencies = [ "bindgen", "getset", - "hex", "lazy_static", "libc", - "paste", - "prost", "serde", - "serde_json", - "swss-common-testing", "tokio", "tracing-subscriber", ] @@ -2165,6 +2164,7 @@ dependencies = [ "prost", "serde", "serde_json", + "sonic-common", "sonic-dash-api-proto", "sonicdb-derive", "swbus-actor", diff --git a/crates/hamgrd/src/actors.rs b/crates/hamgrd/src/actors.rs index db7d7034..4cae90bb 100644 --- a/crates/hamgrd/src/actors.rs +++ b/crates/hamgrd/src/actors.rs @@ -9,15 +9,14 @@ pub mod vdpu; #[cfg(test)] pub mod test; use anyhow::Result as AnyhowResult; +use sonic_common::SonicDbTable; use std::sync::Arc; use swbus_actor::{spawn, Actor, ActorMessage}; use swbus_edge::swbus_proto::message_id_generator::MessageIdGenerator; use swbus_edge::swbus_proto::result::*; use swbus_edge::swbus_proto::swbus::{swbus_message::Body, DataRequest, ServicePath, SwbusErrorCode, SwbusMessage}; use swbus_edge::SwbusEdgeRuntime; -use swss_common::{ - KeyOpFieldValues, KeyOperation, SonicDbTable, SubscriberStateTable, ZmqClient, ZmqProducerStateTable, -}; +use swss_common::{KeyOpFieldValues, KeyOperation, SubscriberStateTable, ZmqClient, ZmqProducerStateTable}; use swss_common_bridge::{consumer::ConsumerBridge, producer::spawn_producer_bridge}; use tokio::sync::mpsc::{channel, Receiver}; use tokio::task::JoinHandle; diff --git a/crates/hamgrd/src/actors/dpu.rs b/crates/hamgrd/src/actors/dpu.rs index 727ccb6b..0e6ae79f 100644 --- a/crates/hamgrd/src/actors/dpu.rs +++ b/crates/hamgrd/src/actors/dpu.rs @@ -5,11 +5,12 @@ use crate::db_structs::{ use crate::ha_actor_messages::{ActorRegistration, DpuActorState, RegistrationType}; use crate::ServicePath; use anyhow::{anyhow, Result}; +use sonic_common::SonicDbTable; use std::collections::HashSet; use std::sync::Arc; use swbus_actor::{state::incoming::Incoming, state::outgoing::Outgoing, Actor, ActorMessage, Context, State}; use swbus_edge::SwbusEdgeRuntime; -use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable, SubscriberStateTable}; +use swss_common::{KeyOpFieldValues, KeyOperation, SubscriberStateTable}; use swss_common_bridge::consumer::ConsumerBridge; use tracing::{debug, error, info, instrument}; @@ -474,8 +475,8 @@ mod test { use crate::db_structs::{BfdSessionTable, DashBfdProbeState, DashHaGlobalConfig, Dpu, DpuState, RemoteDpu}; use crate::ha_actor_messages::DpuActorState; + use sonic_common::SonicDbTable; use std::time::Duration; - use swss_common::SonicDbTable; use swss_common_testing::Redis; use swss_serde::to_field_values; diff --git a/crates/hamgrd/src/actors/ha_scope.rs b/crates/hamgrd/src/actors/ha_scope.rs index fca417d5..f91e32d1 100644 --- a/crates/hamgrd/src/actors/ha_scope.rs +++ b/crates/hamgrd/src/actors/ha_scope.rs @@ -3,6 +3,7 @@ use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use crate::{HaSetActor, VDpuActor}; use anyhow::Result; +use sonic_common::SonicDbTable; use sonic_dash_api_proto::decode_from_field_values; use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; use std::collections::HashMap; @@ -11,7 +12,7 @@ use swbus_actor::{ Actor, ActorMessage, Context, State, }; use swss_common::Table; -use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; +use swss_common::{KeyOpFieldValues, KeyOperation}; use swss_common_bridge::consumer::ConsumerBridge; use tracing::{debug, error, info, instrument}; use uuid::Uuid; @@ -601,10 +602,11 @@ mod test { db_structs::{now_in_millis, DashHaScopeTable, DpuDashHaScopeState, NpuDashHaScopeState}, ha_actor_messages::*, }; + use sonic_common::SonicDbTable; use sonic_dash_api_proto::ha_scope_config::{DesiredHaState, HaScopeConfig}; use sonic_dash_api_proto::types::HaOwner; use std::time::Duration; - use swss_common::{SonicDbTable, Table}; + use swss_common::Table; use swss_common_testing::*; use swss_serde::to_field_values; diff --git a/crates/hamgrd/src/actors/ha_set.rs b/crates/hamgrd/src/actors/ha_set.rs index bb9fd330..8b5151d4 100644 --- a/crates/hamgrd/src/actors/ha_set.rs +++ b/crates/hamgrd/src/actors/ha_set.rs @@ -3,6 +3,7 @@ use crate::actors::{spawn_consumer_bridge_for_actor, DbBasedActor}; use crate::db_structs::*; use crate::ha_actor_messages::{ActorRegistration, HaSetActorState, RegistrationType, VDpuActorState}; use anyhow::{anyhow, Result}; +use sonic_common::SonicDbTable; use sonic_dash_api_proto::decode_from_field_values; use sonic_dash_api_proto::ha_set_config::HaSetConfig; use sonic_dash_api_proto::ip_to_string; @@ -11,7 +12,7 @@ use swbus_actor::{ Actor, ActorMessage, Context, State, }; use swss_common::Table; -use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; +use swss_common::{KeyOpFieldValues, KeyOperation}; use swss_common_bridge::consumer::ConsumerBridge; use tracing::{debug, error, info, instrument}; @@ -162,7 +163,10 @@ impl HaSetActor { global_cfg .vnet_name .ok_or(anyhow!("Missing vnet_name in global config"))?, - self.dash_ha_set_config.as_ref().unwrap().vip_v4 + self.dash_ha_set_config + .as_ref() + .unwrap() + .vip_v4 .as_ref() .map(ip_to_string) .unwrap_or_default() @@ -414,13 +418,13 @@ mod test { db_structs::*, ha_actor_messages::*, }; + use sonic_common::SonicDbTable; use sonic_dash_api_proto::ha_set_config::HaSetConfig; use sonic_dash_api_proto::ip_to_string; use std::collections::HashMap; use std::time::Duration; use swss_common::CxxString; use swss_common::KeyOpFieldValues; - use swss_common::SonicDbTable; use swss_common_testing::*; fn protobuf_struct_to_kfv(cfg: &T) -> HashMap { diff --git a/crates/hamgrd/src/actors/vdpu.rs b/crates/hamgrd/src/actors/vdpu.rs index 6db44102..33e0f12c 100644 --- a/crates/hamgrd/src/actors/vdpu.rs +++ b/crates/hamgrd/src/actors/vdpu.rs @@ -3,9 +3,10 @@ use crate::actors::DbBasedActor; use crate::db_structs::VDpu; use crate::ha_actor_messages::{ActorRegistration, DpuActorState, RegistrationType, VDpuActorState}; use anyhow::Result; +use sonic_common::SonicDbTable; use swbus_actor::Context; use swbus_actor::{state::incoming::Incoming, state::outgoing::Outgoing, Actor, State}; -use swss_common::{KeyOpFieldValues, KeyOperation, SonicDbTable}; +use swss_common::{KeyOpFieldValues, KeyOperation}; use tracing::{error, instrument}; pub struct VDpuActor { @@ -150,8 +151,8 @@ mod test { }, ha_actor_messages::*, }; + use sonic_common::SonicDbTable; use std::time::Duration; - use swss_common::SonicDbTable; #[tokio::test] async fn vdpu_actor() { diff --git a/crates/hamgrd/src/main.rs b/crates/hamgrd/src/main.rs index fcdc7360..8b6404d9 100644 --- a/crates/hamgrd/src/main.rs +++ b/crates/hamgrd/src/main.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, Ok}; use clap::Parser; use sonic_common::log; +use sonic_common::SonicDbTable; use std::net::{Ipv4Addr, Ipv6Addr}; use std::{ sync::{Arc, Mutex}, @@ -9,7 +10,7 @@ use std::{ use swbus_actor::{set_global_runtime, ActorRuntime}; use swbus_config::swbus_config_from_db; use swbus_edge::{simple_client::SimpleSwbusEdgeClient, swbus_proto::swbus::ServicePath, RuntimeEnv, SwbusEdgeRuntime}; -use swss_common::{sonic_db_config_initialize_global, DbConnector, SonicDbTable}; +use swss_common::{sonic_db_config_initialize_global, DbConnector}; use swss_common_bridge::consumer::ConsumerBridge; use tokio::{signal, task::JoinHandle, time::timeout}; use tracing::error; @@ -220,7 +221,7 @@ impl RuntimeData { pub fn common_bridge_sp(runtime: &SwbusEdgeRuntime) -> ServicePath where - T: swss_common::SonicDbTable + 'static, + T: sonic_common::SonicDbTable + 'static, { let mut new_sp = runtime.get_base_sp(); new_sp.resource_type = "swss-common-bridge".into(); diff --git a/crates/sonic-common/src/lib.rs b/crates/sonic-common/src/lib.rs index 2f2dd5c2..84262bd2 100644 --- a/crates/sonic-common/src/lib.rs +++ b/crates/sonic-common/src/lib.rs @@ -1,2 +1,18 @@ pub mod log; pub mod panic; +use swss_common::KeyOpFieldValues; + +/// Trait for objects that can be stored in a Sonic DB table. +pub trait SonicDbTable { + fn key_separator() -> char; + fn table_name() -> &'static str; + fn db_name() -> &'static str; + fn is_proto() -> bool { + false + } + fn convert_pb_to_json(_kfv: &mut KeyOpFieldValues) { + // Default implementation does nothing. + // This can be overridden by the macro to convert protobuf to JSON. + } + fn is_dpu() -> bool; +} diff --git a/crates/sonicdb-derive/Cargo.toml b/crates/sonicdb-derive/Cargo.toml index e3d84792..32b1a8f2 100644 --- a/crates/sonicdb-derive/Cargo.toml +++ b/crates/sonicdb-derive/Cargo.toml @@ -13,6 +13,7 @@ syn = "2.0" # For parsing Rust code quote = "1.0" # For generating Rust code proc-macro2 = "1.0" # For working with procedural macros swss-common = { git = "https://github.com/sonic-net/sonic-swss-common.git", branch = "master" } +sonic-common.workspace = true [lib] proc-macro = true diff --git a/crates/sonicdb-derive/src/lib.rs b/crates/sonicdb-derive/src/lib.rs index e1fe9785..351a2570 100644 --- a/crates/sonicdb-derive/src/lib.rs +++ b/crates/sonicdb-derive/src/lib.rs @@ -118,7 +118,7 @@ pub fn serde_sonicdb_derive(input: TokenStream) -> TokenStream { let is_dpu_value = is_dpu; let expanded = quote! { - impl swss_common::SonicDbTable for #struct_name { + impl sonic_common::SonicDbTable for #struct_name { fn key_separator() -> char { #key_separator } diff --git a/crates/sonicdb-derive/tests/basic.rs b/crates/sonicdb-derive/tests/basic.rs index 11cb4fe9..7e6b4bc2 100644 --- a/crates/sonicdb-derive/tests/basic.rs +++ b/crates/sonicdb-derive/tests/basic.rs @@ -1,6 +1,6 @@ #![allow(unused)] +use sonic_common::SonicDbTable; use sonicdb_derive::SonicDb; -use swss_common::SonicDbTable; #[test] fn test_attributes() { #[derive(SonicDb)] diff --git a/crates/swbus-actor/Cargo.toml b/crates/swbus-actor/Cargo.toml index 338ed3b8..eb77038f 100644 --- a/crates/swbus-actor/Cargo.toml +++ b/crates/swbus-actor/Cargo.toml @@ -17,6 +17,7 @@ serde_json.workspace = true serde_with.workspace = true anyhow.workspace = true tracing.workspace = true +sonic-common.workspace = true [lints] workspace = true diff --git a/crates/swbus-actor/src/state/outgoing.rs b/crates/swbus-actor/src/state/outgoing.rs index 3a3d87dd..24215b3c 100644 --- a/crates/swbus-actor/src/state/outgoing.rs +++ b/crates/swbus-actor/src/state/outgoing.rs @@ -144,7 +144,7 @@ impl Outgoing { pub fn common_bridge_sp(&self) -> ServicePath where - T: swss_common::SonicDbTable + 'static, + T: sonic_common::SonicDbTable + 'static, { let resource_id = format!("{}|{}", T::db_name(), T::table_name()); self.from_my_sp("swss-common-bridge", &resource_id) diff --git a/crates/swss-common-bridge/Cargo.toml b/crates/swss-common-bridge/Cargo.toml index 7bcf8fab..91922287 100644 --- a/crates/swss-common-bridge/Cargo.toml +++ b/crates/swss-common-bridge/Cargo.toml @@ -21,6 +21,7 @@ hex.workspace = true serde.workspace = true serde_json.workspace = true sonicdb-derive.workspace = true +sonic-common.workspace = true [lints] workspace = true diff --git a/crates/swss-common-bridge/src/consumer.rs b/crates/swss-common-bridge/src/consumer.rs index 2d65012f..299272c2 100644 --- a/crates/swss-common-bridge/src/consumer.rs +++ b/crates/swss-common-bridge/src/consumer.rs @@ -1,3 +1,4 @@ +use sonic_common::SonicDbTable; use std::{collections::HashMap, future::Future, sync::Arc}; use swbus_actor::ActorMessage; use swbus_edge::{ @@ -6,8 +7,7 @@ use swbus_edge::{ SwbusEdgeRuntime, }; use swss_common::{ - ConsumerStateTable, FieldValues, KeyOpFieldValues, KeyOperation, SonicDbTable, SubscriberStateTable, Table, - ZmqConsumerStateTable, + ConsumerStateTable, FieldValues, KeyOpFieldValues, KeyOperation, SubscriberStateTable, Table, ZmqConsumerStateTable, }; use tokio::task::JoinHandle; use tokio_util::task::AbortOnDropHandle;