Skip to content

BGP Peering: eBGP and iBGP Configuration

This guide covers RouterOS 7 BGP configuration: establishing eBGP and iBGP peering sessions, advertising and filtering routes, and influencing path selection with BGP attributes.

RouterOS 7 replaces the v6 flat /routing bgp peer model with a three-object design: template (protocol parameters and policy), connection (transport endpoint), and session (runtime state). All examples on this page use RouterOS 7 syntax.

BGP (Border Gateway Protocol) is a path-vector protocol designed for inter-domain routing between autonomous systems (ASes). Unlike IGPs (OSPF, IS-IS), BGP is policy-driven: which routes to accept, which to advertise, and which path to prefer are all explicitly controlled.

Use BGP when:

  • Connecting to one or more ISPs (multihoming)
  • Operating as a transit or peering AS
  • Exchanging routes between internal network segments with distinct policies

Do not use BGP when static routes or an IGP (OSPF, RIP) are sufficient. BGP has high configuration overhead and requires careful policy design to avoid routing loops and path leaks.

eBGPiBGP
ASN relationshipDifferent ASesSame AS
AS_PATH handlingPrepends own AS on sendDoes not modify AS_PATH
Next-hop behaviorNext-hop set to self by defaultNext-hop preserved (requires IGP reachability)
Route propagationFreely propagated to any peerNot re-advertised between iBGP peers (split-horizon)
TTL default1 (direct link)255

iBGP split-horizon means routes learned from one iBGP peer are not forwarded to another iBGP peer. This requires either a full-mesh of iBGP sessions or a route reflector design.

  • RouterOS 7.x with the routing package installed (included by default on most images; check /system/package/print)
  • Each BGP router requires a unique router-id (typically a loopback address)
  • eBGP peers must be directly reachable at the configured remote.address (or multihop configured for indirect peers)
  • For iBGP, all routers need IGP reachability to peer loopback addresses

RouterOS 7 BGP uses three objects:

ObjectMenuPurpose
Template/routing/bgp/templateProtocol defaults: AS number, router-id, timers, filters, redistribution
Connection/routing/bgp/connectionPer-peer transport: remote address, role, template binding
Session/routing/bgp/sessionRuntime state (read-only): established prefixes, uptime, state

A template defines shared behavior. A connection references a template and adds the peer-specific transport details. Multiple connections can share one template.

# View runtime session state
/routing bgp session print
/routing bgp session print detail

# Step 1: Create a template with your AS number and router-id
/routing bgp template
add name=default as=65001 router-id=192.0.2.1
# Step 2: Create a connection for the eBGP peer
/routing bgp connection
add name=to-isp \
remote.address=203.0.113.1 \
remote.as=64500 \
local.role=ebgp \
templates=default

local.role=ebgp is required for eBGP connections. RouterOS uses the role to apply correct AS_PATH and next-hop rules.

Routes are not advertised automatically. Enable redistribution on the template and attach an output filter chain:

# Enable redistribution of connected and static routes
/routing bgp template
set default output.redistribute=connected,static
# Output filter: advertise only your assigned prefix
/routing filter rule
add chain=bgp-out rule="if (dst == 198.51.100.0/24) { accept }"
add chain=bgp-out rule="reject"
# Attach filter to the connection
/routing bgp connection
set to-isp output.filter-chain=bgp-out

The filter chain is evaluated top-to-bottom. Routes not matched by any accept rule are rejected. The final explicit reject rule documents intent but is redundant since unmatched routes are rejected by default.

Always filter inbound routes to prevent route leaks:

# Accept only default route and reject everything else
/routing filter rule
add chain=bgp-in rule="if (dst == 0.0.0.0/0) { accept }"
add chain=bgp-in rule="reject"
/routing bgp connection
set to-isp input.filter-chain=bgp-in

Use TCP MD5 to authenticate BGP sessions:

/routing bgp connection
set to-isp tcp-md5-key="secretpassword"

Both sides must configure the same key.

