Skip to content

Commit 549abb9

Browse files
committed
chore: add rules
Signed-off-by: gruyaume <guillaume.belanger27@gmail.com>
1 parent cd109dc commit 549abb9

3 files changed

Lines changed: 96 additions & 29 deletions

File tree

fleet/client/register.go

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ type Subscriber struct {
9494
Opc string `json:"opc"`
9595
}
9696

97+
// NetworkRule is a per-policy filter rule. Identified by
98+
// (policy_name, direction, precedence); precedence is 1-indexed and
99+
// unique within (policy_name, direction).
100+
type NetworkRule struct {
101+
PolicyName string `json:"policy_name"`
102+
Direction string `json:"direction"` // "uplink" or "downlink"
103+
Precedence int32 `json:"precedence"`
104+
Description string `json:"description"`
105+
RemotePrefix *string `json:"remote_prefix,omitempty"`
106+
Protocol int32 `json:"protocol"`
107+
PortLow int32 `json:"port_low"`
108+
PortHigh int32 `json:"port_high"`
109+
Action string `json:"action"` // "allow" or "deny"
110+
}
111+
97112
type Route struct {
98113
ID int64 `json:"id"`
99114
Destination string `json:"destination"`
@@ -102,6 +117,38 @@ type Route struct {
102117
Metric int `json:"metric"`
103118
}
104119

120+
type BGPSettings struct {
121+
Enabled bool `json:"enabled"`
122+
LocalAS int `json:"local_as"`
123+
RouterID string `json:"router_id"`
124+
ListenAddress string `json:"listen_address"`
125+
}
126+
127+
// BGPPeer is per-node: each Core receives only the peers Fleet has
128+
// scoped to the node making the sync request, and reconciles its local
129+
// bgp_peers table against that list. Address is unique per node.
130+
type BGPPeer struct {
131+
Address string `json:"address"`
132+
RemoteAS int `json:"remote_as"`
133+
HoldTime int `json:"hold_time"`
134+
Password string `json:"password,omitempty"`
135+
Description string `json:"description"`
136+
}
137+
138+
// BGPImportPrefix references a peer by its Address (natural key).
139+
type BGPImportPrefix struct {
140+
PeerAddress string `json:"peer_address"`
141+
Prefix string `json:"prefix"`
142+
MaxLength int `json:"max_length"`
143+
}
144+
145+
// RetentionPolicy holds the retention days for a single category:
146+
// "audit", "radio", "usage", or "flow_reports".
147+
type RetentionPolicy struct {
148+
Category string `json:"category"`
149+
Days int `json:"days"`
150+
}
151+
105152
type N2Interface struct {
106153
Address string `json:"address"`
107154
Port int `json:"port"`
@@ -137,21 +184,26 @@ type StatusNetworkInterfaces struct {
137184
}
138185

139186
type Networking struct {
140-
DataNetworks []DataNetwork `json:"data_networks"`
141-
Routes []Route `json:"routes"`
142-
NAT bool `json:"nat"`
143-
FlowAccounting bool `json:"flow_accounting"`
144-
N3ExternalAddress string `json:"n3_external_address"`
187+
DataNetworks []DataNetwork `json:"data_networks"`
188+
Routes []Route `json:"routes"`
189+
NAT bool `json:"nat"`
190+
FlowAccounting bool `json:"flow_accounting"`
191+
N3ExternalAddress string `json:"n3_external_address"`
192+
BGP BGPSettings `json:"bgp"`
193+
BGPPeers []BGPPeer `json:"bgp_peers"`
194+
BGPImportPrefixes []BGPImportPrefix `json:"bgp_import_prefixes"`
145195
}
146196

147197
type EllaCoreConfig struct {
148-
Operator Operator `json:"operator"`
149-
HomeNetworkKeys []HomeNetworkKey `json:"home_network_keys"`
150-
Networking Networking `json:"networking"`
151-
Profiles []Profile `json:"profiles"`
152-
Slices []Slice `json:"slices"`
153-
Policies []Policy `json:"policies"`
154-
Subscribers []Subscriber `json:"subscribers"`
198+
Operator Operator `json:"operator"`
199+
HomeNetworkKeys []HomeNetworkKey `json:"home_network_keys"`
200+
Networking Networking `json:"networking"`
201+
Profiles []Profile `json:"profiles"`
202+
Slices []Slice `json:"slices"`
203+
Policies []Policy `json:"policies"`
204+
NetworkRules []NetworkRule `json:"network_rules"`
205+
Subscribers []Subscriber `json:"subscribers"`
206+
RetentionPolicies []RetentionPolicy `json:"retention_policies"`
155207
}
156208

157209
type PlmnID struct {

fleet/client/sync.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,21 @@ type SyncNetworking struct {
5555
NAT bool `json:"nat"`
5656
FlowAccounting bool `json:"flow_accounting"`
5757
NetworkInterfaces SyncNetworkInterfaces `json:"network_interfaces"`
58+
BGP BGPSettings `json:"bgp"`
59+
BGPPeers []BGPPeer `json:"bgp_peers"`
60+
BGPImportPrefixes []BGPImportPrefix `json:"bgp_import_prefixes"`
5861
}
5962

6063
type SyncConfig struct {
61-
Operator Operator `json:"operator"`
62-
HomeNetworkKeys []HomeNetworkKey `json:"home_network_keys"`
63-
Networking SyncNetworking `json:"networking"`
64-
Profiles []Profile `json:"profiles"`
65-
Slices []Slice `json:"slices"`
66-
Policies []Policy `json:"policies"`
67-
Subscribers []Subscriber `json:"subscribers"`
64+
Operator Operator `json:"operator"`
65+
HomeNetworkKeys []HomeNetworkKey `json:"home_network_keys"`
66+
Networking SyncNetworking `json:"networking"`
67+
Profiles []Profile `json:"profiles"`
68+
Slices []Slice `json:"slices"`
69+
Policies []Policy `json:"policies"`
70+
NetworkRules []NetworkRule `json:"network_rules"`
71+
Subscribers []Subscriber `json:"subscribers"`
72+
RetentionPolicies []RetentionPolicy `json:"retention_policies"`
6873
}
6974

7075
type SyncResponse struct {

fleet/fleet.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,14 @@ type syncer interface {
103103
Sync(ctx context.Context, params *client.SyncParams) (*client.SyncResponse, error)
104104
}
105105

106-
// syncDB abstracts the database operations needed by the sync loop. The
107-
// leader-only operations (UpdateConfig, UpdateFleetConfigRevision,
108-
// GetRawDailyUsage) are not called on followers.
106+
// syncDB abstracts the database operations needed by the sync loop.
107+
// UpdateConfig and GetRawDailyUsage are leader-only (replicated tables;
108+
// the leader's apply propagates via Raft). UpdateNodeConfig and
109+
// UpdateFleetConfigRevision run on every node — they write to local-only
110+
// tables (per-node network config and the fleet registration row).
109111
type syncDB interface {
110112
UpdateConfig(ctx context.Context, cfg client.SyncConfig) error
113+
UpdateNodeConfig(ctx context.Context, cfg client.SyncConfig) error
111114
UpdateFleetConfigRevision(ctx context.Context, revision int64) error
112115
GetRawDailyUsage(ctx context.Context, start, end time.Time) ([]db.DailyUsage, error)
113116
GetFleet(ctx context.Context) (*db.Fleet, error)
@@ -191,13 +194,20 @@ func (r *syncRunner) runOneCycle(ctx context.Context) {
191194
r.tracker.Confirm(currentStatus)
192195
}
193196

194-
// Only the leader applies config and records the revision — a follower
195-
// must not write to the replicated fleet table (that would desync the
196-
// revision across nodes mid-cycle) and must not apply config changes
197-
// (the leader's apply already replicates).
198-
if isLeader && resp.Config != nil {
199-
if err := r.db.UpdateConfig(ctx, *resp.Config); err != nil {
200-
logger.EllaLog.Error("failed to apply fleet config", zap.Error(err))
197+
// Cluster-wide replicated state (operator, profiles, slices, policies,
198+
// subscribers, etc.) is applied only by the leader; the resulting
199+
// changeset propagates to followers via Raft. Per-node state (NAT,
200+
// flow accounting, N3, routes, BGP) is applied locally on every node
201+
// against its own node-scoped slice of the response.
202+
if resp.Config != nil {
203+
if isLeader {
204+
if err := r.db.UpdateConfig(ctx, *resp.Config); err != nil {
205+
logger.EllaLog.Error("failed to apply fleet config", zap.Error(err))
206+
}
207+
}
208+
209+
if err := r.db.UpdateNodeConfig(ctx, *resp.Config); err != nil {
210+
logger.EllaLog.Error("failed to apply per-node fleet config", zap.Error(err))
201211
} else {
202212
r.lastKnownRev = resp.ConfigRevision
203213

0 commit comments

Comments
 (0)