| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- package dynamicrouting
- import (
- "os"
- "path/filepath"
- "strings"
- "testing"
- )
- func TestOSPFStatusIsPerInstance(t *testing.T) {
- dir := t.TempDir()
- text := "#!/bin/sh\nprintf 'ospf_a OSPF master4 up 00:00\\nospf_b OSPF master4 down 00:00\\n'\n"
- if err := os.WriteFile(filepath.Join(dir, "birdc"), []byte(text), 0755); err != nil {
- t.Fatal(err)
- }
- t.Setenv("PATH", dir+":"+os.Getenv("PATH"))
- m := &Manager{}
- m.config.OSPFInstances = []OSPFInstance{{Name: "a"}, {Name: "b"}, {Name: "c"}}
- got := m.ListOSPFInstances()
- if !got[0].Running || got[1].Running || got[2].Running {
- t.Fatal("one OSPF instance marked other instances running", got)
- }
- }
- func TestOSPFBirdConfigGeneration(t *testing.T) {
- m := &Manager{}
- m.config.OSPFInstances = []OSPFInstance{
- {
- ID: "inst-1",
- Name: "core",
- Version: 2,
- VRF: "vrf-mgmt",
- RoutingTable: "t100",
- RouterID: "10.255.0.1",
- Enabled: true,
- RedistributeConnected: true,
- RedistributeStatic: false, // Must NOT export RTS_STATIC
- RedistributeBGP: true,
- DefaultMetric: 55,
- },
- }
- m.config.OSPFAreas = []OSPFArea{
- {
- ID: "area-1",
- Name: "stub-area",
- Instance: "core",
- AreaID: "0.0.0.10",
- AreaType: "stub",
- DefaultCost: 25,
- NoSummaries: true,
- },
- }
- m.config.OSPFAreaRanges = []OSPFAreaRange{
- {
- ID: "range-1",
- Area: "stub-area",
- Prefix: "10.10.0.0/16",
- Cost: 10,
- Advertise: false, // Must emit hidden;
- },
- {
- ID: "range-2",
- Area: "stub-area",
- Prefix: "10.20.0.0/16",
- Cost: 5,
- Advertise: true,
- },
- }
- m.config.OSPFInterfaces = []OSPFInterface{
- {
- ID: "iface-1",
- Interfaces: "eth0, eth1",
- Area: "stub-area",
- Networks: "10.10.1.0/24",
- NetworkType: "nonbroadcast",
- Cost: 15,
- Priority: 64,
- Auth: "md5",
- AuthKey: "secretpass",
- },
- }
- m.config.OSPFStaticNbrs = []OSPFStaticNeighbor{
- {
- ID: "snbr-1",
- Address: "10.10.1.5",
- Area: "stub-area",
- PollInterval: 30,
- Cost: 15,
- },
- {
- ID: "snbr-2",
- Address: "192.168.99.1",
- Area: "stub-area",
- PollInterval: 45,
- Cost: 20,
- },
- }
- conf := m.generateBirdConfig()
- // 1. Verify instance settings
- if !strings.Contains(conf, "protocol ospf v2 ospf_core {") {
- t.Fatalf("missing protocol ospf v2 ospf_core in config:\n%s", conf)
- }
- if !strings.Contains(conf, "vrf vrf-mgmt;") {
- t.Fatalf("missing vrf vrf-mgmt in config:\n%s", conf)
- }
- if !strings.Contains(conf, "router id 10.255.0.1;") {
- t.Fatalf("missing router id 10.255.0.1 in config:\n%s", conf)
- }
- if !strings.Contains(conf, "table t100;") {
- t.Fatalf("missing table t100 in config:\n%s", conf)
- }
- // 2. Verify redistribution & default metric
- ospfBlock := conf[strings.Index(conf, "protocol ospf v2 ospf_core"):]
- if strings.Contains(ospfBlock, "RTS_STATIC") {
- t.Fatalf("RTS_STATIC exported even though RedistributeStatic is false:\n%s", ospfBlock)
- }
- if !strings.Contains(ospfBlock, "RTS_DEVICE, RTS_BGP") {
- t.Fatalf("expected RTS_DEVICE, RTS_BGP in export filter:\n%s", ospfBlock)
- }
- if !strings.Contains(ospfBlock, "ospf_metric1 = 55;") {
- t.Fatalf("missing ospf_metric1 = 55; in export filter:\n%s", ospfBlock)
- }
- // 3. Verify area options: stub, default cost, summary no
- if !strings.Contains(conf, "area 0.0.0.10 {") {
- t.Fatalf("missing area 0.0.0.10 in config:\n%s", conf)
- }
- if !strings.Contains(conf, "stub;") {
- t.Fatalf("missing stub; in area:\n%s", conf)
- }
- if !strings.Contains(conf, "default cost 25;") {
- t.Fatalf("missing default cost 25; in area:\n%s", conf)
- }
- if !strings.Contains(conf, "summary no;") {
- t.Fatalf("missing summary no; in area:\n%s", conf)
- }
- // 4. Verify area range advertising: hidden; for advertise=false
- if !strings.Contains(conf, "stubnet 10.10.0.0/16 { cost 10; hidden; };") {
- t.Fatalf("missing stubnet 10.10.0.0/16 { cost 10; hidden; }; in config:\n%s", conf)
- }
- if !strings.Contains(conf, "stubnet 10.20.0.0/16 { cost 5; };") {
- t.Fatalf("missing stubnet 10.20.0.0/16 { cost 5; }; in config:\n%s", conf)
- }
- // 5. Verify interface template formatting: comma separated interfaces
- if !strings.Contains(conf, "interface \"eth0\", \"eth1\", 10.10.1.0/24 {") {
- t.Fatalf("missing interface \"eth0\", \"eth1\", 10.10.1.0/24 { in config:\n%s", conf)
- }
- if !strings.Contains(conf, "type nonbroadcast;") {
- t.Fatalf("missing type nonbroadcast; in config:\n%s", conf)
- }
- if !strings.Contains(conf, "cost 15;") {
- t.Fatalf("missing cost 15; in config:\n%s", conf)
- }
- if !strings.Contains(conf, "priority 64;") {
- t.Fatalf("missing priority 64; in config:\n%s", conf)
- }
- if !strings.Contains(conf, "authentication cryptographic;\n password \"secretpass\";") {
- t.Fatalf("missing authentication cryptographic and password in config:\n%s", conf)
- }
- // 6. Verify static neighbor attached to matching interface template
- if !strings.Contains(conf, "10.10.1.5;") {
- t.Fatalf("missing static neighbor 10.10.1.5 in config:\n%s", conf)
- }
- // 7. Verify remaining static neighbor in fallback interface "*"
- if !strings.Contains(conf, "192.168.99.1;") {
- t.Fatalf("missing static neighbor 192.168.99.1 in config:\n%s", conf)
- }
- }
- func TestOSPFStaticNeighborManagement(t *testing.T) {
- m := &Manager{}
- snbr := OSPFStaticNeighbor{
- Address: "10.0.0.2",
- Area: "Default",
- PollInterval: 60,
- Cost: 5,
- }
- if err := m.SaveOSPFStaticNeighbor(snbr); err != nil {
- // applyBirdConfig may fail if bird is not running in test env, but config must be in memory
- t.Logf("Save returned error (expected in mock env): %v", err)
- }
- list := m.ListOSPFStaticNeighbors()
- if len(list) != 1 || list[0].Address != "10.0.0.2" {
- t.Fatalf("expected 1 static neighbor with address 10.0.0.2, got: %+v", list)
- }
- id := list[0].ID
- _ = m.SetOSPFStaticNeighborState(id, true)
- list2 := m.ListOSPFStaticNeighbors()
- if !list2[0].Disabled {
- t.Fatalf("expected neighbor to be disabled, got: %+v", list2[0])
- }
- _ = m.DeleteOSPFStaticNeighbor(id)
- list3 := m.ListOSPFStaticNeighbors()
- if len(list3) != 0 {
- t.Fatalf("expected 0 static neighbors after delete, got: %+v", list3)
- }
- }
|