When the eBGP peer is not directly connected (e.g., peering over a loopback or through intermediate hops), increase the TTL:

/routing bgp connection
set to-isp multihop=yes

Ensure the remote peer address is reachable via a static route or IGP.

A passive connection does not initiate the TCP session — it only accepts incoming connections:

/routing bgp connection
set to-isp passive=yes

Use passive mode when the remote peer always initiates, or to prevent TCP collisions on simultaneous open.


iBGP requires that every router receive all BGP routes. The simplest design is a full mesh: every iBGP router sessions to every other. With n routers this creates n(n-1)/2 sessions — practical only for small networks (3–5 routers).

# On router R1 (AS 65000, router-id 10.255.0.1)
/routing bgp template
add name=ibgp-default as=65000 router-id=10.255.0.1
/routing bgp connection
add name=to-r2 remote.address=10.255.0.2 remote.as=65000 \
local.role=ibgp templates=ibgp-default
add name=to-r3 remote.address=10.255.0.3 remote.as=65000 \
local.role=ibgp templates=ibgp-default

The same AS number is used for all iBGP connections. Peers use loopback addresses for session stability (the session survives as long as the loopback is reachable via IGP, regardless of which physical link is used).

When eBGP-learned routes are propagated to iBGP peers, the next-hop is the external peer address. If iBGP clients do not have a route to the external next-hop, force the router to set itself as next-hop:

/routing bgp connection
set to-r2 nexthop-choice=force-self
set to-r3 nexthop-choice=force-self

Alternatively, redistribute the external next-hop addresses via IGP so all iBGP routers can resolve them without next-hop rewriting.

Route reflectors (RR) eliminate the full-mesh requirement. A route reflector re-advertises iBGP-learned routes to its clients. Clients only need to session with the RR, not with each other.

[R1] ─── [RR] ─── [R2]
[R3]

RR and clients are in the same AS. The RR sessions with all clients; clients session only with the RR.

# On the Route Reflector (RR)
/routing bgp template
add name=rr-template as=65000 router-id=10.255.0.254
# Session to each client: local.role=ibgp-rr
/routing bgp connection
add name=to-client1 remote.address=10.255.0.1 remote.as=65000 \
local.role=ibgp-rr templates=rr-template
add name=to-client2 remote.address=10.255.0.2 remote.as=65000 \
local.role=ibgp-rr templates=rr-template
add name=to-client3 remote.address=10.255.0.3 remote.as=65000 \
local.role=ibgp-rr templates=rr-template
# On each RR Client
/routing bgp template
add name=client-template as=65000 router-id=10.255.0.1
# Session only to the RR: local.role=ibgp-rr-client
/routing bgp connection
add name=to-rr remote.address=10.255.0.254 remote.as=65000 \
local.role=ibgp-rr-client templates=client-template

The RR automatically adds ORIGINATOR_ID and CLUSTER_LIST attributes to reflected routes to prevent loops.

Deploy two RRs per cluster for redundancy. Both RRs should use the same cluster-id so clients see them as equivalent:

# On both RR1 and RR2
/routing bgp template
set rr-template cluster-id=10.255.0.0

Clients session with both RRs. Each RR reflects independently; clients install routes from whichever RR provides the best path.


/routing bgp template
set default output.redistribute=connected,static

Supported output.redistribute values: connected, static, rip, ospf, ospf-ext1, ospf-ext2, bgp.

Always combine redistribution with an output filter chain to prevent advertising unwanted prefixes.

Selective Advertisement with Output Filters

Section titled “Selective Advertisement with Output Filters”
# Advertise only specific prefixes
/routing filter rule
add chain=bgp-out rule="if (dst == 192.0.2.0/24) { accept }"
add chain=bgp-out rule="if (dst == 192.0.2.128/25) { accept }"
add chain=bgp-out rule="reject"
/routing bgp connection
set to-isp output.filter-chain=bgp-out

To accept a block of prefixes with a length constraint (e.g., customer /24s within a /22):

