package birdfmt import ( "fmt" "strings" ) // Directory and fragment file names for EvoBGP-generated includes (relative to bird.conf). const ( DirBirdD = "bird.d" FragmentPrefixesV4 = "evobgp_prefixes_v4.conf" FragmentPrefixesV6 = "evobgp_prefixes_v6.conf" FragmentFiltersV4 = "evobgp_filters_v4.conf" FragmentFiltersV6 = "evobgp_filters_v6.conf" FragmentBGPTemplate = "evobgp_bgp_template.conf" FragmentPeers = "evobgp_peers.conf" ) // FragmentIncludePath returns a POSIX include path such as bird.d/evobgp_prefixes_v4.conf. func FragmentIncludePath(fragmentBaseName string) string { if fragmentBaseName == "" { return DirBirdD + "/" } return DirBirdD + "/" + fragmentBaseName } // StandardIncludeFragments is the recommended order: filters before BGP templates and peers. func StandardIncludeFragments() []string { return []string{ FragmentIncludePath(FragmentFiltersV4), FragmentIncludePath(FragmentFiltersV6), FragmentIncludePath(FragmentBGPTemplate), FragmentIncludePath(FragmentPrefixesV4), FragmentIncludePath(FragmentPrefixesV6), FragmentIncludePath(FragmentPeers), } } // MainBirdConfOptions describes the top-level bird.conf skeleton EvoBGP expects beside bird.d/. type MainBirdConfOptions struct { // RouterID is the BIRD router id (IPv4 dotted quad recommended). RouterID string // Includes are paths as in include "…" (e.g. bird.d/evobgp_prefixes_v4.conf). Includes []string // Preamble is optional comment lines (each line prefixed with #), no trailing newline required. Preamble string } // RenderMainBirdConf returns a BIRD 2 main config: device, direct, include lines. // RouterID must be non-empty. func RenderMainBirdConf(opts MainBirdConfOptions) (string, error) { if strings.TrimSpace(opts.RouterID) == "" { return "", fmt.Errorf("birdfmt: router id is required") } var b strings.Builder pre := strings.TrimSpace(opts.Preamble) if pre != "" { for _, line := range strings.Split(pre, "\n") { line = strings.TrimRight(line, "\r") if line == "" { b.WriteByte('\n') continue } if !strings.HasPrefix(line, "#") { b.WriteString("# ") } b.WriteString(line) b.WriteByte('\n') } b.WriteByte('\n') } b.WriteString("router id ") b.WriteString(strings.TrimSpace(opts.RouterID)) b.WriteString(";\n\n") for _, inc := range opts.Includes { inc = strings.TrimSpace(inc) if inc == "" { continue } b.WriteString("include \"") b.WriteString(inc) b.WriteString("\";\n") } if len(opts.Includes) > 0 { b.WriteByte('\n') } b.WriteString(`protocol device { } protocol direct { ipv4; ipv6; } `) return b.String(), nil }