routers update

This commit is contained in:
Graham McIntire 2026-05-09 09:00:35 -05:00
parent 6f65f1035a
commit 34c88a2380
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
12 changed files with 177 additions and 31 deletions

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = K4QG-8NQV
#
# model = RB5009UG+S+
@ -468,7 +468,7 @@ add chain=ospf-in disabled=no rule="accept;\r\
add chain=ospf-out disabled=no rule="accept;"
/routing ospf interface-template
add area=ospf-area-1 auth=sha512 auth-id=1 disabled=no interfaces=\
ether2-climax type=ptp use-bfd=yes
ether2-climax type=ptp use-bfd=no
add area=ospf-area-1 disabled=no passive
/routing ospf static-neighbor
add address=10.250.1.70%ether2-climax area=ospf-area-1 disabled=no \

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = FUVS-HCM5
#
# model = CCR1009-7G-1C-1S+

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = UETF-WF31
#
# model = CCR2004-16G-2S+
@ -399,8 +399,6 @@ set api address=204.110.188.0/22,10.0.0.0/8,100.64.0.0/10
set api-ssl certificate=MyCA
/ip ssh
set host-key-type=ed25519 strong-crypto=yes
/ipv6 address
add address=2606:1c80:0:1010::1 interface=ether6-verona-11ghz
/ipv6 dhcp-relay option
set client_mac value="0x0001\$(CLIENT_MAC)"
/ipv6 nd
@ -436,7 +434,7 @@ add area=backbone-v3 cost=10 disabled=no use-bfd=no
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
ether6-verona-11ghz priority=1 type=ptp use-bfd=no
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
ether5-494 priority=1 type=ptp use-bfd=yes
ether5-494 priority=1 type=ptp use-bfd=no
add area=backbone-v3 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\
ether3-culleoka-11ghz priority=1 type=ptp use-bfd=no
add area=backbone-v2 auth=sha512 auth-id=1 cost=10 disabled=no interfaces=\

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = XS5B-41QR
#
# model = CCR1009-7G-1C-1S+

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = HVP9-3G0K
#
# model = CCR1009-7G-1C-1S+

View file

@ -1,4 +1,4 @@
# may/09/2026 08:51:41 by RouterOS 6.49.18
# may/09/2026 09:00:22 by RouterOS 6.49.18
# software id = 8XZE-R7EJ
#
# model = CCR2004-1G-12S+2XS

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = 2I9X-PQZP
#
# model = CCR1009-7G-1C-1S+

View file

