Skip to content

Commit

Permalink
gs: Ensure deterministic order of frequency plans
Browse files Browse the repository at this point in the history
  • Loading branch information
cvetkovski98 committed Nov 15, 2023
1 parent 1b7cd8d commit c4b70d8
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 50 deletions.
27 changes: 12 additions & 15 deletions pkg/gatewayserver/io/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ type Connection struct {
frontend Frontend
gateway *ttnpb.Gateway
gatewayPrimaryFP *frequencyplans.FrequencyPlan
gatewayFPs map[string]*frequencyplans.FrequencyPlan
gatewayFPs []*frequencyplans.FrequencyPlan
band *band.Band
fps *frequencyplans.Store
scheduler *scheduling.Scheduler
Expand Down Expand Up @@ -178,13 +178,13 @@ func NewConnection(
opt(connectionOptions)
}

gatewayFPs := make(map[string]*frequencyplans.FrequencyPlan, len(gateway.FrequencyPlanIds))
gatewayFPs := make([]*frequencyplans.FrequencyPlan, len(gateway.FrequencyPlanIds))
fp0ID := gateway.FrequencyPlanId
fp0, err := fps.GetByID(fp0ID)
if err != nil {
return nil, err
}
gatewayFPs[fp0ID] = fp0
gatewayFPs[0] = fp0
phy, err := band.GetLatest(fp0.BandID)
if err != nil {
return nil, err
Expand All @@ -202,7 +202,7 @@ func NewConnection(
if fpn.BandID != fp0.BandID {
return nil, errFrequencyPlansNotFromSameBand.New()
}
gatewayFPs[gateway.FrequencyPlanIds[i]] = fpn
gatewayFPs[i] = fpn
}
}

Expand Down Expand Up @@ -530,16 +530,13 @@ func (c *Connection) ScheduleDown(path *ttnpb.DownlinkPath, msg *ttnpb.DownlinkM
var fp *frequencyplans.FrequencyPlan
fpID := request.GetFrequencyPlanId()
if fpID != "" {
fp = c.gatewayFPs[fpID]
if fp == nil {
// The requested frequency plan is not configured for the gateway. Load the plan and enforce that it's in the same band.
fp, err = c.fps.GetByID(fpID)
if err != nil {
return false, false, 0, errFrequencyPlanNotConfigured.WithCause(err).WithAttributes("id", request.FrequencyPlanId)
}
if fp.BandID != c.band.ID {
return false, false, 0, errFrequencyPlansNotFromSameBand.New()
}
// Load the plan and enforce that it's in the same band.
fp, err = c.fps.GetByID(fpID)
if err != nil {
return false, false, 0, errFrequencyPlanNotConfigured.WithCause(err).WithAttributes("id", request.FrequencyPlanId)
}
if fp.BandID != c.band.ID {
return false, false, 0, errFrequencyPlansNotFromSameBand.New()
}
} else {
// Backwards compatibility. If there's no FrequencyPlanID in the TxRequest, then there must be only one Frequency
Expand Down Expand Up @@ -863,7 +860,7 @@ func (c *Connection) Stats() (*ttnpb.GatewayConnectionStats, []string) {
}

// FrequencyPlans returns the frequency plans for the gateway.
func (c *Connection) FrequencyPlans() map[string]*frequencyplans.FrequencyPlan { return c.gatewayFPs }
func (c *Connection) FrequencyPlans() []*frequencyplans.FrequencyPlan { return c.gatewayFPs }

// PrimaryFrequencyPlan returns the primary frequency plan of the gateway.
func (c *Connection) PrimaryFrequencyPlan() *frequencyplans.FrequencyPlan { return c.gatewayPrimaryFP }
Expand Down
2 changes: 1 addition & 1 deletion pkg/gatewayserver/io/ws/lbslns/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (*lbsLNS) GetRouterConfig(
ctx context.Context,
msg []byte,
bandID string,
fps map[string]*frequencyplans.FrequencyPlan,
fps []*frequencyplans.FrequencyPlan,
antennaGain int,
receivedAt time.Time,
) (context.Context, []byte, *ttnpb.GatewayStatus, error) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/gatewayserver/scheduling/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ var (
// If no time source is specified, the system time is used.
func NewScheduler(
ctx context.Context,
fps map[string]*frequencyplans.FrequencyPlan,
fps []*frequencyplans.FrequencyPlan,
enforceDutyCycle bool,
dutyCycleStyle DutyCycleStyle,
scheduleAnytimeDelay *time.Duration,
Expand Down Expand Up @@ -188,7 +188,7 @@ func NewScheduler(
// Scheduler is a packet scheduler that takes time conflicts and sub-band restrictions into account.
type Scheduler struct {
clock *RolloverClock
fps map[string]*frequencyplans.FrequencyPlan
fps []*frequencyplans.FrequencyPlan
timeOffAir frequencyplans.TimeOffAir
timeSource TimeSource
subBands []*SubBand
Expand Down
50 changes: 25 additions & 25 deletions pkg/gatewayserver/scheduling/scheduler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
func TestScheduleAtWithBandDutyCycle(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down Expand Up @@ -350,7 +350,7 @@ func TestScheduleAtWithBandDutyCycle(t *testing.T) {
func TestScheduleAtWithFrequencyPlanDutyCycle(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{{
BandID: band.EU_863_870,
SubBands: []frequencyplans.SubBandParameters{
{
Expand Down Expand Up @@ -438,7 +438,7 @@ func TestScheduleAtWithFrequencyPlanDutyCycle(t *testing.T) {
func TestScheduleAnytime(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down Expand Up @@ -552,7 +552,7 @@ func TestScheduleAnytime(t *testing.T) {
func TestScheduleAnytimeShort(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down Expand Up @@ -752,7 +752,7 @@ func TestScheduleAnytimeShort(t *testing.T) {
func TestScheduleAnytimeClassC(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down Expand Up @@ -843,14 +843,14 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
ctx := test.Context()
for _, tc := range []struct {
Name string
FrequencyPlans map[string]*frequencyplans.FrequencyPlan
FrequencyPlans []*frequencyplans.FrequencyPlan
ExpectedSubBandCount int
ErrorAssertion func(error) bool
}{
{
Name: "RepeatedNoOverlap",
FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{
test.EUFrequencyPlanID: {
FrequencyPlans: []*frequencyplans.FrequencyPlan{
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -860,7 +860,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
Duration: durationPtr(2 * time.Second),
},
},
"EU_863_870_Custom": {
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -875,8 +875,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
},
{
Name: "UnionOfNonOverlapping",
FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{
test.EUFrequencyPlanID: {
FrequencyPlans: []*frequencyplans.FrequencyPlan{
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -895,7 +895,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
},
},
},
"EU_863_870_Custom": {
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -910,8 +910,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
},
{
Name: "MismatchedTimeOffAir",
FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{
test.EUFrequencyPlanID: {
FrequencyPlans: []*frequencyplans.FrequencyPlan{
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: 2 * time.Second,
Expand All @@ -921,7 +921,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
Duration: durationPtr(2 * time.Second),
},
},
"EU_863_870_Custom": {
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -938,8 +938,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
},
{
Name: "OverlappingSubBands",
FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{
test.EUFrequencyPlanID: {
FrequencyPlans: []*frequencyplans.FrequencyPlan{
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -958,7 +958,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
},
},
},
"EU_863_870_Custom": {
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -975,8 +975,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
},
{
Name: "OverlappingSubBandsFromBand",
FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{
"AS_923": {
FrequencyPlans: []*frequencyplans.FrequencyPlan{
{
// This is a fictional test case since currently we don't support mix-band frequency plans (https://github.com/TheThingsNetwork/lorawan-stack/issues/1394).
BandID: band.AS_923,
TimeOffAir: frequencyplans.TimeOffAir{
Expand All @@ -987,7 +987,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
Duration: durationPtr(2 * time.Second),
},
},
"AU_915_928": {
{
BandID: band.AU_915_928,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down Expand Up @@ -1029,8 +1029,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) {
func TestSchedulingWithMultipleFrequencyPlans(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{
test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand All @@ -1049,7 +1049,7 @@ func TestSchedulingWithMultipleFrequencyPlans(t *testing.T) {
},
},
},
"EU_863_870_Custom": {
{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down Expand Up @@ -1140,7 +1140,7 @@ func TestSchedulingWithMultipleFrequencyPlans(t *testing.T) {
func TestScheduleSyncViaUplinkToken(t *testing.T) {
a := assertions.New(t)
ctx := test.Context()
fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: {
fps := []*frequencyplans.FrequencyPlan{{
BandID: band.EU_863_870,
TimeOffAir: frequencyplans.TimeOffAir{
Duration: time.Second,
Expand Down
11 changes: 6 additions & 5 deletions pkg/pfconfig/lbslns/lbslbs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func TestGetRouterConfig(t *testing.T) {
t.Parallel()

a, ctx := test.New(t)
fps := map[string]*frequencyplans.FrequencyPlan{tc.FrequencyPlanID: &tc.FrequencyPlan}
fps := []*frequencyplans.FrequencyPlan{&tc.FrequencyPlan}
cfg, err := GetRouterConfig(ctx, tc.FrequencyPlan.BandID, fps, tc.Features, time.Now(), 0)
if err != nil {
if tc.ErrorAssertion == nil || !a.So(tc.ErrorAssertion(err), should.BeTrue) {
Expand All @@ -295,16 +295,16 @@ func TestGetRouterConfigWithMultipleFP(t *testing.T) {
for _, tc := range []struct {
Name string
BandID string
FrequencyPlans map[string]*frequencyplans.FrequencyPlan
FrequencyPlans []*frequencyplans.FrequencyPlan
Cfg RouterConfig
Features TestFeatures
ErrorAssertion func(err error) bool
}{
{
Name: "ValidFrequencyPlan",
BandID: "US_902_928",
FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{
test.USFrequencyPlanID: {
FrequencyPlans: []*frequencyplans.FrequencyPlan{
{
BandID: "US_902_928",
Radios: []frequencyplans.Radio{
{
Expand All @@ -322,7 +322,8 @@ func TestGetRouterConfigWithMultipleFP(t *testing.T) {
Frequency: 925000000,
},
},
}, "US_902_928_Custom": {
},
{
BandID: "US_902_928",
Radios: []frequencyplans.Radio{
{
Expand Down
4 changes: 2 additions & 2 deletions pkg/pfconfig/lbslns/lbslns.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ type RouterFeatures interface {
func GetRouterConfig(
ctx context.Context,
bandID string,
fps map[string]*frequencyplans.FrequencyPlan,
fps []*frequencyplans.FrequencyPlan,
features RouterFeatures,
dlTime time.Time,
antennaGain int,
Expand Down Expand Up @@ -386,7 +386,7 @@ func getDataRatesFromBandID(id string) (DataRates, error) {
}

// getMinMaxFrequencies extract the minimum and maximum frequencies between all the bands.
func getMinMaxFrequencies(fps map[string]*frequencyplans.FrequencyPlan) (min uint64, max uint64, err error) {
func getMinMaxFrequencies(fps []*frequencyplans.FrequencyPlan) (min uint64, max uint64, err error) {
min = math.MaxUint64
for _, fp := range fps {
if len(fp.Radios) == 0 {
Expand Down

0 comments on commit c4b70d8

Please sign in to comment.