/routing filter rule
# Accept /24s within 203.0.113.0/22, reject more-specifics and summaries
add chain=bgp-out rule="if (dst in 203.0.113.0/22 && dst-len == 24) { accept }"
add chain=bgp-out rule="reject"

Reject routes from specific ASes or with specific AS_PATH patterns:

/routing filter rule
# Reject anything with AS 64496 in the path (customer route leak prevention)
add chain=bgp-in rule="if (bgp-as-path .= \".*64496.*\") { reject }"
# Accept all other routes
add chain=bgp-in rule="accept"

RouterOS 7 selects the best BGP path in this order (first difference wins):

StepCriterionPrefer
1Local Preference (bgp-local-pref)Higher
2AS-PATH lengthShorter
3Origin codeIGP > EGP > Incomplete
4MEDLower
5eBGP over iBGPeBGP
6IGP distance to next-hopLower
7Router-ID of advertising peerLower
8Cluster-list lengthShorter
9Peer IP addressLower

RouterOS does not implement Cisco-style per-neighbor weight. Use local-pref or per-connection filters instead.

Local Preference influences path selection within your AS. Higher is preferred. Set it on inbound eBGP routes:

# Prefer ISP-A (local-pref 200) over ISP-B (local-pref 100)
/routing filter rule
add chain=bgp-in-isp-a rule="accept; set bgp-local-pref 200"
add chain=bgp-in-isp-b rule="accept; set bgp-local-pref 100"
/routing bgp connection
set to-isp-a input.filter-chain=bgp-in-isp-a
set to-isp-b input.filter-chain=bgp-in-isp-b

Local Preference is propagated to all iBGP peers. It is not sent to eBGP neighbors.

MED influences how external peers choose between your entry points. Lower MED is preferred. Set it on outbound announcements:

# Prefer traffic entering via this router for 198.51.100.0/24
/routing filter rule
add chain=bgp-out rule="if (dst == 198.51.100.0/24) { set bgp-med 10; accept }"
add chain=bgp-out rule="reject"

MED is only compared between routes from the same neighboring AS unless the peer’s BGP implementation is configured otherwise.

Prepend your AS number multiple times on outbound announcements to make a path appear longer and therefore less preferred by external networks:

# Make traffic prefer the other link for 198.51.100.0/24
/routing filter rule
add chain=bgp-out-secondary rule="if (dst == 198.51.100.0/24) { \
set bgp-path-prepend 3; accept }"
add chain=bgp-out-secondary rule="reject"
/routing bgp connection
set to-isp-secondary output.filter-chain=bgp-out-secondary

set bgp-path-prepend 3 prepends your AS three times.

Communities are tags attached to routes. Use them to implement policy signaling between peers:

# Tag outbound routes with a standard community
/routing filter rule
add chain=bgp-out rule="if (dst == 198.51.100.0/24) { \
append bgp-communities 65000:100; accept }"
# Match incoming community and set local-pref
/routing filter rule
add chain=bgp-in rule="if (bgp-communities includes 65010:200) { \
set bgp-local-pref 250; accept }"
add chain=bgp-in rule="accept"

RouterOS 7 supports standard communities (65000:100), extended communities, and large communities (65000:1:100).


This example shows a router with two eBGP upstreams and iBGP to a peer router, applying preference policy and advertising an aggregate prefix.