@ -285,17 +285,21 @@ func runExport(cfg *Config) {
wg.Wait()
}
// findRouter looks up a router by name in the config; returns nil if missing.
func findRouter(cfg *Config, name string) *Router {
for i := range cfg.Routers {
if cfg.Routers[i].Name == name {
r := cfg.Routers[i]
return &r
}
}
return nil
}
// runAPI logs into one router by name and runs an arbitrary API command,
// printing the rows returned. Useful for ad-hoc lookups (`arp culleoka`).
func runAPI(cfg *Config, routerName string, apiArgs []string) {
var target *Router
for i := range cfg.Routers {
if cfg.Routers[i].Name == routerName {
r := cfg.Routers[i]
target = &r
break
}
}
target := findRouter(cfg, routerName)
if target == nil {
log.Fatalf("no router named %q in config", routerName)
}
@ -324,6 +328,130 @@ func runAPI(cfg *Config, routerName string, apiArgs []string) {
}
}
// runSchema introspects a MikroTik API path on a single router and shows
// what parameter names exist in the wild. ROS7 keeps shuffling property
// names between point releases (address-families → afi, type=blackhole
// → blackhole flag, etc.), and the live router + the .rsc exports are
// the only authoritative reference. Two sources, in order:
//
// 1. Live API: union of property keys observed across all rows under
// <path>/print, with one example value per key. Falls back to /get
// for singletons (/system/identity, /ip/dns, etc.).
//
// 2. Local .rsc exports: any block whose first line is the matching
// ROS-script path (e.g. `/routing bgp connection` for input
// `/routing/bgp/connection`), with the next several non-blank lines
// so the user can see actual `add ...` invocations.
//
// Trailing /add /set /remove /print /get on the input path are stripped
// — typing `mikrotik-tool schema verona /routing/bgp/connection/add` is
// the natural reflex when you've just hit "unknown parameter" on an add.
func runSchema(cfg *Config, routerName, path string) {
target := findRouter(cfg, routerName)
if target == nil {
log.Fatalf("no router named %q in config", routerName)
}
r := cfg.resolve(*target)
norm := strings.TrimPrefix(path, "/")
norm = strings.Trim(norm, "/")
for _, suffix := range []string{"/add", "/set", "/remove", "/print", "/get", "/getall"} {
norm = strings.TrimSuffix(norm, suffix)
}
apiPath := "/" + norm
fmt.Printf("=== schema: %s on %s ===\n", apiPath, r.Name)
c, err := dialAPI(r)
if err != nil {
log.Fatalf("[%s] %v", r.Name, err)
}
defer c.Close()
keys := map[string]string{}
source := ""
if rep, err := c.RunArgs([]string{apiPath + "/print"}); err == nil && len(rep.Re) > 0 {
source = fmt.Sprintf("union of keys across %d existing item(s)", len(rep.Re))
for _, row := range rep.Re {
for k, v := range row.Map {
if _, exists := keys[k]; !exists {
keys[k] = v
}
}
}
} else if rep, err := c.RunArgs([]string{apiPath + "/get"}); err == nil && len(rep.Re) > 0 {
source = "singleton (/get)"
for _, row := range rep.Re {
for k, v := range row.Map {
keys[k] = v
}
}
}
if len(keys) == 0 {
fmt.Printf("\n# live api: no rows visible at %s\n", apiPath)
} else {
fmt.Printf("\n# live api: %s\n", source)
var names []string
for k := range keys {
names = append(names, k)
}
sort.Strings(names)
for _, k := range names {
example := keys[k]
if len(example) > 60 {
example = example[:60] + "…"
}
fmt.Printf(" %-32s e.g. %s\n", k, example)
}
}
rscPath := "/" + strings.ReplaceAll(norm, "/", " ")
fmt.Printf("\n# .rsc examples (matching `%s`):\n", rscPath)
rscFiles, _ := filepath.Glob("*.rsc")
sort.Strings(rscFiles)
found := 0
const maxExamples = 6
const maxLinesPerExample = 12
for _, f := range rscFiles {
if found >= maxExamples {
break
}
data, err := os.ReadFile(f)
if err != nil {
continue
}
lines := strings.Split(string(data), "\n")
for i, line := range lines {
if found >= maxExamples {
break
}
if strings.TrimSpace(line) != rscPath {
continue
}
fmt.Printf("\n [%s:%d]\n", f, i+1)
for j := 1; j < maxLinesPerExample && i+j < len(lines); j++ {
next := lines[i+j]
trimmed := strings.TrimSpace(next)
if strings.HasPrefix(trimmed, "/") {
break
}
if trimmed == "" {
break
}
fmt.Printf(" %s\n", strings.TrimRight(next, "\r"))
}
found++
}
}
if found == 0 {
fmt.Println(" (no matches in local .rsc files)")
} else if found >= maxExamples {
fmt.Printf("\n (truncated at %d examples)\n", maxExamples)
}
}
func runList(cfg *Config) {
for _, r := range cfg.Routers {
r2 := cfg.resolve(r)
@ -339,7 +467,12 @@ commands:
export ssh to each router, run "/export", save stdout to <name>.rsc locally
inventory discover access points, backhaul radios, and tower switches across
every router (skipping customer equipment) and re-render
inventory.yaml in place`)
inventory.yaml in place
api run an arbitrary API command on one router
(e.g. mikrotik-tool api verona /ip/route/print)
schema show parameter names accepted under an API path on one router,
plus matching examples from local .rsc exports
(e.g. mikrotik-tool schema verona /routing/bgp/connection)`)
os.Exit(2)
}
@ -388,6 +521,12 @@ func main() {
os.Exit(2)
}
runAPI(cfg, args[1], args[2:])
case "schema":
if len(args) < 3 {
fmt.Fprintln(os.Stderr, "usage: mikrotik-tool schema <router> <api-path>")
os.Exit(2)
}
runSchema(cfg, args[1], args[2])
default:
fmt.Fprintf(os.Stderr, "unknown command: %s\n", args[0])
usage()

