BGP is the feature that justified rewriting RouterOS routing from scratch. The v6 implementation was single-threaded and infamous for it: a full table on a CCR meant minutes of convergence while one CPU core melted and thirty-five others watched. MikroTik’s answer in v7 wasn’t a patch — it was a new routing process with a new configuration model to match.
The model change is blunt: /routing bgp peer no longer exists. Configuration now lives in templates (reusable parameter sets) and connections (the actual sessions). Networks aren’t announced from a network menu anymore — that’s gone too, replaced by output.network pointing at a firewall address-list. If you try to type your v6 muscle memory into a v7 box, nothing autocompletes, and that’s the point.
This article builds eBGP and iBGP the v7 way, covers the parameters that actually matter — roles, multihop, prefix limits — and explains why the new stack finally makes MikroTik a serious BGP platform. Filtering gets the next article to itself; here I’ll wire the hooks and leave them loaded.
Instances, Templates and Connections
Recent 7.x releases settled the object model into three layers. An instance is your BGP identity — AS number and router ID — and every session belongs to one. A template is an optional bag of shared session parameters (address families, filter chains) for keeping multi-peer configs DRY. A connection is one BGP session, referencing the instance and optionally inheriting a template.
# The identity — this is where the router ID lives in current v7/routing bgp instance add name=as65500 as=65500 router-id=10.255.0.1
# Optional shared parameters for sessions/routing bgp template add name=defaults afi=ipafi= takes ip (IPv4 unicast), ipv6, and the VPN families. Note it’s ip, not ipv4 — a small trap for people arriving from other vendors; in older 7.x this parameter was spelled address-families, so expect both spellings in forum posts. Sessions negotiate only the families both ends configure.
Pin router-id to your loopback address on the instance and be done with it — a router ID that floats with whatever address is up is a subtle way to reset every session when a WAN flaps.
eBGP to an Upstream
AS 65500, single upstream at AS 64600, announcing 203.0.113.0/24:
# 1. What we announce: an address-list, not a network statement/ip firewall address-list add list=bgp-networks address=203.0.113.0/24
# 2. A route for it must exist (BGP won't announce what isn't routed)/ip route add dst-address=203.0.113.0/24 blackhole comment="BGP anchor"
# 3. The session/routing bgp connection add name=upstream1 instance=as65500 templates=defaults \ remote.address=198.51.100.1 remote.as=64600 local.role=ebgp \ output.network=bgp-networksThree things replaced the v6 network statement here. The address-list (output.network=bgp-networks) defines candidate prefixes; the blackhole anchor route makes each prefix valid to announce (exactly the same discipline as on any other vendor — announce only what you can route); and the connection ties them together. Add a prefix to the list, make sure it’s routed, and it’s announced. It’s more explicit than v6 and much harder to fat-finger into announcing a /8.
local.role=ebgp isn’t decoration. Roles (ebgp, ebgp-customer, ebgp-provider, ebgp-peer, ebgp-rs, ibgp, ibgp-rr, …) tell the stack what kind of relationship this is — and the RFC 9234-style roles enable leak prevention semantics on top. At minimum, ebgp vs ibgp decides AS-path behavior, next-hop handling, and multihop defaults. Set it correctly on every connection.
Do not bring this session up without filters. An eBGP session with no input.filter accepts everything the peer sends — including a full table or a leak of someone else’s routes. I said it in the VyOS BGP article and it’s just as true here: filters are not optional. The hooks look like this, and the next article fills the chains in:
/routing bgp connection set upstream1 \ input.filter=upstream-in output.filter-chain=upstream-outPrefix Limits: Your Blast Shield
The v7 spelling of max-prefix is input.limit-process-routes-ipv4 (and -ipv6):
# Upstream sends default-only? Cap it hard./routing bgp connection set upstream1 input.limit-process-routes-ipv4=10
# Full-table peer (~1M IPv4 routes in 2026): cap with headroom/routing bgp connection set upstream1 input.limit-process-routes-ipv4=1200000Semantics differ from Cisco-style max-prefix, so read carefully: when the limit is hit, RouterOS stops processing further routes and flags the session — it does not tear the session down. Recovery is manual: after fixing the cause, clear the session:
/routing bgp session print/routing bgp session clear [find name~"upstream1"]The limit is per-address-family and counts received routes, not installed ones. It’s a blast shield, not a substitute for input filtering — a peer can still send you 9 garbage routes under a limit of 10.
iBGP
iBGP in v7 is the same objects with local.role=ibgp and the usual iBGP disciplines: peer between loopbacks, and remember iBGP doesn’t rewrite next-hop.
# Loopback peering — survives any single link failure if the IGP has a path/routing bgp connection add name=rr1 instance=as65500 \ local.address=10.255.0.1 local.role=ibgp \ remote.address=10.255.0.2 remote.as=65500 \ multihop=yes nexthop-choice=force-selflocal.address= is v7’s update-source. multihop=yes is required for loopback iBGP — eBGP defaults to TTL 1 semantics and loopback-to-loopback is more than one hop; the same flag serves eBGP-multihop setups (route servers, providers peering from a distant router). nexthop-choice=force-self is next-hop-self: without it, routes learned from your upstream get advertised to iBGP neighbors with an external next-hop they can’t resolve, and the routes stay inactive on the far end.
Full mesh scales as N(N-1)/2, so past a handful of routers make one or two boxes route reflectors — that’s just local.role=ibgp-rr on the reflector’s connections toward its clients, ibgp on the clients. No separate cluster configuration for the basic case.
For session security on eBGP, tcp-md5-key= gives you RFC 2385 TCP MD5 if the other side requires it, and use-bfd=yes gets you sub-second failure detection instead of waiting out the hold timer.
Verification
The session view is the first stop:
/routing bgp session print# name="upstream1-1" remote.address=198.51.100.1 remote.as=64600# local.role=ebgp uptime=2h3m ...Note sessions are dynamic objects created from connections — a connection that never produces a session means TCP 179 isn’t completing (firewall, wrong address, no route to peer).
What did they send us, and what did we install?
# Everything BGP knows, including filtered-out routes/routing route print where bgp
# What actually made the FIB/ip route print where bgpWhat are we announcing? This one has a v7 quirk: to inspect sent advertisements after the fact, the session must store them, which costs memory and is off by default:
/routing bgp connection set upstream1 output.keep-sent-attributes=yes/routing bgp session print/routing bgp session dump-saved-advertisements [find name~"upstream1"]# writes the current Adj-RIB-Out to a file for inspectionTurn keep-sent-attributes on while you’re building or debugging, off on memory-constrained boxes in steady state. For quick checks, /routing bgp advertisements print shows the current outgoing updates without the dump machinery.
Why v7 BGP Finally Scales
The v6 routing process was a single-threaded monolith: one core did best-path for every peer, every update, every reconvergence. The v7 routing stack is a ground-up rewrite that spreads work across cores — sessions, filtering, and route processing no longer serialize behind one CPU.
In practice, on multi-core hardware (CCR2004/CCR2116/CCR2216 class), that’s the difference between a full IPv4+IPv6 table converging in minutes and converging in seconds, and between “touching a filter reloads the world” and incremental updates. Add the honest config model — explicit address families, roles, per-AFI limits — and v7 is the first RouterOS you can defend running at an IXP or as a multi-homed edge without a stack of caveats. RAM still matters: budget roughly a few hundred MB per full-table peer with attributes retained, which rules out the 256 MB boxes for full tables — take a default plus longer-than-/22s instead on those.
What v7 BGP is not is finished in every corner: exotic knobs from big-iron vendors (per-neighbor ORF, some add-path modes) are still absent or young. For transit, peering, and iBGP cores, it’s solid.
Closing Thoughts
The v7 checklist:
- Instance for identity (
as,router-id), optional template for shared parameters (afi=ip), connections for sessions. output.networkaddress-list + anchor route replaces the network statement.local.roleon every connection;multihop=yesandlocal.addressfor loopback peering;nexthop-choice=force-selftoward iBGP.input.limit-process-routes-ipv4on every eBGP session — and remember it flags, it doesn’t tear down;session clearto recover.keep-sent-attributeswhen debugging announcements.
Everything here assumed the filter chains exist. They don’t yet — and an unfiltered BGP session is an outage on a timer. Next article: the v7 routing filter language, where those upstream-in and upstream-out chains get built properly.