ISP-A (AS64500) ISP-B (AS64501)
203.0.113.1 203.0.113.5
│ │
ether1 .2 ether2 .6
┌─────────────────────────┐
│ edge-router │
│ router-id 10.255.0.1 │
│ AS 65000 │
└──────────┬──────────────┘
ether3 10.255.0.1
│ (iBGP to core)
[core-router 10.255.0.2]
# Template
/routing bgp template
add name=edge as=65000 router-id=10.255.0.1 \
output.redistribute=connected,static
# eBGP connections
/routing bgp connection
add name=to-isp-a remote.address=203.0.113.1 remote.as=64500 \
local.role=ebgp templates=edge \
input.filter-chain=bgp-in-isp-a output.filter-chain=bgp-out
add name=to-isp-b remote.address=203.0.113.5 remote.as=64501 \
local.role=ebgp templates=edge \
input.filter-chain=bgp-in-isp-b output.filter-chain=bgp-out
# iBGP to core router (next-hop-self so core can resolve external next-hops)
/routing bgp connection
add name=to-core remote.address=10.255.0.2 remote.as=65000 \
local.role=ibgp templates=edge \
nexthop-choice=force-self
# Outbound: advertise only our /24 aggregate
/routing filter rule
add chain=bgp-out rule="if (dst == 198.51.100.0/24) { accept }"
add chain=bgp-out rule="reject"
# Inbound from ISP-A: prefer (local-pref 200)
/routing filter rule
add chain=bgp-in-isp-a rule="if (dst == 0.0.0.0/0) { set bgp-local-pref 200; accept }"
add chain=bgp-in-isp-a rule="reject"
# Inbound from ISP-B: fallback (local-pref 100)
/routing filter rule
add chain=bgp-in-isp-b rule="if (dst == 0.0.0.0/0) { set bgp-local-pref 100; accept }"
add chain=bgp-in-isp-b rule="reject"

# View all BGP sessions and their current state
/routing bgp session print
# Detail view: shows uptime, prefixes received/advertised, hold-time
/routing bgp session print detail

BGP session states progress through: Idle → Connect → Active → OpenSent → OpenConfirm → Established

StateMeaning
IdleBGP is not attempting to connect (disabled or waiting)
ConnectTCP connection attempt in progress
ActiveTCP failed; retrying. Usually: wrong peer address, firewall blocking TCP/179, or peer not listening
OpenSentTCP established, BGP OPEN sent, waiting for peer OPEN
OpenConfirmOPEN received, exchanging KEEPALIVEs
EstablishedSession up and routes exchanged

A session stuck in Active indicates TCP is not completing. Check:

# Verify the peer address and AS number are correct
/routing bgp connection print detail
# Confirm TCP/179 is not blocked
/ip firewall filter print where dst-port=179 or src-port=179
# Test reachability to peer
/tool/ping 203.0.113.1

For multihop eBGP, verify a route exists to the peer address and multihop=yes is set.

# Show routes received from a specific peer
/routing bgp advertisements print where session=to-isp
# Show all BGP routes in the routing table
/ip route print where bgp~"."
# Show BGP routes not installed (e.g. suboptimal or filtered)
/routing bgp session print detail

Check the prefix-count fields in session detail — output-prefixes shows advertised, input-prefixes shows received.

A BGP route may be received but not installed in the routing table when:

  1. A better route exists — check if a static or connected route covers the same prefix with a lower distance
  2. Output filter rejected it — verify the filter chain with /routing filter rule print where chain=<name>
  3. BGP distance is too high — BGP administrative distance is 20 (eBGP) or 200 (iBGP) by default
  4. next-hop unresolvable — the next-hop IP is not reachable; check IGP or add a static route
# Check if a prefix is present in BGP table
/routing bgp advertisements print where session=to-isp prefix~"198.51.100"
# Check the routing table for the prefix
/ip route print where dst-address~"198.51.100"

If output-prefixes is 0 after establishing a session:

  1. Verify output.redistribute is set on the template
  2. Check the output filter chain is attached and passes the intended routes
  3. Confirm the routes exist in the routing table (/ip route print)
  4. Temporarily remove the output filter to confirm redistribution is working:
/routing bgp connection set to-isp output.filter-chain=""
# Check output-prefixes in session detail
/routing bgp session print detail
# Re-attach filter after testing
/routing bgp connection set to-isp output.filter-chain=bgp-out

  • OSPF Configuration — Redistributing OSPF routes into BGP and vice versa
  • OSPF — OSPF fundamentals for building the IGP underlay required by iBGP
  • Route Filters — Complete routing filter rule syntax, matchers, and actions
  • WireGuard VPN — Running BGP over VPN tunnels for site interconnects