Binary file not shown.

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = 5HTF-YFWV
#
# model = CCR1009-7G-1C-1S+

View file

@ -118,20 +118,22 @@ add chain=forward action=drop
# -----------------------------------------------------------------------------
# APPLY — iBGP to edge over v4 transport, carrying v6 NLRI
# -----------------------------------------------------------------------------
# ROS 7.21.4 syntax notes (verified live on verona 2026-05-09):
# - parameter is `afi=ip,ipv6` NOT `address-families=...`
# - need a `/routing bgp instance` to reference (carries the local AS)
# - `templates=default` ties it to the existing /routing/bgp/template
# Output filter: only advertise verona+altoga /44 aggregates over this session.
/routing filter rule
add chain=v6-ibgp-out disabled=no rule="if (dst==2606:1c80:1000::/44 || dst==2606:1c80:1500::/44) { accept; } else { reject; }"
/routing bgp instance
add name=bgp-instance-1 as=393837 router-id=10.254.254.101
/routing bgp connection
add name=ibgp-edge-v6 \
remote.address=10.254.254.254 \
remote.as=393837 \
local.address=10.254.254.101 \
local.role=ibgp \
address-families=ipv6 \
multihop=yes \
output.filter-chain=v6-ibgp-out \
nexthop-choice=force-self \
add name=ibgp-edge-v6 instance=bgp-instance-1 templates=default \
afi=ip,ipv6 local.role=ibgp local.address=10.254.254.101 \
remote.address=10.254.254.254 remote.as=393837 multihop=yes \
nexthop-choice=force-self output.filter-chain=v6-ibgp-out \
comment="iBGP to edge, v4 transport / v6 NLRI"
# -----------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
# 2026-05-09 08:51:42 by RouterOS 7.21.4
# 2026-05-09 09:00:22 by RouterOS 7.21.4
# software id = Y1CT-1WB1
#
# model = CCR2004-16G-2S+
@ -425,6 +425,8 @@ set ether15_wave_n queue=FQ_Codel
set ether16 queue=FQ_Codel
set sfp-sfpplus1-verona-tower-switch queue=FQ_Codel
set sfp-sfpplus2-switch queue=FQ_Codel
/routing bgp instance
add as=393837 name=bgp-instance-1 router-id=10.254.254.101
/routing bgp template
set default disabled=no output.network=bgp-networks
/routing id
@ -974,6 +976,11 @@ add address=204.110.191.2 disabled=yes require-message-auth=no service=\
set accept=yes
/routing bfd configuration
add disabled=no interfaces=all min-rx=200ms min-tx=200ms multiplier=5
/routing bgp connection
add afi=ip,ipv6 comment="iBGP to edge, v4 transport / v6 NLRI" instance=\
bgp-instance-1 local.address=10.254.254.101 .role=ibgp multihop=yes name=\
ibgp-edge-v6 nexthop-choice=force-self output.filter-chain=v6-ibgp-out \
remote.address=10.254.254.254 .as=393837 templates=default
/routing filter rule
add chain=ospf-in disabled=no rule="accept;"
add chain=ospf-out disabled=no rule="accept;"