Spaces:
Sleeping
Sleeping
Commit ·
491f25a
0
Parent(s):
BGP RAG cloud chatbot — initial commit
Browse files- .gitignore +0 -0
- README.md +154 -0
- app.py +188 -0
- data/docs/bgp_configuration_guide.txt +258 -0
- data/docs/bgp_error_messages.txt +223 -0
- data/docs/bgp_show_commands.txt +178 -0
- data/docs/bgp_states_guide.txt +143 -0
- data/docs/bgp_troubleshooting_guide.txt +205 -0
- data/telemetry/bgp_telemetry_logs.txt +187 -0
- ingest.py +123 -0
- rag_chain.py +203 -0
- requirements.txt +34 -0
.gitignore
ADDED
|
Binary file (90 Bytes). View file
|
|
|
README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BGP Troubleshooting RAG Chatbot — Cloud Deployment
|
| 2 |
+
|
| 3 |
+
Domain-specific RAG chatbot for Cisco BGP troubleshooting, deployed on HuggingFace Spaces with Groq cloud LLM inference. No local setup required — visit the URL and start asking questions.
|
| 4 |
+
|
| 5 |
+
🔗 **Live Demo:** [huggingface.co/spaces/VP21/bgp-rag-groq](https://huggingface.co/spaces/VP21/bgp-rag-groq)
|
| 6 |
+
📁 **Local Version (nettune):** [github.com/vanip3/bgp-rag-chatbot](https://github.com/vanip3/bgp-rag-chatbot)
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
## Architecture
|
| 11 |
+
|
| 12 |
+
```
|
| 13 |
+
User (Browser)
|
| 14 |
+
│
|
| 15 |
+
▼
|
| 16 |
+
HuggingFace Spaces
|
| 17 |
+
(Streamlit App — app.py)
|
| 18 |
+
│
|
| 19 |
+
├──► FAISS Vector Store ◄── HuggingFace Embeddings
|
| 20 |
+
│ (Pre-built index, (all-MiniLM-L6-v2)
|
| 21 |
+
│ committed to repo)
|
| 22 |
+
│
|
| 23 |
+
├──► Top-4 Relevant Chunks
|
| 24 |
+
│
|
| 25 |
+
▼
|
| 26 |
+
Groq Cloud API
|
| 27 |
+
(llama-3.1-8b-instant)
|
| 28 |
+
│
|
| 29 |
+
▼
|
| 30 |
+
Answer + Source Documents
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
The user's question is embedded locally using `all-MiniLM-L6-v2`, compared against the pre-built FAISS index to retrieve the 4 most relevant document chunks, then passed to Llama 3.1 8B via the Groq API for answer generation. Source attribution shows which documents informed each answer.
|
| 34 |
+
|
| 35 |
+
---
|
| 36 |
+
|
| 37 |
+
## Local vs Cloud Version Comparison
|
| 38 |
+
|
| 39 |
+
| | Local (Project 2) | Cloud (This Project) |
|
| 40 |
+
|------------------|---------------------------------|------------------------------|
|
| 41 |
+
| **LLM** | nettune (fine-tuned, Ollama) | Llama 3.1 8B (Groq API) |
|
| 42 |
+
| **Embeddings** | all-MiniLM-L6-v2 | all-MiniLM-L6-v2 |
|
| 43 |
+
| **Vector Store** | FAISS (built at runtime) | FAISS (pre-built index) |
|
| 44 |
+
| **Access** | Local only | Public URL |
|
| 45 |
+
| **Cost** | Free (local GPU/CPU) | Free (Groq free tier) |
|
| 46 |
+
| **Setup needed** | Ollama + model download | None — visit URL |
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
## Key Concepts Demonstrated
|
| 51 |
+
|
| 52 |
+
**RAG pipeline cloud deployment** — the same retrieval-augmented generation pattern from the local version runs on a public URL with zero infrastructure management. HuggingFace Spaces handles the server, networking, and TLS.
|
| 53 |
+
|
| 54 |
+
**Secure API key management** — `GROQ_API_KEY` is stored in HF Spaces Secrets (encrypted at rest, injected as an environment variable at runtime). It never appears in code or git history. This is the same pattern used in AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault.
|
| 55 |
+
|
| 56 |
+
**Pre-built vector index strategy** — the FAISS index is built once locally (`python ingest.py`) and committed to the repo as binary files (`faiss_index/index.faiss`, `faiss_index/index.pkl`). The Space loads these files in ~3 seconds instead of spending 3-5 minutes building the index on every cold start — a critical optimization for serverless deployments with CPU limits.
|
| 57 |
+
|
| 58 |
+
**Cloud LLM inference via Groq API** — Groq's LPU (Language Processing Unit) hardware delivers ~500 tokens/second on Llama 3.1 8B, free tier, no credit card required. The API is OpenAI-compatible, making it a drop-in for any LangChain LLM component.
|
| 59 |
+
|
| 60 |
+
**Production Streamlit deployment** — explicit API key validation at startup, graceful error messaging for operators who fork without setting secrets, persistent chat history via `st.session_state`, and source document attribution on every response.
|
| 61 |
+
|
| 62 |
+
---
|
| 63 |
+
|
| 64 |
+
## Knowledge Base
|
| 65 |
+
|
| 66 |
+
Six documents indexed from Cisco BGP documentation and production telemetry:
|
| 67 |
+
|
| 68 |
+
| File | Content |
|
| 69 |
+
|------|---------|
|
| 70 |
+
| `bgp_states_guide.txt` | BGP FSM states (IDLE → ESTABLISHED), causes, and verification commands |
|
| 71 |
+
| `bgp_troubleshooting_guide.txt` | Systematic methodology for session failures, flapping, route issues |
|
| 72 |
+
| `bgp_show_commands.txt` | Complete `show` command reference with output interpretation |
|
| 73 |
+
| `bgp_error_messages.txt` | Syslog message reference with NOTIFICATION error codes and remediation |
|
| 74 |
+
| `bgp_configuration_guide.txt` | iBGP, Route Reflectors, authentication, filtering, timers |
|
| 75 |
+
| `bgp_telemetry_logs.txt` | 30-day production syslog data with incident analysis |
|
| 76 |
+
|
| 77 |
+
---
|
| 78 |
+
|
| 79 |
+
## How to Deploy Your Own Copy
|
| 80 |
+
|
| 81 |
+
1. Fork this repo (or create a new HuggingFace Space and push directly)
|
| 82 |
+
2. Create a new HuggingFace Space — select **Streamlit** as the SDK
|
| 83 |
+
3. Push this repo to the Space:
|
| 84 |
+
```bash
|
| 85 |
+
git remote add space https://huggingface.co/spaces/YOUR-USERNAME/YOUR-SPACE-NAME
|
| 86 |
+
git push space main
|
| 87 |
+
```
|
| 88 |
+
4. In Space Settings → **Variables and Secrets**, add:
|
| 89 |
+
- **Name:** `GROQ_API_KEY`
|
| 90 |
+
- **Value:** your key from [console.groq.com](https://console.groq.com)
|
| 91 |
+
5. The Space auto-builds and deploys — your public URL is live in ~2 minutes
|
| 92 |
+
|
| 93 |
+
---
|
| 94 |
+
|
| 95 |
+
## Local Development
|
| 96 |
+
|
| 97 |
+
```bash
|
| 98 |
+
# 1. Clone
|
| 99 |
+
git clone https://github.com/vanip3/bgp-rag-groq
|
| 100 |
+
cd bgp-rag-groq
|
| 101 |
+
|
| 102 |
+
# 2. Install dependencies
|
| 103 |
+
pip install -r requirements.txt
|
| 104 |
+
|
| 105 |
+
# 3. Build FAISS index (one-time)
|
| 106 |
+
python ingest.py
|
| 107 |
+
|
| 108 |
+
# 4. Set API key
|
| 109 |
+
export GROQ_API_KEY=gsk_... # Linux/macOS
|
| 110 |
+
# or: set GROQ_API_KEY=gsk_... # Windows CMD
|
| 111 |
+
|
| 112 |
+
# 5. Run the app
|
| 113 |
+
streamlit run app.py
|
| 114 |
+
```
|
| 115 |
+
|
| 116 |
+
To verify the RAG chain works before launching the UI:
|
| 117 |
+
```bash
|
| 118 |
+
python rag_chain.py
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
---
|
| 122 |
+
|
| 123 |
+
## File Structure
|
| 124 |
+
|
| 125 |
+
```
|
| 126 |
+
bgp-rag-groq/
|
| 127 |
+
├── app.py # Streamlit UI (HF Spaces entry point)
|
| 128 |
+
├── rag_chain.py # RAG chain: Groq LLM + FAISS retrieval
|
| 129 |
+
├── ingest.py # Build FAISS index (run once locally)
|
| 130 |
+
├── requirements.txt # Auto-installed by HF Spaces
|
| 131 |
+
├── data/
|
| 132 |
+
│ ├── docs/
|
| 133 |
+
│ │ ├── bgp_states_guide.txt
|
| 134 |
+
│ │ ├── bgp_troubleshooting_guide.txt
|
| 135 |
+
│ │ ├── bgp_show_commands.txt
|
| 136 |
+
│ │ ├── bgp_error_messages.txt
|
| 137 |
+
│ │ └── bgp_configuration_guide.txt
|
| 138 |
+
│ └── telemetry/
|
| 139 |
+
│ └── bgp_telemetry_logs.txt
|
| 140 |
+
└── faiss_index/ # Pre-built index — committed to repo
|
| 141 |
+
├── index.faiss
|
| 142 |
+
└── index.pkl
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## Tech Stack
|
| 148 |
+
|
| 149 |
+
- **[LangChain](https://langchain.com)** — RAG chain orchestration (`RetrievalQA`, `PromptTemplate`)
|
| 150 |
+
- **[Groq API](https://groq.com)** — Cloud LLM inference (`llama-3.1-8b-instant`, free tier)
|
| 151 |
+
- **[HuggingFace Embeddings](https://huggingface.co)** — `sentence-transformers/all-MiniLM-L6-v2` (local, CPU)
|
| 152 |
+
- **[FAISS](https://github.com/facebookresearch/faiss)** — Vector similarity search (Facebook AI Research)
|
| 153 |
+
- **[Streamlit](https://streamlit.io)** — Web UI (auto-detected by HF Spaces)
|
| 154 |
+
- **[HuggingFace Spaces](https://huggingface.co/spaces)** — Free cloud deployment platform
|
app.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
app.py — BGP Troubleshooting RAG Chatbot (Cloud Edition)
|
| 3 |
+
Deployed on HuggingFace Spaces. Run: streamlit run app.py
|
| 4 |
+
|
| 5 |
+
HuggingFace Spaces auto-detects app.py and runs it as the entry point.
|
| 6 |
+
The GROQ_API_KEY must be set in Space Settings → Variables and Secrets.
|
| 7 |
+
|
| 8 |
+
WHY ERROR HANDLING FOR MISSING API KEY MATTERS:
|
| 9 |
+
In cloud deployments, environment variables are set by operators, not users.
|
| 10 |
+
If someone forks your Space and forgets to add their GROQ_API_KEY, the app
|
| 11 |
+
will crash with an ugly traceback. Explicit error handling with st.error()
|
| 12 |
+
gives them a clear, actionable message instead of a 500 error. This is the
|
| 13 |
+
difference between a hobby script and a production app.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
import os
|
| 17 |
+
from dotenv import load_dotenv
|
| 18 |
+
load_dotenv() # loads .env locally; no-op on HF Spaces (key comes from Secrets instead)
|
| 19 |
+
|
| 20 |
+
import streamlit as st
|
| 21 |
+
from rag_chain import query_bgp, get_chunk_count, get_vectorstore, get_embeddings
|
| 22 |
+
|
| 23 |
+
# ── Page Configuration ────────────────────────────────────────────────────────
|
| 24 |
+
|
| 25 |
+
st.set_page_config(
|
| 26 |
+
page_title="BGP Troubleshooting RAG — Cloud Edition",
|
| 27 |
+
page_icon="🌐",
|
| 28 |
+
layout="wide",
|
| 29 |
+
initial_sidebar_state="expanded",
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
# ── API Key Guard (must be first — stops execution if key missing) ─────────────
|
| 33 |
+
|
| 34 |
+
if not os.environ.get("GROQ_API_KEY"):
|
| 35 |
+
st.error(
|
| 36 |
+
"⚠️ **GROQ_API_KEY not set.**\n\n"
|
| 37 |
+
"To deploy your own copy:\n"
|
| 38 |
+
"1. Go to your HuggingFace Space\n"
|
| 39 |
+
"2. Click **Settings** → **Variables and Secrets**\n"
|
| 40 |
+
"3. Add a new Secret: `GROQ_API_KEY` = your key from [console.groq.com](https://console.groq.com)\n\n"
|
| 41 |
+
"For local development: `export GROQ_API_KEY=gsk_...`"
|
| 42 |
+
)
|
| 43 |
+
st.stop() # Halts rendering — nothing below this runs without the key
|
| 44 |
+
|
| 45 |
+
# ── Session State Initialization ──────────────────────────────────────────────
|
| 46 |
+
|
| 47 |
+
if "messages" not in st.session_state:
|
| 48 |
+
st.session_state.messages = []
|
| 49 |
+
|
| 50 |
+
if "chain_loaded" not in st.session_state:
|
| 51 |
+
st.session_state.chain_loaded = False
|
| 52 |
+
|
| 53 |
+
# ── Example Questions ─────────────────────────────────────────────────────────
|
| 54 |
+
|
| 55 |
+
EXAMPLE_QUESTIONS = [
|
| 56 |
+
"Why is my BGP neighbor stuck in IDLE state?",
|
| 57 |
+
"What does %BGP-5-ADJCHANGE neighbor Down mean?",
|
| 58 |
+
"How do I verify BGP authentication is working?",
|
| 59 |
+
"My BGP session keeps flapping — what should I check?",
|
| 60 |
+
"Based on the telemetry logs, what is the most common failure?",
|
| 61 |
+
]
|
| 62 |
+
|
| 63 |
+
# ── Sidebar ───────────────────────────────────────────────────────────────────
|
| 64 |
+
|
| 65 |
+
with st.sidebar:
|
| 66 |
+
st.title("🌐 BGP RAG Chatbot")
|
| 67 |
+
st.caption("Cloud Edition")
|
| 68 |
+
|
| 69 |
+
# Deployment info
|
| 70 |
+
st.markdown("### 🚀 Deployment")
|
| 71 |
+
st.markdown(
|
| 72 |
+
"""
|
| 73 |
+
| Component | Value |
|
| 74 |
+
|-----------|-------|
|
| 75 |
+
| **LLM** | Groq API — llama-3.1-8b-instant |
|
| 76 |
+
| **Embeddings** | all-MiniLM-L6-v2 (Local) |
|
| 77 |
+
| **Vector DB** | FAISS (Pre-built index) |
|
| 78 |
+
| **Hosted on** | HuggingFace Spaces |
|
| 79 |
+
"""
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
# Knowledge base stats
|
| 83 |
+
st.markdown("### 📚 Knowledge Base")
|
| 84 |
+
chunk_count = get_chunk_count()
|
| 85 |
+
if chunk_count > 0:
|
| 86 |
+
st.success(f"✅ Index loaded — **{chunk_count:,}** chunks")
|
| 87 |
+
else:
|
| 88 |
+
st.warning("⚠️ Index not loaded yet")
|
| 89 |
+
|
| 90 |
+
st.markdown(
|
| 91 |
+
"""
|
| 92 |
+
**Documents indexed:**
|
| 93 |
+
- bgp_states_guide.txt
|
| 94 |
+
- bgp_troubleshooting_guide.txt
|
| 95 |
+
- bgp_show_commands.txt
|
| 96 |
+
- bgp_error_messages.txt
|
| 97 |
+
- bgp_configuration_guide.txt
|
| 98 |
+
- bgp_telemetry_logs.txt
|
| 99 |
+
"""
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
# Example questions
|
| 103 |
+
st.markdown("### 💡 Example Questions")
|
| 104 |
+
st.caption("Click to populate the input")
|
| 105 |
+
|
| 106 |
+
for q in EXAMPLE_QUESTIONS:
|
| 107 |
+
if st.button(q, key=f"example_{q[:20]}", use_container_width=True):
|
| 108 |
+
st.session_state["pending_question"] = q
|
| 109 |
+
|
| 110 |
+
# Footer
|
| 111 |
+
st.divider()
|
| 112 |
+
st.caption(
|
| 113 |
+
"🔗 [Local Version (nettune)](https://github.com/vanip3/bgp-rag-chatbot) \n"
|
| 114 |
+
"Powered by [Groq](https://groq.com) · [LangChain](https://langchain.com) · [FAISS](https://github.com/facebookresearch/faiss)"
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
if st.button("🗑️ Clear Chat History", use_container_width=True):
|
| 118 |
+
st.session_state.messages = []
|
| 119 |
+
st.rerun()
|
| 120 |
+
|
| 121 |
+
# ── Main Area ─────────────────────────────────────────────────────────────────
|
| 122 |
+
|
| 123 |
+
st.title("🌐 BGP Troubleshooting RAG Chatbot")
|
| 124 |
+
st.markdown(
|
| 125 |
+
"**Powered by Groq (Llama 3.1) + FAISS + Cisco BGP Knowledge Base** "
|
| 126 |
+
"| Deployed on HuggingFace Spaces \n"
|
| 127 |
+
"Ask any BGP troubleshooting question — answers grounded in Cisco documentation and real telemetry logs."
|
| 128 |
+
)
|
| 129 |
+
st.divider()
|
| 130 |
+
|
| 131 |
+
# Display chat history
|
| 132 |
+
for message in st.session_state.messages:
|
| 133 |
+
with st.chat_message(message["role"]):
|
| 134 |
+
st.markdown(message["content"])
|
| 135 |
+
if message["role"] == "assistant" and "sources" in message:
|
| 136 |
+
with st.expander("📄 Sources retrieved"):
|
| 137 |
+
for src in message["sources"]:
|
| 138 |
+
st.markdown(f"- `{src}`")
|
| 139 |
+
|
| 140 |
+
# Handle example question button clicks (populates input via session state)
|
| 141 |
+
pending = st.session_state.pop("pending_question", None)
|
| 142 |
+
|
| 143 |
+
# Chat input
|
| 144 |
+
user_input = st.chat_input("Ask a BGP troubleshooting question...")
|
| 145 |
+
|
| 146 |
+
# Use the pending example question if a button was clicked, otherwise use typed input
|
| 147 |
+
question = pending or user_input
|
| 148 |
+
|
| 149 |
+
if question:
|
| 150 |
+
# Show user message
|
| 151 |
+
st.session_state.messages.append({"role": "user", "content": question})
|
| 152 |
+
with st.chat_message("user"):
|
| 153 |
+
st.markdown(question)
|
| 154 |
+
|
| 155 |
+
# Generate response
|
| 156 |
+
with st.chat_message("assistant"):
|
| 157 |
+
with st.spinner("🔍 Searching knowledge base and querying Groq..."):
|
| 158 |
+
try:
|
| 159 |
+
result = query_bgp(question)
|
| 160 |
+
answer = result["answer"]
|
| 161 |
+
sources = result["sources"]
|
| 162 |
+
|
| 163 |
+
st.markdown(answer)
|
| 164 |
+
|
| 165 |
+
if sources:
|
| 166 |
+
with st.expander("📄 Sources retrieved"):
|
| 167 |
+
for src in sources:
|
| 168 |
+
st.markdown(f"- `{src}`")
|
| 169 |
+
|
| 170 |
+
# Save to history with sources
|
| 171 |
+
st.session_state.messages.append({
|
| 172 |
+
"role": "assistant",
|
| 173 |
+
"content": answer,
|
| 174 |
+
"sources": sources,
|
| 175 |
+
})
|
| 176 |
+
|
| 177 |
+
except Exception as e:
|
| 178 |
+
error_msg = f"❌ Error generating response: {str(e)}"
|
| 179 |
+
st.error(error_msg)
|
| 180 |
+
st.session_state.messages.append({
|
| 181 |
+
"role": "assistant",
|
| 182 |
+
"content": error_msg,
|
| 183 |
+
"sources": [],
|
| 184 |
+
})
|
| 185 |
+
|
| 186 |
+
# Re-run to clear the pending question state cleanly
|
| 187 |
+
if pending:
|
| 188 |
+
st.rerun()
|
data/docs/bgp_configuration_guide.txt
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BGP CONFIGURATION GUIDE — CISCO IOS / IOS-XE
|
| 2 |
+
=============================================
|
| 3 |
+
|
| 4 |
+
BASIC BGP CONFIGURATION
|
| 5 |
+
------------------------
|
| 6 |
+
|
| 7 |
+
Minimum configuration to start BGP process and establish a peer:
|
| 8 |
+
|
| 9 |
+
router bgp <local-AS-number>
|
| 10 |
+
bgp router-id <x.x.x.x> ! Best practice: always set manually
|
| 11 |
+
bgp log-neighbor-changes ! Enable logging of state changes (CRITICAL)
|
| 12 |
+
!
|
| 13 |
+
! eBGP peer (different AS)
|
| 14 |
+
neighbor <peer-ip> remote-as <peer-AS>
|
| 15 |
+
neighbor <peer-ip> description <text>
|
| 16 |
+
!
|
| 17 |
+
! Advertise a network
|
| 18 |
+
network <prefix> mask <subnet-mask>
|
| 19 |
+
|
| 20 |
+
Verify: show ip bgp summary
|
| 21 |
+
show bgp neighbors <peer-ip>
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
iBGP CONFIGURATION (SAME AS)
|
| 25 |
+
------------------------------
|
| 26 |
+
|
| 27 |
+
Key principle: iBGP peers must be fully meshed OR use Route Reflectors / Confederations.
|
| 28 |
+
iBGP does NOT loop prevention via split-horizon: routes learned from iBGP peer
|
| 29 |
+
are not forwarded to another iBGP peer (prevents loops but requires full mesh).
|
| 30 |
+
|
| 31 |
+
Full mesh iBGP (N routers = N*(N-1)/2 sessions — doesn't scale):
|
| 32 |
+
|
| 33 |
+
router bgp 65001
|
| 34 |
+
neighbor 10.0.0.2 remote-as 65001 ! same AS = iBGP
|
| 35 |
+
neighbor 10.0.0.2 update-source Loopback0 ! use stable source IP
|
| 36 |
+
neighbor 10.0.0.2 next-hop-self ! fix next-hop for iBGP
|
| 37 |
+
!
|
| 38 |
+
neighbor 10.0.0.3 remote-as 65001
|
| 39 |
+
neighbor 10.0.0.3 update-source Loopback0
|
| 40 |
+
neighbor 10.0.0.3 next-hop-self
|
| 41 |
+
|
| 42 |
+
Important iBGP rules:
|
| 43 |
+
- Always use loopbacks for iBGP peering (more stable than physical IPs)
|
| 44 |
+
- Always configure: neighbor <ip> update-source Loopback0
|
| 45 |
+
- Always configure: neighbor <ip> next-hop-self (especially for eBGP-learned routes)
|
| 46 |
+
- Ensure loopback reachability via IGP (OSPF/EIGRP)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
ROUTE REFLECTOR CONFIGURATION
|
| 50 |
+
-------------------------------
|
| 51 |
+
|
| 52 |
+
Route Reflector eliminates full-mesh iBGP requirement.
|
| 53 |
+
RR reflects iBGP routes to clients — clients only need session to RR.
|
| 54 |
+
|
| 55 |
+
On Route Reflector:
|
| 56 |
+
router bgp 65001
|
| 57 |
+
bgp cluster-id 1 ! Required if multiple RRs in same cluster
|
| 58 |
+
!
|
| 59 |
+
neighbor 10.0.1.1 remote-as 65001
|
| 60 |
+
neighbor 10.0.1.1 route-reflector-client ! Mark as RR client
|
| 61 |
+
!
|
| 62 |
+
neighbor 10.0.1.2 remote-as 65001
|
| 63 |
+
neighbor 10.0.1.2 route-reflector-client
|
| 64 |
+
!
|
| 65 |
+
neighbor 10.0.2.1 remote-as 65001 ! This peer is NOT an RR client
|
| 66 |
+
! (peer-to-peer iBGP, e.g., another RR)
|
| 67 |
+
|
| 68 |
+
On RR Client (standard iBGP config — client doesn't know it's a client):
|
| 69 |
+
router bgp 65001
|
| 70 |
+
neighbor 10.0.0.1 remote-as 65001 ! Points to RR
|
| 71 |
+
neighbor 10.0.0.1 update-source Loopback0
|
| 72 |
+
|
| 73 |
+
Verify: show ip bgp <prefix> — ORIGINATOR_ID and CLUSTER_LIST will be present
|
| 74 |
+
show bgp neighbors <ip> | include reflector
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
PEER GROUPS (SCALING CONFIGURATION)
|
| 78 |
+
--------------------------------------
|
| 79 |
+
|
| 80 |
+
Peer groups reduce config duplication and improve performance.
|
| 81 |
+
Peers in a group share policy — UPDATE generation done once for group.
|
| 82 |
+
|
| 83 |
+
router bgp 65001
|
| 84 |
+
!
|
| 85 |
+
neighbor IBGP-PEERS peer-group
|
| 86 |
+
neighbor IBGP-PEERS remote-as 65001
|
| 87 |
+
neighbor IBGP-PEERS update-source Loopback0
|
| 88 |
+
neighbor IBGP-PEERS next-hop-self
|
| 89 |
+
neighbor IBGP-PEERS soft-reconfiguration inbound
|
| 90 |
+
!
|
| 91 |
+
neighbor 10.0.0.2 peer-group IBGP-PEERS
|
| 92 |
+
neighbor 10.0.0.3 peer-group IBGP-PEERS
|
| 93 |
+
neighbor 10.0.0.4 peer-group IBGP-PEERS
|
| 94 |
+
|
| 95 |
+
Verify: show ip bgp peer-group
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
BGP AUTHENTICATION (MD5)
|
| 99 |
+
--------------------------
|
| 100 |
+
|
| 101 |
+
Configure identical passwords on both sides:
|
| 102 |
+
|
| 103 |
+
Router A:
|
| 104 |
+
neighbor 10.1.1.2 password Cisco123!
|
| 105 |
+
|
| 106 |
+
Router B:
|
| 107 |
+
neighbor 10.1.1.1 password Cisco123!
|
| 108 |
+
|
| 109 |
+
Notes:
|
| 110 |
+
- Password is case-sensitive
|
| 111 |
+
- No spaces allowed at beginning or end
|
| 112 |
+
- Hashed in show running-config (type 7 or encrypted)
|
| 113 |
+
- Session must be reset after adding authentication:
|
| 114 |
+
clear ip bgp 10.1.1.2
|
| 115 |
+
|
| 116 |
+
Verify: show bgp neighbors 10.1.1.2 | include password
|
| 117 |
+
(shows "MD5 is configured" — never shows actual password)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
INBOUND/OUTBOUND ROUTE FILTERING
|
| 121 |
+
----------------------------------
|
| 122 |
+
|
| 123 |
+
Method 1: Prefix-list (recommended — most efficient)
|
| 124 |
+
|
| 125 |
+
ip prefix-list ALLOW-ONLY-DEFAULT permit 0.0.0.0/0
|
| 126 |
+
ip prefix-list ALLOW-ONLY-DEFAULT deny 0.0.0.0/0 le 32
|
| 127 |
+
|
| 128 |
+
router bgp 65001
|
| 129 |
+
neighbor <ip> prefix-list ALLOW-ONLY-DEFAULT in
|
| 130 |
+
|
| 131 |
+
Method 2: Route-map (most flexible)
|
| 132 |
+
|
| 133 |
+
route-map SET-LOCAL-PREF permit 10
|
| 134 |
+
match ip address prefix-list CUSTOMER-ROUTES
|
| 135 |
+
set local-preference 200
|
| 136 |
+
route-map SET-LOCAL-PREF permit 20
|
| 137 |
+
|
| 138 |
+
router bgp 65001
|
| 139 |
+
neighbor <ip> route-map SET-LOCAL-PREF in
|
| 140 |
+
|
| 141 |
+
Method 3: AS-path filter
|
| 142 |
+
|
| 143 |
+
ip as-path access-list 1 permit ^65100_
|
| 144 |
+
ip as-path access-list 1 deny .*
|
| 145 |
+
|
| 146 |
+
router bgp 65001
|
| 147 |
+
neighbor <ip> filter-list 1 in
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
BGP TIMER CONFIGURATION
|
| 151 |
+
-------------------------
|
| 152 |
+
|
| 153 |
+
Default timers (RFC 4271):
|
| 154 |
+
Keepalive: 60 seconds
|
| 155 |
+
Hold time: 180 seconds
|
| 156 |
+
|
| 157 |
+
Modify timers (both sides should match for predictability):
|
| 158 |
+
timers bgp <keepalive> <holdtime>
|
| 159 |
+
|
| 160 |
+
Examples:
|
| 161 |
+
timers bgp 10 30 ! Fast convergence (test/datacenter)
|
| 162 |
+
timers bgp 60 180 ! Default (most WAN deployments)
|
| 163 |
+
timers bgp 0 0 ! Disable hold timer (NOT recommended)
|
| 164 |
+
|
| 165 |
+
Per-neighbor override:
|
| 166 |
+
neighbor <ip> timers <keepalive> <holdtime>
|
| 167 |
+
|
| 168 |
+
Verify: show bgp neighbors <ip> | include Hold|Keepalive
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
BGP GRACEFUL RESTART
|
| 172 |
+
---------------------
|
| 173 |
+
|
| 174 |
+
Allows BGP to maintain forwarding during a restart event (NSF/NSR).
|
| 175 |
+
|
| 176 |
+
router bgp 65001
|
| 177 |
+
bgp graceful-restart
|
| 178 |
+
bgp graceful-restart restart-time 120 ! Default 120s
|
| 179 |
+
bgp graceful-restart stalepath-time 360 ! Default 360s
|
| 180 |
+
|
| 181 |
+
Verify: show bgp neighbors <ip> | include graceful
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
MAXIMUM PREFIX CONFIGURATION
|
| 185 |
+
------------------------------
|
| 186 |
+
|
| 187 |
+
Protects router from accepting too many routes (route leak protection):
|
| 188 |
+
|
| 189 |
+
router bgp 65001
|
| 190 |
+
! Tear down session if peer sends > 500000 prefixes
|
| 191 |
+
neighbor <ip> maximum-prefix 500000
|
| 192 |
+
|
| 193 |
+
! Warn at 80% of limit, tear down at 100%
|
| 194 |
+
neighbor <ip> maximum-prefix 500000 80
|
| 195 |
+
|
| 196 |
+
! Warning only — never tear down session
|
| 197 |
+
neighbor <ip> maximum-prefix 500000 warning-only
|
| 198 |
+
|
| 199 |
+
Verify: show bgp neighbors <ip> | include prefix
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
SOFT RECONFIGURATION
|
| 203 |
+
---------------------
|
| 204 |
+
|
| 205 |
+
Required to use "show ip bgp neighbors <ip> received-routes":
|
| 206 |
+
|
| 207 |
+
router bgp 65001
|
| 208 |
+
neighbor <ip> soft-reconfiguration inbound
|
| 209 |
+
|
| 210 |
+
Note: Stores a copy of all received routes before policy application.
|
| 211 |
+
Uses additional memory. Consider carefully on high-prefix-count sessions.
|
| 212 |
+
|
| 213 |
+
Alternatively, use Route Refresh (if supported by both peers):
|
| 214 |
+
clear ip bgp <ip> soft in ! Requests peer to resend routes
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
WEIGHT, LOCAL-PREFERENCE, MED CONFIGURATION
|
| 218 |
+
---------------------------------------------
|
| 219 |
+
|
| 220 |
+
WEIGHT (Cisco proprietary — not advertised to peers, local only):
|
| 221 |
+
route-map SET-WEIGHT permit 10
|
| 222 |
+
match ip address prefix-list PREFERRED-ROUTES
|
| 223 |
+
set weight 200
|
| 224 |
+
router bgp 65001
|
| 225 |
+
neighbor <ip> route-map SET-WEIGHT in
|
| 226 |
+
|
| 227 |
+
LOCAL-PREFERENCE (advertised within AS, higher = preferred):
|
| 228 |
+
route-map SET-LP permit 10
|
| 229 |
+
set local-preference 150
|
| 230 |
+
router bgp 65001
|
| 231 |
+
neighbor <ip> route-map SET-LP in
|
| 232 |
+
|
| 233 |
+
Default local-pref: bgp default local-preference <value> (default 100)
|
| 234 |
+
|
| 235 |
+
MED (Multi-Exit Discriminator — advertised to external peers, lower = preferred):
|
| 236 |
+
route-map SET-MED permit 10
|
| 237 |
+
set metric 100
|
| 238 |
+
router bgp 65001
|
| 239 |
+
neighbor <ip> route-map SET-MED out
|
| 240 |
+
|
| 241 |
+
AS-PATH PREPENDING (make path look longer to influence inbound traffic):
|
| 242 |
+
route-map PREPEND permit 10
|
| 243 |
+
set as-path prepend 65001 65001 65001 ! Prepend our ASN 3 times
|
| 244 |
+
router bgp 65001
|
| 245 |
+
neighbor <ip> route-map PREPEND out
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
CONFEDERATIONS
|
| 249 |
+
--------------
|
| 250 |
+
|
| 251 |
+
Alternative to full-mesh iBGP for large AS. Splits AS into sub-ASs.
|
| 252 |
+
Less common than Route Reflectors in modern networks.
|
| 253 |
+
|
| 254 |
+
router bgp 65100 ! Sub-AS number
|
| 255 |
+
bgp confederation identifier 65001 ! Public-facing AS number
|
| 256 |
+
bgp confederation peers 65101 65102 ! Other sub-ASs in confederation
|
| 257 |
+
!
|
| 258 |
+
neighbor <ip> remote-as 65101 ! Peer in another sub-AS
|
data/docs/bgp_error_messages.txt
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BGP ERROR MESSAGES AND SYSLOG REFERENCE — CISCO IOS
|
| 2 |
+
=====================================================
|
| 3 |
+
|
| 4 |
+
This guide covers the most common BGP syslog messages, their meaning,
|
| 5 |
+
severity levels, and recommended remediation steps.
|
| 6 |
+
|
| 7 |
+
FORMAT: %FACILITY-SEVERITY-MNEMONIC: description
|
| 8 |
+
Severity: 0=Emergency, 1=Alert, 2=Critical, 3=Error, 4=Warning, 5=Notice, 6=Info, 7=Debug
|
| 9 |
+
|
| 10 |
+
=============================================================================
|
| 11 |
+
SESSION STATE CHANGE MESSAGES
|
| 12 |
+
=============================================================================
|
| 13 |
+
|
| 14 |
+
%BGP-5-ADJCHANGE: neighbor <ip> Down <reason>
|
| 15 |
+
Severity: 5 (Notice)
|
| 16 |
+
Meaning: BGP adjacency has gone down.
|
| 17 |
+
The <reason> field is critical — common values:
|
| 18 |
+
|
| 19 |
+
"Hold Timer Expired"
|
| 20 |
+
→ No KEEPALIVE received within hold-time seconds
|
| 21 |
+
→ Check: CPU utilization on both routers (show processes cpu)
|
| 22 |
+
→ Check: Interface drops (show interfaces | include drops)
|
| 23 |
+
→ Check: Routing to peer (ping with source IP)
|
| 24 |
+
→ Fix: May need to increase hold timer (timers bgp 60 180)
|
| 25 |
+
|
| 26 |
+
"BGP Notification sent"
|
| 27 |
+
→ Local router sent a NOTIFICATION (error) to peer
|
| 28 |
+
→ Follow-up: check logs for %BGP-3-NOTIFICATION line
|
| 29 |
+
→ That will identify the specific error code
|
| 30 |
+
|
| 31 |
+
"BGP Notification received"
|
| 32 |
+
→ Remote peer sent a NOTIFICATION to us
|
| 33 |
+
→ Follow-up: check logs for the NOTIFICATION code
|
| 34 |
+
→ May indicate our UPDATE was malformed
|
| 35 |
+
|
| 36 |
+
"Peer closed the session"
|
| 37 |
+
→ Remote router closed TCP connection cleanly
|
| 38 |
+
→ May be deliberate (peer reset the session) or process restart
|
| 39 |
+
|
| 40 |
+
"Interface flap"
|
| 41 |
+
→ Underlying interface went down, pulling BGP TCP session with it
|
| 42 |
+
→ Check: show interfaces <int> for line protocol changes
|
| 43 |
+
→ Consider BFD for faster failure detection
|
| 44 |
+
|
| 45 |
+
"Reset requested by peer"
|
| 46 |
+
→ Remote operator ran: clear ip bgp <ip>
|
| 47 |
+
→ Normal operational event
|
| 48 |
+
|
| 49 |
+
"Neighbor deleted"
|
| 50 |
+
→ BGP neighbor statement removed from configuration
|
| 51 |
+
|
| 52 |
+
%BGP-5-ADJCHANGE: neighbor <ip> Up
|
| 53 |
+
Severity: 5 (Notice)
|
| 54 |
+
Meaning: BGP adjacency established. Normal operational message.
|
| 55 |
+
Log this to verify expected peering.
|
| 56 |
+
|
| 57 |
+
=============================================================================
|
| 58 |
+
NOTIFICATION MESSAGES
|
| 59 |
+
=============================================================================
|
| 60 |
+
|
| 61 |
+
%BGP-3-NOTIFICATION: sent to neighbor <ip> <error-code>/<sub-code> (<reason>) <data>
|
| 62 |
+
%BGP-3-NOTIFICATION: received from neighbor <ip> <error-code>/<sub-code> (<reason>) <data>
|
| 63 |
+
Severity: 3 (Error)
|
| 64 |
+
Meaning: BGP NOTIFICATION message sent/received — session will reset.
|
| 65 |
+
|
| 66 |
+
Error Code 1 — Message Header Error
|
| 67 |
+
Subcode 1: Connection Not Synchronized
|
| 68 |
+
Subcode 2: Bad Message Length
|
| 69 |
+
Subcode 3: Bad Message Type
|
| 70 |
+
→ Usually indicates implementation bug or packet corruption
|
| 71 |
+
→ Check for MTU mismatches causing BGP message truncation
|
| 72 |
+
|
| 73 |
+
Error Code 2 — OPEN Message Error
|
| 74 |
+
Subcode 1: Unsupported Version Number
|
| 75 |
+
→ One side is not running BGP4 (extremely rare)
|
| 76 |
+
|
| 77 |
+
Subcode 2: Bad Peer AS
|
| 78 |
+
→ neighbor remote-as configured incorrectly on one side
|
| 79 |
+
→ Verify ASNs match on both routers: show bgp neighbors | include remote AS
|
| 80 |
+
|
| 81 |
+
Subcode 3: Bad BGP Identifier
|
| 82 |
+
→ Router ID conflict (same Router ID on both peers)
|
| 83 |
+
→ Fix: bgp router-id <unique-id> on one router
|
| 84 |
+
|
| 85 |
+
Subcode 4: Unsupported Optional Parameter
|
| 86 |
+
→ Capability mismatch (rare on modern IOS)
|
| 87 |
+
|
| 88 |
+
Subcode 5: Authentication Failure
|
| 89 |
+
→ MD5 password mismatch
|
| 90 |
+
→ Also look for: %TCP-6-BADAUTH messages
|
| 91 |
+
|
| 92 |
+
Subcode 6: Unacceptable Hold Time
|
| 93 |
+
→ Hold time < 3 seconds (RFC requirement)
|
| 94 |
+
→ Check: timers bgp configuration on both sides
|
| 95 |
+
|
| 96 |
+
Error Code 3 — UPDATE Message Error
|
| 97 |
+
Subcode 1: Malformed Attribute List
|
| 98 |
+
Subcode 2: Unrecognized Well-known Attribute
|
| 99 |
+
Subcode 3: Missing Well-known Attribute
|
| 100 |
+
Subcode 4: Attribute Flags Error
|
| 101 |
+
Subcode 5: Attribute Length Error
|
| 102 |
+
Subcode 6: Invalid ORIGIN Attribute
|
| 103 |
+
Subcode 8: Invalid NEXT_HOP Attribute
|
| 104 |
+
→ These indicate a routing protocol implementation bug
|
| 105 |
+
→ Collect: debug ip bgp <ip> updates, capture the problematic UPDATE
|
| 106 |
+
→ May need to contact Cisco TAC with packet capture
|
| 107 |
+
|
| 108 |
+
Error Code 4 — Hold Timer Expired
|
| 109 |
+
→ Same as "Hold Timer Expired" reason in ADJCHANGE
|
| 110 |
+
→ Session reset because no KEEPALIVE within hold-time
|
| 111 |
+
|
| 112 |
+
Error Code 5 — Finite State Machine Error
|
| 113 |
+
→ BGP received unexpected event for current state
|
| 114 |
+
→ Often indicates a software bug or packet corruption
|
| 115 |
+
|
| 116 |
+
Error Code 6 — Cease
|
| 117 |
+
Subcode 1: Maximum Number of Prefixes Reached
|
| 118 |
+
→ Peer exceeded maximum-prefix limit
|
| 119 |
+
→ Fix: Increase limit or fix routing policy on peer
|
| 120 |
+
|
| 121 |
+
Subcode 2: Administrative Shutdown
|
| 122 |
+
→ Peer ran: neighbor <ip> shutdown
|
| 123 |
+
→ Normal operational event
|
| 124 |
+
|
| 125 |
+
Subcode 3: Peer De-configured
|
| 126 |
+
→ Neighbor statement removed on remote side
|
| 127 |
+
|
| 128 |
+
Subcode 4: Administrative Reset
|
| 129 |
+
→ Peer ran: clear ip bgp <ip>
|
| 130 |
+
|
| 131 |
+
Subcode 7: Connection Collision Resolution
|
| 132 |
+
→ Both routers initiated TCP connection simultaneously
|
| 133 |
+
→ One session kept, one dropped. Normal behavior.
|
| 134 |
+
|
| 135 |
+
=============================================================================
|
| 136 |
+
AUTHENTICATION MESSAGES
|
| 137 |
+
=============================================================================
|
| 138 |
+
|
| 139 |
+
%TCP-6-BADAUTH: No MD5 digest from <ip>(<port>) to <ip>(<port>)
|
| 140 |
+
Meaning: We expect MD5 authentication but peer is NOT sending it.
|
| 141 |
+
Fix: Add authentication on the peer: neighbor <local-ip> password <key>
|
| 142 |
+
|
| 143 |
+
%TCP-6-BADAUTH: Invalid MD5 digest from <ip>(<port>) to <ip>(<port>)
|
| 144 |
+
Meaning: Both sides are using MD5 but the passwords do NOT match.
|
| 145 |
+
Fix: Verify identical passwords. Check for:
|
| 146 |
+
- Trailing whitespace in password
|
| 147 |
+
- Case sensitivity errors
|
| 148 |
+
- Type-0 vs Type-7 password confusion in config
|
| 149 |
+
|
| 150 |
+
=============================================================================
|
| 151 |
+
PREFIX LIMIT MESSAGES
|
| 152 |
+
=============================================================================
|
| 153 |
+
|
| 154 |
+
%BGP-3-MAXPFXEXCEED: No. of prefix received from <ip> (<count>) exceeds limit <limit>
|
| 155 |
+
Severity: 3 (Error)
|
| 156 |
+
Meaning: Peer sent more prefixes than maximum-prefix allows.
|
| 157 |
+
Action depends on configuration:
|
| 158 |
+
- Default: session torn down with NOTIFICATION (Cease/Max-Prefix)
|
| 159 |
+
- With warning-only: session stays up, alert generated
|
| 160 |
+
- With threshold: warning at percentage of limit
|
| 161 |
+
|
| 162 |
+
Fix:
|
| 163 |
+
a) Investigate why peer is sending unexpected volume
|
| 164 |
+
b) Adjust limit: neighbor <ip> maximum-prefix <new-limit>
|
| 165 |
+
c) Reset session: clear ip bgp <ip>
|
| 166 |
+
|
| 167 |
+
%BGP-4-MAXPFX: No. of prefix received from <ip> (<count>) reaches <threshold>%
|
| 168 |
+
Severity: 4 (Warning)
|
| 169 |
+
Meaning: Prefix count approaching limit — warning only, session intact.
|
| 170 |
+
Action: Monitor; consider adjusting limit or investigating route growth.
|
| 171 |
+
|
| 172 |
+
=============================================================================
|
| 173 |
+
ROUTE FLAP / DAMPENING MESSAGES
|
| 174 |
+
=============================================================================
|
| 175 |
+
|
| 176 |
+
%BGP-6-ASPATH: Long AS path <path> received — truncated
|
| 177 |
+
Severity: 6 (Informational)
|
| 178 |
+
Meaning: Received an AS_PATH exceeding 255 ASNs (virtually impossible in real networks).
|
| 179 |
+
Typically indicates a routing loop or AS_PATH prepending misconfiguration.
|
| 180 |
+
|
| 181 |
+
%BGP-5-DAMP: Prefix <prefix> now suppressed, penalty <n>
|
| 182 |
+
Meaning: Route flap dampening suppressed this prefix.
|
| 183 |
+
Fix: Either wait for suppression to lift (show ip bgp dampened-paths)
|
| 184 |
+
or clear: clear ip bgp dampening <prefix>
|
| 185 |
+
|
| 186 |
+
=============================================================================
|
| 187 |
+
MEMORY AND RESOURCE MESSAGES
|
| 188 |
+
=============================================================================
|
| 189 |
+
|
| 190 |
+
%BGP-4-MEMNOMEM: No memory available for <resource>
|
| 191 |
+
Severity: 4 (Warning)
|
| 192 |
+
Meaning: Router running low on memory for BGP operations.
|
| 193 |
+
Immediate actions:
|
| 194 |
+
1. show processes memory sorted — identify memory consumers
|
| 195 |
+
2. show ip bgp summary — how many routes/peers?
|
| 196 |
+
3. Consider prefix filtering to reduce table size
|
| 197 |
+
4. May require hardware upgrade if persistent
|
| 198 |
+
|
| 199 |
+
%SYS-2-MALLOCFAIL: Memory allocation of <n> bytes failed from <location>
|
| 200 |
+
Severity: 2 (Critical)
|
| 201 |
+
Meaning: System-wide memory exhaustion. BGP will likely flap.
|
| 202 |
+
Action: Emergency — contact NOC, consider graceful shutdown of non-critical BGP peers.
|
| 203 |
+
|
| 204 |
+
=============================================================================
|
| 205 |
+
QUICK REFERENCE: MOST COMMON MESSAGES
|
| 206 |
+
=============================================================================
|
| 207 |
+
|
| 208 |
+
Most frequently seen in production:
|
| 209 |
+
|
| 210 |
+
1. %BGP-5-ADJCHANGE: neighbor x.x.x.x Down Hold Timer Expired
|
| 211 |
+
→ Check CPU, interface drops, routing path to peer
|
| 212 |
+
|
| 213 |
+
2. %BGP-5-ADJCHANGE: neighbor x.x.x.x Down BGP Notification sent
|
| 214 |
+
→ Find the matching NOTIFICATION message for error details
|
| 215 |
+
|
| 216 |
+
3. %TCP-6-BADAUTH: Invalid MD5 digest
|
| 217 |
+
→ Password mismatch — verify both sides
|
| 218 |
+
|
| 219 |
+
4. %BGP-3-NOTIFICATION: Error Code 2 / Subcode 2 (Bad Peer AS)
|
| 220 |
+
→ AS number mismatch in neighbor configuration
|
| 221 |
+
|
| 222 |
+
5. %BGP-3-MAXPFXEXCEED
|
| 223 |
+
→ Prefix limit hit — peer sending unexpected volume of routes
|
data/docs/bgp_show_commands.txt
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BGP SHOW COMMANDS REFERENCE — CISCO IOS / IOS-XE
|
| 2 |
+
==================================================
|
| 3 |
+
|
| 4 |
+
SUMMARY AND OVERVIEW COMMANDS
|
| 5 |
+
-------------------------------
|
| 6 |
+
|
| 7 |
+
show ip bgp summary
|
| 8 |
+
Purpose: Quick overview of all BGP neighbors, their state, prefixes received
|
| 9 |
+
Output fields:
|
| 10 |
+
Neighbor — Peer IP address
|
| 11 |
+
V — BGP version (always 4)
|
| 12 |
+
AS — Remote AS number
|
| 13 |
+
MsgRcvd — Total messages received since session start
|
| 14 |
+
MsgSent — Total messages sent
|
| 15 |
+
TblVer — Table version (increments with each routing change)
|
| 16 |
+
InQ/OutQ — Messages queued (should be 0; if non-zero, session overloaded)
|
| 17 |
+
Up/Down — Session uptime (or time since last state change if down)
|
| 18 |
+
State/PfxRcd — Session state or prefix count if ESTABLISHED
|
| 19 |
+
|
| 20 |
+
Key interpretation:
|
| 21 |
+
State = Idle/Active/Connect → session NOT established
|
| 22 |
+
State = numeric (e.g., 145032) → ESTABLISHED, showing prefix count
|
| 23 |
+
State = 0 → ESTABLISHED but no prefixes received
|
| 24 |
+
|
| 25 |
+
show ip bgp
|
| 26 |
+
Purpose: Full BGP routing table
|
| 27 |
+
Output columns:
|
| 28 |
+
Status codes: s=suppressed, d=damped, h=history, *=valid, >=best, i=internal
|
| 29 |
+
Origin codes: i=IGP, e=EGP, ?=incomplete
|
| 30 |
+
Common filters:
|
| 31 |
+
show ip bgp <prefix> — specific prefix detail
|
| 32 |
+
show ip bgp regexp <regex> — filter by AS_PATH
|
| 33 |
+
show ip bgp community <value> — filter by community
|
| 34 |
+
show ip bgp prefix-list <name> — filter by prefix-list
|
| 35 |
+
|
| 36 |
+
show bgp neighbors <ip> (or show ip bgp neighbors <ip>)
|
| 37 |
+
Purpose: Detailed per-neighbor information
|
| 38 |
+
Key fields to check:
|
| 39 |
+
BGP state = <state> — current FSM state
|
| 40 |
+
Hold time is <n>, keepalive is <n> — negotiated timers
|
| 41 |
+
Configured hold time is <n> — locally configured value
|
| 42 |
+
BGP version = 4 — should always be 4
|
| 43 |
+
Neighbor capabilities: — supported features
|
| 44 |
+
Message statistics: — counts by message type
|
| 45 |
+
Prefix activity: — prefixes accepted/denied
|
| 46 |
+
Local host: <ip>, Local port: <port>
|
| 47 |
+
Foreign host: <ip>, Foreign port: <port>
|
| 48 |
+
Connections established <n>; dropped <n>
|
| 49 |
+
Last reset <time> ago, due to: <reason> ← CRITICAL FOR TROUBLESHOOTING
|
| 50 |
+
|
| 51 |
+
PREFIX AND ROUTE COMMANDS
|
| 52 |
+
--------------------------
|
| 53 |
+
|
| 54 |
+
show ip bgp neighbors <ip> advertised-routes
|
| 55 |
+
Purpose: Show routes being sent TO this neighbor
|
| 56 |
+
Use case: Verify outbound policy is working correctly
|
| 57 |
+
Note: Does not require soft-reconfiguration inbound
|
| 58 |
+
|
| 59 |
+
show ip bgp neighbors <ip> received-routes
|
| 60 |
+
Purpose: Show ALL routes received FROM neighbor (before inbound policy)
|
| 61 |
+
Prerequisite: neighbor <ip> soft-reconfiguration inbound must be configured
|
| 62 |
+
Use case: Verify what peer is actually sending before filters
|
| 63 |
+
|
| 64 |
+
show ip bgp neighbors <ip> routes
|
| 65 |
+
Purpose: Show routes accepted after inbound policy
|
| 66 |
+
Use case: Verify filtered routes are being applied
|
| 67 |
+
|
| 68 |
+
show ip bgp <prefix>
|
| 69 |
+
Purpose: Detailed path information for a specific prefix
|
| 70 |
+
Shows: All paths, best path selection reason, full attributes
|
| 71 |
+
Example output interpretation:
|
| 72 |
+
BGP routing table entry for 10.0.0.0/8, version 45
|
| 73 |
+
Paths: (2 available, best #1, table Default-IP-Routing-Table)
|
| 74 |
+
Advertised to update-groups: 1
|
| 75 |
+
Path #1: <best>
|
| 76 |
+
10.1.1.1 from 10.1.1.1 (192.168.1.1)
|
| 77 |
+
Origin IGP, metric 0, localpref 100, valid, external, best
|
| 78 |
+
Community: 65000:100
|
| 79 |
+
|
| 80 |
+
show ip bgp <prefix> longer-prefixes
|
| 81 |
+
Purpose: Show all more-specific routes within a prefix block
|
| 82 |
+
Use case: Check for more-specifics competing with aggregate
|
| 83 |
+
|
| 84 |
+
POLICY AND FILTERING COMMANDS
|
| 85 |
+
-------------------------------
|
| 86 |
+
|
| 87 |
+
show route-map [name]
|
| 88 |
+
Purpose: Display route-map configuration and match/set statistics
|
| 89 |
+
Counter field: Policy routing matches — shows how many routes hit each clause
|
| 90 |
+
|
| 91 |
+
show ip prefix-list [name]
|
| 92 |
+
Purpose: Display prefix-list and hit counters
|
| 93 |
+
Use case: Verify prefix-lists are matching expected routes
|
| 94 |
+
|
| 95 |
+
show ip community-list [number|name]
|
| 96 |
+
Purpose: Display community-list configuration
|
| 97 |
+
|
| 98 |
+
show bgp neighbors <ip> policy
|
| 99 |
+
Purpose: Show inbound and outbound policies applied to this neighbor
|
| 100 |
+
Requires: BGP policy accounting enabled, or IOS-XE enhanced policy view
|
| 101 |
+
|
| 102 |
+
ATTRIBUTE MANIPULATION VERIFICATION
|
| 103 |
+
-------------------------------------
|
| 104 |
+
|
| 105 |
+
show ip bgp | include LOCAL_PREF
|
| 106 |
+
Purpose: Verify LOCAL_PREFERENCE values in table
|
| 107 |
+
|
| 108 |
+
show ip bgp detail | include community
|
| 109 |
+
Purpose: Show community values on prefixes
|
| 110 |
+
|
| 111 |
+
show ip bgp <prefix> detail
|
| 112 |
+
Purpose: Full attribute dump including:
|
| 113 |
+
- LOCAL_PREF, MED, WEIGHT, AS_PATH
|
| 114 |
+
- COMMUNITIES, ORIGINATOR_ID, CLUSTER_LIST
|
| 115 |
+
- NEXT_HOP and IGP metric to next-hop
|
| 116 |
+
- Path selection reason
|
| 117 |
+
|
| 118 |
+
STATISTICS AND MONITORING
|
| 119 |
+
--------------------------
|
| 120 |
+
|
| 121 |
+
show bgp neighbors <ip> | include notifications
|
| 122 |
+
Purpose: Check for NOTIFICATION messages (errors sent/received)
|
| 123 |
+
Non-zero notifications indicate session resets with error codes
|
| 124 |
+
|
| 125 |
+
show bgp neighbors <ip> | include drops
|
| 126 |
+
Purpose: Count session drops/resets
|
| 127 |
+
|
| 128 |
+
show bgp summary | include Down
|
| 129 |
+
Purpose: Quick filter to see which peers are down
|
| 130 |
+
|
| 131 |
+
show tcp brief
|
| 132 |
+
Purpose: Verify TCP session exists for BGP (port 179)
|
| 133 |
+
Look for: <peer-ip>.bgp ESTABLISHED
|
| 134 |
+
|
| 135 |
+
show ip route bgp
|
| 136 |
+
Purpose: Show only BGP-installed routes in routing table
|
| 137 |
+
Use case: Verify BGP routes are being used for forwarding
|
| 138 |
+
|
| 139 |
+
DEBUG COMMANDS (USE WITH CAUTION IN PRODUCTION)
|
| 140 |
+
-------------------------------------------------
|
| 141 |
+
|
| 142 |
+
debug ip bgp <neighbor-ip> events
|
| 143 |
+
Shows: Session state changes, timer events, connection attempts
|
| 144 |
+
Safe to use briefly in production
|
| 145 |
+
|
| 146 |
+
debug ip bgp <neighbor-ip> updates
|
| 147 |
+
Shows: Every UPDATE message sent and received
|
| 148 |
+
WARNING: Very verbose if many prefixes; can impact router performance
|
| 149 |
+
Best practice: Use with specific neighbor IP, not "debug ip bgp *"
|
| 150 |
+
|
| 151 |
+
debug ip bgp all
|
| 152 |
+
WARNING: NEVER use in production. Shows ALL BGP events for ALL peers.
|
| 153 |
+
Use only in lab environment.
|
| 154 |
+
|
| 155 |
+
Undebug all: undebug all (or: no debug all)
|
| 156 |
+
|
| 157 |
+
USEFUL SHOW COMMAND SEQUENCES FOR COMMON SCENARIOS
|
| 158 |
+
----------------------------------------------------
|
| 159 |
+
|
| 160 |
+
Scenario: BGP session down, need to know why
|
| 161 |
+
1. show ip bgp summary — confirm state
|
| 162 |
+
2. show bgp neighbors <ip> | include state — current state
|
| 163 |
+
3. show bgp neighbors <ip> | include reset — last reset reason
|
| 164 |
+
4. ping <ip> source <source-ip> — test reachability
|
| 165 |
+
5. show log | include BGP — check syslog history
|
| 166 |
+
|
| 167 |
+
Scenario: Routes not appearing in BGP table
|
| 168 |
+
1. show ip bgp summary — confirm ESTABLISHED
|
| 169 |
+
2. show bgp neighbors <ip> received-routes — what did peer send?
|
| 170 |
+
3. show bgp neighbors <ip> routes — what survived filtering?
|
| 171 |
+
4. show bgp neighbors <ip> policy — what policy is applied?
|
| 172 |
+
5. show route-map <name> — check policy config
|
| 173 |
+
|
| 174 |
+
Scenario: Suboptimal routing (wrong path selected)
|
| 175 |
+
1. show ip bgp <prefix> — see all paths
|
| 176 |
+
2. show ip bgp <prefix> detail — see attribute comparison
|
| 177 |
+
3. show bgp neighbors <ip> advertised-routes — verify what you're sending
|
| 178 |
+
4. Check: weight, local-pref, AS-path, MED in order of preference
|
data/docs/bgp_states_guide.txt
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BGP NEIGHBOR STATE MACHINE — CISCO IOS REFERENCE GUIDE
|
| 2 |
+
=======================================================
|
| 3 |
+
|
| 4 |
+
BGP uses a finite state machine (FSM) with six states to manage neighbor relationships.
|
| 5 |
+
Understanding each state is critical for troubleshooting peering issues.
|
| 6 |
+
|
| 7 |
+
STATE 1: IDLE
|
| 8 |
+
-------------
|
| 9 |
+
Description:
|
| 10 |
+
The router is not attempting BGP connections. This is the initial state.
|
| 11 |
+
|
| 12 |
+
Common causes of being stuck in IDLE:
|
| 13 |
+
- BGP process not started or neighbor statement missing
|
| 14 |
+
- Administrative shutdown: neighbor <ip> shutdown
|
| 15 |
+
- Route to neighbor unreachable (no IGP path)
|
| 16 |
+
- TCP port 179 blocked by ACL or firewall
|
| 17 |
+
- Incorrect neighbor IP address configured
|
| 18 |
+
|
| 19 |
+
Verification commands:
|
| 20 |
+
show bgp neighbors <ip>
|
| 21 |
+
show ip bgp summary
|
| 22 |
+
ping <neighbor-ip> source <local-ip>
|
| 23 |
+
telnet <neighbor-ip> 179
|
| 24 |
+
|
| 25 |
+
Transition: IDLE → CONNECT when BGP initiates TCP connection
|
| 26 |
+
|
| 27 |
+
STATE 2: CONNECT
|
| 28 |
+
----------------
|
| 29 |
+
Description:
|
| 30 |
+
BGP is waiting for the TCP three-way handshake to complete on port 179.
|
| 31 |
+
|
| 32 |
+
Common issues:
|
| 33 |
+
- TCP SYN sent but no SYN-ACK received (firewall blocking)
|
| 34 |
+
- Wrong source IP for TCP session (use update-source loopback for iBGP)
|
| 35 |
+
- MTU mismatch causing TCP fragmentation issues
|
| 36 |
+
|
| 37 |
+
Verification commands:
|
| 38 |
+
debug ip bgp <neighbor-ip> events
|
| 39 |
+
show tcp brief
|
| 40 |
+
show ip interface brief (verify source interface)
|
| 41 |
+
|
| 42 |
+
Transition: CONNECT → OPENSENT when TCP session established
|
| 43 |
+
|
| 44 |
+
STATE 3: ACTIVE
|
| 45 |
+
---------------
|
| 46 |
+
Description:
|
| 47 |
+
TCP connection failed; BGP is actively retrying. The router alternates
|
| 48 |
+
between CONNECT and ACTIVE states while attempting to establish TCP.
|
| 49 |
+
|
| 50 |
+
ACTIVE state is one of the most common "stuck" states and indicates:
|
| 51 |
+
- TCP connectivity problem (most common)
|
| 52 |
+
- Incorrect neighbor IP address
|
| 53 |
+
- Missing or wrong update-source configuration for loopback peers
|
| 54 |
+
- Interface down on one side
|
| 55 |
+
|
| 56 |
+
Key distinction: ACTIVE means BGP is TRYING but failing at TCP layer.
|
| 57 |
+
|
| 58 |
+
Verification commands:
|
| 59 |
+
show bgp neighbors <ip> | include BGP state
|
| 60 |
+
debug ip tcp transactions
|
| 61 |
+
show ip route <neighbor-ip>
|
| 62 |
+
|
| 63 |
+
STATE 4: OPENSENT
|
| 64 |
+
-----------------
|
| 65 |
+
Description:
|
| 66 |
+
TCP connection established. Local router sent OPEN message and is waiting
|
| 67 |
+
for the remote router's OPEN message.
|
| 68 |
+
|
| 69 |
+
OPEN message contains:
|
| 70 |
+
- BGP version (must be 4 on both sides)
|
| 71 |
+
- AS number
|
| 72 |
+
- Hold time
|
| 73 |
+
- BGP Router ID
|
| 74 |
+
- Optional capabilities (route refresh, 4-byte ASN, etc.)
|
| 75 |
+
|
| 76 |
+
Common errors at this stage:
|
| 77 |
+
- AS number mismatch
|
| 78 |
+
- BGP version incompatibility (rare, always version 4)
|
| 79 |
+
- Unsupported capability causing NOTIFICATION
|
| 80 |
+
|
| 81 |
+
Verification commands:
|
| 82 |
+
debug ip bgp <neighbor-ip> updates
|
| 83 |
+
show bgp neighbors <ip>
|
| 84 |
+
|
| 85 |
+
STATE 5: OPENCONFIRM
|
| 86 |
+
--------------------
|
| 87 |
+
Description:
|
| 88 |
+
Both OPEN messages exchanged. BGP is waiting for KEEPALIVE to confirm
|
| 89 |
+
the session. Hold timer negotiation occurs here.
|
| 90 |
+
|
| 91 |
+
Hold time negotiation: lower value of the two routers wins.
|
| 92 |
+
Default hold time: 180 seconds
|
| 93 |
+
Default keepalive interval: 60 seconds (1/3 of hold time)
|
| 94 |
+
|
| 95 |
+
Common issues:
|
| 96 |
+
- Hold time mismatch (one side configured with timers bgp 10 30,
|
| 97 |
+
other side uses default 60 180 — the lower 30 will be selected)
|
| 98 |
+
- NOTIFICATION sent by remote (check logs)
|
| 99 |
+
|
| 100 |
+
Verification commands:
|
| 101 |
+
show bgp neighbors <ip> | include Hold time
|
| 102 |
+
show bgp neighbors <ip> | include Keepalive
|
| 103 |
+
|
| 104 |
+
STATE 6: ESTABLISHED
|
| 105 |
+
--------------------
|
| 106 |
+
Description:
|
| 107 |
+
BGP session is fully up. KEEPALIVE messages exchanged every keepalive
|
| 108 |
+
interval. UPDATE messages carry routing information.
|
| 109 |
+
|
| 110 |
+
Monitoring an ESTABLISHED session:
|
| 111 |
+
show ip bgp summary — shows prefixes received, uptime, state
|
| 112 |
+
show bgp neighbors <ip> — detailed session info
|
| 113 |
+
show ip bgp — full BGP table
|
| 114 |
+
show ip bgp neighbors <ip> advertised-routes
|
| 115 |
+
show ip bgp neighbors <ip> received-routes
|
| 116 |
+
|
| 117 |
+
Session going DOWN from ESTABLISHED indicates:
|
| 118 |
+
- Hold timer expired (no KEEPALIVE received in hold-time seconds)
|
| 119 |
+
- NOTIFICATION message received
|
| 120 |
+
- TCP session reset (interface flap, carrier drop)
|
| 121 |
+
- BFD failure (if configured)
|
| 122 |
+
- Peer reset (clear ip bgp executed on remote)
|
| 123 |
+
|
| 124 |
+
BGP TIMER REFERENCE
|
| 125 |
+
-------------------
|
| 126 |
+
Default keepalive: 60 seconds
|
| 127 |
+
Default hold time: 180 seconds
|
| 128 |
+
Minimum hold time: 0 (hold timer disabled — not recommended)
|
| 129 |
+
ConnectRetry timer: 32 seconds (wait before retrying TCP after failure)
|
| 130 |
+
|
| 131 |
+
Recommended for fast convergence (data center):
|
| 132 |
+
timers bgp 3 9
|
| 133 |
+
(keepalive 3s, hold 9s — aggressive but supported)
|
| 134 |
+
|
| 135 |
+
BGP ROUTER ID SELECTION
|
| 136 |
+
------------------------
|
| 137 |
+
BGP Router ID is selected in this order:
|
| 138 |
+
1. Manually configured: bgp router-id <x.x.x.x>
|
| 139 |
+
2. Highest loopback IP address
|
| 140 |
+
3. Highest physical interface IP address (if no loopback)
|
| 141 |
+
|
| 142 |
+
Router ID conflict causes OPEN message rejection.
|
| 143 |
+
Two iBGP peers cannot have same Router ID.
|
data/docs/bgp_troubleshooting_guide.txt
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BGP TROUBLESHOOTING GUIDE — SYSTEMATIC METHODOLOGY
|
| 2 |
+
====================================================
|
| 3 |
+
|
| 4 |
+
GOLDEN RULE: Always start at Layer 3 (IP reachability) before debugging BGP.
|
| 5 |
+
BGP runs over TCP port 179 — if TCP fails, BGP fails.
|
| 6 |
+
|
| 7 |
+
TROUBLESHOOTING FRAMEWORK
|
| 8 |
+
--------------------------
|
| 9 |
+
Step 1: Verify physical/logical connectivity
|
| 10 |
+
Step 2: Verify IP reachability to BGP peer
|
| 11 |
+
Step 3: Verify BGP configuration matches on both sides
|
| 12 |
+
Step 4: Check BGP state machine and error messages
|
| 13 |
+
Step 5: Verify prefix exchange and routing policies
|
| 14 |
+
|
| 15 |
+
SECTION 1: BGP SESSION NOT FORMING
|
| 16 |
+
------------------------------------
|
| 17 |
+
|
| 18 |
+
Symptom: "show ip bgp summary" shows neighbor in ACTIVE or IDLE state
|
| 19 |
+
|
| 20 |
+
Checklist:
|
| 21 |
+
[ ] Can you ping the neighbor IP from the correct source?
|
| 22 |
+
ping <neighbor-ip> source <update-source-ip>
|
| 23 |
+
|
| 24 |
+
[ ] Is TCP 179 reachable?
|
| 25 |
+
telnet <neighbor-ip> 179
|
| 26 |
+
|
| 27 |
+
[ ] Is the neighbor statement correct?
|
| 28 |
+
neighbor <ip> remote-as <asn>
|
| 29 |
+
|
| 30 |
+
[ ] For iBGP with loopbacks: is update-source configured?
|
| 31 |
+
neighbor <loopback-ip> update-source Loopback0
|
| 32 |
+
|
| 33 |
+
[ ] Is there a route to the neighbor in the routing table?
|
| 34 |
+
show ip route <neighbor-ip>
|
| 35 |
+
|
| 36 |
+
[ ] Is port 179 blocked?
|
| 37 |
+
show ip access-lists (check for deny tcp any any eq 179)
|
| 38 |
+
|
| 39 |
+
[ ] Are both sides using the same MD5 password?
|
| 40 |
+
neighbor <ip> password <key>
|
| 41 |
+
— Password mismatch causes TCP session to silently fail
|
| 42 |
+
|
| 43 |
+
Commands to run:
|
| 44 |
+
show ip bgp summary
|
| 45 |
+
show bgp neighbors <ip>
|
| 46 |
+
debug ip bgp <ip> events (use with caution in production)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
SECTION 2: BGP SESSION FLAPPING
|
| 50 |
+
---------------------------------
|
| 51 |
+
|
| 52 |
+
Symptom: BGP neighbor goes up and down repeatedly
|
| 53 |
+
Syslog: %BGP-5-ADJCHANGE: neighbor <ip> Down
|
| 54 |
+
|
| 55 |
+
Root causes and remediation:
|
| 56 |
+
|
| 57 |
+
1. HOLD TIMER EXPIRY (most common flapping cause)
|
| 58 |
+
- Symptoms: "BGP notification sent or received" in logs
|
| 59 |
+
- Cause: KEEPALIVE messages not arriving within hold-time
|
| 60 |
+
- Often caused by: high CPU on router, interface congestion,
|
| 61 |
+
route processor overload
|
| 62 |
+
- Fix:
|
| 63 |
+
a) Check CPU: show processes cpu sorted
|
| 64 |
+
b) Check input queue drops: show interfaces <int> | include drops
|
| 65 |
+
c) Consider increasing hold timer: timers bgp 60 180
|
| 66 |
+
d) Consider BFD as alternative failure detection
|
| 67 |
+
|
| 68 |
+
2. INTERFACE FLAPPING
|
| 69 |
+
- Verify: show interfaces <int> | include line protocol
|
| 70 |
+
- Check error counters: show interfaces <int>
|
| 71 |
+
- Look for CRC errors, input errors indicating physical layer issue
|
| 72 |
+
|
| 73 |
+
3. ROUTE REFLECTOR / CONFEDERATION ISSUES
|
| 74 |
+
- Verify RR cluster-id matches across all RR clients
|
| 75 |
+
- Check for routing loops caused by missing cluster-id
|
| 76 |
+
|
| 77 |
+
4. MEMORY EXHAUSTION
|
| 78 |
+
- show processes memory sorted
|
| 79 |
+
- BGP table too large for available memory
|
| 80 |
+
- Consider prefix-list filtering: neighbor <ip> prefix-list FILTER in
|
| 81 |
+
|
| 82 |
+
5. BFD TRIGGERED FAILOVER
|
| 83 |
+
- show bfd neighbors
|
| 84 |
+
- BFD more sensitive than BGP hold timer — may trigger false positives
|
| 85 |
+
- Tune: bfd interval 300 min_rx 300 multiplier 3
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
SECTION 3: ROUTES NOT BEING RECEIVED
|
| 89 |
+
--------------------------------------
|
| 90 |
+
|
| 91 |
+
Symptom: BGP session is ESTABLISHED but expected prefixes missing
|
| 92 |
+
|
| 93 |
+
Checklist:
|
| 94 |
+
[ ] Does the remote side have the route to advertise?
|
| 95 |
+
show ip bgp <prefix> (on remote router)
|
| 96 |
+
|
| 97 |
+
[ ] Is the route being advertised?
|
| 98 |
+
show ip bgp neighbors <ip> advertised-routes
|
| 99 |
+
|
| 100 |
+
[ ] Is an inbound route policy filtering it?
|
| 101 |
+
show ip bgp neighbors <ip> policy
|
| 102 |
+
show route-map <name>
|
| 103 |
+
|
| 104 |
+
[ ] Is the prefix blocked by a prefix-list?
|
| 105 |
+
show ip prefix-list <name>
|
| 106 |
+
|
| 107 |
+
[ ] Is soft-reconfiguration enabled (to see received routes)?
|
| 108 |
+
neighbor <ip> soft-reconfiguration inbound
|
| 109 |
+
show ip bgp neighbors <ip> received-routes
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
SECTION 4: ROUTES NOT BEING ADVERTISED
|
| 113 |
+
----------------------------------------
|
| 114 |
+
|
| 115 |
+
Symptom: Local prefixes not appearing in peer's BGP table
|
| 116 |
+
|
| 117 |
+
Common causes:
|
| 118 |
+
|
| 119 |
+
1. NETWORK STATEMENT MISSING OR WRONG
|
| 120 |
+
- network <prefix> mask <mask> must exactly match routing table entry
|
| 121 |
+
- network 10.0.0.0 mask 255.255.0.0 will only work if 10.0.0.0/16
|
| 122 |
+
exists exactly in the routing table (not just a subnet of it)
|
| 123 |
+
|
| 124 |
+
2. REDISTRIBUTE NOT CONFIGURED
|
| 125 |
+
- If redistributing from OSPF/EIGRP:
|
| 126 |
+
redistribute ospf 1 metric 100 route-map EXPORT
|
| 127 |
+
|
| 128 |
+
3. NEXT-HOP NOT REACHABLE
|
| 129 |
+
- iBGP: next-hop-self required when advertising eBGP-learned routes to iBGP
|
| 130 |
+
- neighbor <ip> next-hop-self
|
| 131 |
+
|
| 132 |
+
4. OUTBOUND ROUTE POLICY BLOCKING
|
| 133 |
+
- show bgp neighbors <ip> policy
|
| 134 |
+
- show route-map <name> (check for deny statements)
|
| 135 |
+
|
| 136 |
+
5. MAXIMUM-PREFIX LIMIT HIT
|
| 137 |
+
- neighbor <ip> maximum-prefix <number> [threshold] [warning-only]
|
| 138 |
+
- show ip bgp neighbors <ip> | include prefix
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
SECTION 5: BGP PATH SELECTION ISSUES
|
| 142 |
+
--------------------------------------
|
| 143 |
+
|
| 144 |
+
When multiple paths exist, BGP selects best path using this ordered criteria:
|
| 145 |
+
|
| 146 |
+
1. Highest WEIGHT (Cisco proprietary, local to router)
|
| 147 |
+
2. Highest LOCAL_PREFERENCE (within AS, default 100)
|
| 148 |
+
3. Locally originated (network/redistribute > iBGP learned)
|
| 149 |
+
4. Shortest AS_PATH length
|
| 150 |
+
5. Lowest ORIGIN (IGP < EGP < incomplete)
|
| 151 |
+
6. Lowest MED (when paths come from same neighboring AS)
|
| 152 |
+
7. eBGP path over iBGP path
|
| 153 |
+
8. Lowest IGP metric to BGP next-hop
|
| 154 |
+
9. Oldest eBGP path (most stable)
|
| 155 |
+
10. Lowest BGP Router ID
|
| 156 |
+
11. Lowest neighbor IP address
|
| 157 |
+
|
| 158 |
+
Debug path selection:
|
| 159 |
+
show ip bgp <prefix> — shows all paths, best marked with >
|
| 160 |
+
show ip bgp <prefix> detail — full attribute dump
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
SECTION 6: AUTHENTICATION FAILURES
|
| 164 |
+
-------------------------------------
|
| 165 |
+
|
| 166 |
+
BGP MD5 authentication:
|
| 167 |
+
neighbor <ip> password <key>
|
| 168 |
+
|
| 169 |
+
Symptoms of mismatch:
|
| 170 |
+
- TCP session never establishes (stays in ACTIVE)
|
| 171 |
+
- Syslog: %TCP-6-BADAUTH: No MD5 digest from <ip>
|
| 172 |
+
- Syslog: %TCP-6-BADAUTH: Invalid MD5 digest from <ip>
|
| 173 |
+
|
| 174 |
+
Verification:
|
| 175 |
+
show bgp neighbors <ip> | include password
|
| 176 |
+
(will show "MD5 is configured" but NOT the password itself)
|
| 177 |
+
|
| 178 |
+
Common mistakes:
|
| 179 |
+
- Trailing space in password string
|
| 180 |
+
- Case sensitivity error
|
| 181 |
+
- One side has password, other does not
|
| 182 |
+
- Password configured but TCP session pre-dates authentication config
|
| 183 |
+
(requires session reset: clear ip bgp <ip> soft)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
SECTION 7: HIGH CPU FROM BGP
|
| 187 |
+
------------------------------
|
| 188 |
+
|
| 189 |
+
Symptoms: Router sluggish, BGP sessions flapping, high CPU
|
| 190 |
+
|
| 191 |
+
Commands:
|
| 192 |
+
show processes cpu sorted | head 20
|
| 193 |
+
show bgp process detail (XE/XR)
|
| 194 |
+
|
| 195 |
+
Common causes:
|
| 196 |
+
1. Full internet BGP table (800k+ routes) — normal during convergence
|
| 197 |
+
2. Route policy with complex regex (avoid regex in large deployments)
|
| 198 |
+
3. Peer sending malformed updates (check: show ip bgp neighbors <ip> | include notifications)
|
| 199 |
+
4. BGP scanner running (every 60s, unavoidable but brief)
|
| 200 |
+
5. Soft reset in progress: clear ip bgp <ip> soft in
|
| 201 |
+
|
| 202 |
+
Mitigation:
|
| 203 |
+
- Prefix filtering: only accept needed prefixes
|
| 204 |
+
- Outbound route filtering (ORF)
|
| 205 |
+
- BGP route dampening (use carefully — deprecated in some designs)
|
data/telemetry/bgp_telemetry_logs.txt
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BGP TELEMETRY AND SYSLOG DATA — PRODUCTION NETWORK SAMPLES
|
| 2 |
+
============================================================
|
| 3 |
+
Collection period: 30 days
|
| 4 |
+
Network: Enterprise dual-homed AS65001 (iBGP + 2x eBGP upstreams)
|
| 5 |
+
Routers: CORE-RTR-01, CORE-RTR-02, EDGE-RTR-01, EDGE-RTR-02
|
| 6 |
+
|
| 7 |
+
=============================================================================
|
| 8 |
+
WEEK 1 — NORMAL OPERATIONS + AUTHENTICATION INCIDENT
|
| 9 |
+
=============================================================================
|
| 10 |
+
|
| 11 |
+
2024-01-02 00:01:15 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Up
|
| 12 |
+
2024-01-02 00:01:16 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 172.16.0.1 Up
|
| 13 |
+
2024-01-02 00:01:18 UTC EDGE-RTR-01: %BGP-5-ADJCHANGE: neighbor 203.0.113.1 Up
|
| 14 |
+
|
| 15 |
+
2024-01-02 00:15:30 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Down Hold Timer Expired
|
| 16 |
+
2024-01-02 00:15:30 UTC CORE-RTR-01: %BGP-3-NOTIFICATION: sent to neighbor 10.0.0.2 4/0 (hold time expired) 0 bytes
|
| 17 |
+
2024-01-02 00:15:47 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Up
|
| 18 |
+
# Analysis: Brief hold timer expiry — likely high CPU spike. Recovered quickly.
|
| 19 |
+
# Action taken: Monitored; CPU was at 92% during BGP scanner run.
|
| 20 |
+
|
| 21 |
+
2024-01-03 09:22:11 UTC EDGE-RTR-01: %TCP-6-BADAUTH: No MD5 digest from 198.51.100.1(179) to 198.51.100.2(49821)
|
| 22 |
+
2024-01-03 09:22:11 UTC EDGE-RTR-01: %TCP-6-BADAUTH: No MD5 digest from 198.51.100.1(179) to 198.51.100.2(49821)
|
| 23 |
+
2024-01-03 09:22:12 UTC EDGE-RTR-01: %TCP-6-BADAUTH: No MD5 digest from 198.51.100.1(179) to 198.51.100.2(49821)
|
| 24 |
+
# Analysis: ISP-01 (198.51.100.1) not sending MD5 authentication.
|
| 25 |
+
# Opened ticket with ISP — they had removed auth after maintenance window.
|
| 26 |
+
# ISP added auth back at 09:45. Session re-established at 09:47.
|
| 27 |
+
|
| 28 |
+
2024-01-03 09:47:03 UTC EDGE-RTR-01: %BGP-5-ADJCHANGE: neighbor 198.51.100.1 Up
|
| 29 |
+
|
| 30 |
+
2024-01-04 14:33:22 UTC EDGE-RTR-02: %BGP-5-ADJCHANGE: neighbor 203.0.113.5 Down BGP Notification received
|
| 31 |
+
2024-01-04 14:33:22 UTC EDGE-RTR-02: %BGP-3-NOTIFICATION: received from neighbor 203.0.113.5 2/2 (open error/bad peer AS) 2 bytes
|
| 32 |
+
# Analysis: ISP-02 (203.0.113.5) sent Open Error — Bad Peer AS.
|
| 33 |
+
# Investigation: ISP changed our peer configuration to wrong ASN after circuit upgrade.
|
| 34 |
+
# ISP corrected at 15:10.
|
| 35 |
+
|
| 36 |
+
2024-01-04 15:10:44 UTC EDGE-RTR-02: %BGP-5-ADJCHANGE: neighbor 203.0.113.5 Up
|
| 37 |
+
|
| 38 |
+
=============================================================================
|
| 39 |
+
WEEK 2 — HOLD TIMER EXPIRY INCIDENTS (MOST COMMON ISSUE TYPE)
|
| 40 |
+
=============================================================================
|
| 41 |
+
|
| 42 |
+
# Hold timer expiry accounted for 67% of all BGP resets this month.
|
| 43 |
+
# Primary cause: CPU spikes during BGP table scan (every 60 seconds).
|
| 44 |
+
|
| 45 |
+
2024-01-08 02:14:55 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Down Hold Timer Expired
|
| 46 |
+
2024-01-08 02:14:55 UTC CORE-RTR-01: show processes cpu sorted output:
|
| 47 |
+
CPU utilization for five seconds: 98%/62%; one minute: 78%; five minutes: 45%
|
| 48 |
+
PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process
|
| 49 |
+
170 8234901 291034 28290 72.45% 41.23% 18.12% 0 BGP Scanner
|
| 50 |
+
045 1923044 82341 23360 14.22% 8.44% 4.21% 0 BGP Router
|
| 51 |
+
# BGP Scanner consuming 72% CPU — causing keepalive packet drops.
|
| 52 |
+
|
| 53 |
+
2024-01-08 02:15:22 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Up
|
| 54 |
+
|
| 55 |
+
2024-01-09 03:45:11 UTC CORE-RTR-02: %BGP-5-ADJCHANGE: neighbor 10.0.0.1 Down Hold Timer Expired
|
| 56 |
+
2024-01-09 03:45:34 UTC CORE-RTR-02: %BGP-5-ADJCHANGE: neighbor 10.0.0.1 Up
|
| 57 |
+
# Same pattern on CORE-RTR-02. Hold timer expiry at 03:45, recovered at 03:45.
|
| 58 |
+
# Duration: 23 seconds.
|
| 59 |
+
|
| 60 |
+
2024-01-10 03:44:58 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Down Hold Timer Expired
|
| 61 |
+
# Third consecutive night at ~03:45 UTC. Correlates with nightly backup job.
|
| 62 |
+
# Backup script was causing 80% CPU spike on management plane.
|
| 63 |
+
# Resolution: Rescheduled backup to 05:00 UTC. No further occurrences.
|
| 64 |
+
|
| 65 |
+
2024-01-11 05:00:00 UTC — Backup rescheduled
|
| 66 |
+
2024-01-11 onwards — No Hold Timer Expiry events on CORE-RTR-01/02
|
| 67 |
+
|
| 68 |
+
=============================================================================
|
| 69 |
+
WEEK 2 — INTERFACE FLAP CAUSING BGP RESET
|
| 70 |
+
=============================================================================
|
| 71 |
+
|
| 72 |
+
2024-01-09 11:22:33 UTC EDGE-RTR-01: %LINK-3-UPDOWN: Interface GigabitEthernet0/0, changed state to down
|
| 73 |
+
2024-01-09 11:22:33 UTC EDGE-RTR-01: %BGP-5-ADJCHANGE: neighbor 203.0.113.1 Down Interface flap
|
| 74 |
+
2024-01-09 11:22:33 UTC EDGE-RTR-01: %LINK-3-UPDOWN: Interface GigabitEthernet0/0, changed state to up
|
| 75 |
+
2024-01-09 11:22:35 UTC EDGE-RTR-01: %BGP-5-ADJCHANGE: neighbor 203.0.113.1 Up
|
| 76 |
+
# Physical layer flap on upstream interface. Duration: 2 seconds.
|
| 77 |
+
# Cause: Fiber patch cable reseated during data center maintenance.
|
| 78 |
+
# BGP convergence time: 2 seconds (BFD not configured on this link).
|
| 79 |
+
|
| 80 |
+
2024-01-09 11:22:33 UTC CORE-RTR-01: show ip bgp summary excerpt:
|
| 81 |
+
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
|
| 82 |
+
10.0.0.2 4 65001 45231 45219 982345 0 0 3d14h 145032
|
| 83 |
+
172.16.0.1 4 65001 12043 12039 982345 0 0 3d14h 45231
|
| 84 |
+
203.0.113.1 4 65002 89321 89315 982345 0 0 00:00:03 312045
|
| 85 |
+
198.51.100.1 4 65003 67234 67228 982345 0 0 5d02h 289034
|
| 86 |
+
# Note 203.0.113.1 shows uptime 00:00:03 — just reestablished after flap.
|
| 87 |
+
|
| 88 |
+
=============================================================================
|
| 89 |
+
WEEK 3 — PREFIX LIMIT INCIDENT
|
| 90 |
+
=============================================================================
|
| 91 |
+
|
| 92 |
+
2024-01-15 08:45:22 UTC EDGE-RTR-02: %BGP-4-MAXPFX: No. of prefix received from 203.0.113.5 (267812) reaches 80% of limit 325000
|
| 93 |
+
# Warning: Prefix count at 80% of limit. ISP-02 prefix count growing.
|
| 94 |
+
|
| 95 |
+
2024-01-15 08:46:11 UTC EDGE-RTR-02: %BGP-4-MAXPFX: No. of prefix received from 203.0.113.5 (289034) reaches 89% of limit 325000
|
| 96 |
+
|
| 97 |
+
2024-01-15 08:47:03 UTC EDGE-RTR-02: %BGP-3-MAXPFXEXCEED: No. of prefix received from 203.0.113.5 (332411) exceeds limit 325000
|
| 98 |
+
2024-01-15 08:47:03 UTC EDGE-RTR-02: %BGP-5-ADJCHANGE: neighbor 203.0.113.5 Down MAXPFX exceeded
|
| 99 |
+
# Session torn down! ISP-02 leaked a full routing table.
|
| 100 |
+
# Full internet BGP table: ~900K+ routes. Our limit was 325K.
|
| 101 |
+
# Investigation: ISP-02 suffered route leak from their upstream — all routes redistributed.
|
| 102 |
+
|
| 103 |
+
2024-01-15 09:15:00 UTC — ISP-02 fixed route leak, prefix count normalized
|
| 104 |
+
2024-01-15 09:15:44 UTC EDGE-RTR-02: clear ip bgp 203.0.113.5 executed
|
| 105 |
+
2024-01-15 09:15:50 UTC EDGE-RTR-02: %BGP-5-ADJCHANGE: neighbor 203.0.113.5 Up
|
| 106 |
+
# Session reestablished. Lesson: maximum-prefix saved us from memory exhaustion.
|
| 107 |
+
|
| 108 |
+
=============================================================================
|
| 109 |
+
WEEK 3 — BGP AUTHENTICATION MISMATCH
|
| 110 |
+
=============================================================================
|
| 111 |
+
|
| 112 |
+
2024-01-16 14:22:45 UTC CORE-RTR-01: %TCP-6-BADAUTH: Invalid MD5 digest from 10.0.0.2(49301) to 10.0.0.1(179)
|
| 113 |
+
2024-01-16 14:22:45 UTC CORE-RTR-01: %TCP-6-BADAUTH: Invalid MD5 digest from 10.0.0.2(49301) to 10.0.0.1(179)
|
| 114 |
+
2024-01-16 14:22:45 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Down BGP authentication failure
|
| 115 |
+
# Invalid MD5 — passwords don't match. CORE-RTR-02 had a password change.
|
| 116 |
+
# Change management error: password updated on RTR-02 but not RTR-01.
|
| 117 |
+
# Fix: Updated password on RTR-01 to match.
|
| 118 |
+
|
| 119 |
+
2024-01-16 14:35:12 UTC CORE-RTR-01: clear ip bgp 10.0.0.2
|
| 120 |
+
2024-01-16 14:35:18 UTC CORE-RTR-01: %BGP-5-ADJCHANGE: neighbor 10.0.0.2 Up
|
| 121 |
+
|
| 122 |
+
=============================================================================
|
| 123 |
+
WEEK 4 — ROUTE REFLECTOR CLUSTER-ID ISSUE
|
| 124 |
+
=============================================================================
|
| 125 |
+
|
| 126 |
+
2024-01-22 09:11:22 UTC CORE-RTR-01: %BGP-3-CLUSTER_LIST_LOOP: Cluster list loop detected for prefix 192.168.0.0/16
|
| 127 |
+
2024-01-22 09:11:22 UTC CORE-RTR-01: %BGP-3-CLUSTER_LIST_LOOP: Cluster list loop detected for prefix 192.168.1.0/24
|
| 128 |
+
# RR loop detection triggered. Missing cluster-id on one of the RRs.
|
| 129 |
+
# CORE-RTR-02 was acting as RR but had no cluster-id configured.
|
| 130 |
+
# Without cluster-id, multiple RRs in the same cluster cause duplicate originator loops.
|
| 131 |
+
# Fix: Added bgp cluster-id 1 to CORE-RTR-02.
|
| 132 |
+
# Reference: RFC 4456 Section 8
|
| 133 |
+
|
| 134 |
+
2024-01-22 09:45:00 UTC — cluster-id added to CORE-RTR-02
|
| 135 |
+
2024-01-22 09:45:11 UTC CORE-RTR-01: clear ip bgp * soft
|
| 136 |
+
2024-01-22 09:45:30 UTC — Cluster list loop messages ceased
|
| 137 |
+
|
| 138 |
+
=============================================================================
|
| 139 |
+
MONTHLY SUMMARY — INCIDENT STATISTICS
|
| 140 |
+
=============================================================================
|
| 141 |
+
|
| 142 |
+
Total BGP session resets: 23 events over 30 days
|
| 143 |
+
|
| 144 |
+
Breakdown by cause:
|
| 145 |
+
Hold Timer Expired: 11 events (47.8%) — MOST COMMON
|
| 146 |
+
Interface flap: 4 events (17.4%)
|
| 147 |
+
Authentication mismatch: 3 events (13.0%)
|
| 148 |
+
Administrative reset (clear): 3 events (13.0%)
|
| 149 |
+
Peer AS mismatch: 1 event ( 4.3%)
|
| 150 |
+
Maximum prefix exceeded: 1 event ( 4.3%)
|
| 151 |
+
|
| 152 |
+
Average session downtime by cause:
|
| 153 |
+
Hold Timer Expired: 28 seconds
|
| 154 |
+
Interface flap: 8 seconds
|
| 155 |
+
Authentication issue: 12 minutes (requires manual fix)
|
| 156 |
+
Peer AS mismatch: 37 minutes (requires ISP coordination)
|
| 157 |
+
Max prefix exceeded: 28 minutes (requires ISP to fix leak)
|
| 158 |
+
|
| 159 |
+
Most stable peers (no resets):
|
| 160 |
+
- 10.0.0.2 CORE-RTR-02 iBGP: 1 reset (timer) + 1 reset (auth mismatch)
|
| 161 |
+
- 198.51.100.1 ISP-01 eBGP: 1 reset (auth incident)
|
| 162 |
+
|
| 163 |
+
Most problematic peers:
|
| 164 |
+
- 203.0.113.5 ISP-02 eBGP: 3 resets (AS mismatch, max-prefix, auth)
|
| 165 |
+
- 203.0.113.1 ISP-03 eBGP: 4 resets (all interface flap related)
|
| 166 |
+
|
| 167 |
+
Recommendations from 30-day analysis:
|
| 168 |
+
1. Increase hold timer from 30s to 90s to reduce false Hold Timer Expiry
|
| 169 |
+
2. Configure BFD on physical eBGP links for faster failure detection
|
| 170 |
+
3. Increase max-prefix limit on ISP-02 to 500K with 80% warning threshold
|
| 171 |
+
4. Schedule backup jobs at 05:00 UTC — CPU impact confirmed during 03:45 UTC slot
|
| 172 |
+
5. Implement change management procedure for BGP auth password updates (both sides simultaneously)
|
| 173 |
+
6. Add cluster-id to all Route Reflectors immediately
|
| 174 |
+
|
| 175 |
+
BGP Table Statistics (end of month):
|
| 176 |
+
Total prefixes in RIB: 487,231
|
| 177 |
+
iBGP learned: 45,032
|
| 178 |
+
eBGP learned (ISP-01): 289,034
|
| 179 |
+
eBGP learned (ISP-02): 312,045
|
| 180 |
+
eBGP learned (ISP-03): 145,231
|
| 181 |
+
Locally originated: 12
|
| 182 |
+
|
| 183 |
+
Router Memory Usage:
|
| 184 |
+
CORE-RTR-01: 4.2GB / 8GB (BGP table: 1.8GB)
|
| 185 |
+
CORE-RTR-02: 4.1GB / 8GB (BGP table: 1.8GB)
|
| 186 |
+
EDGE-RTR-01: 2.8GB / 8GB (BGP table: 1.2GB)
|
| 187 |
+
EDGE-RTR-02: 3.1GB / 8GB (BGP table: 1.4GB)
|
ingest.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
ingest.py — Build FAISS vector index from BGP documentation.
|
| 3 |
+
|
| 4 |
+
Run this ONCE locally before deploying to HuggingFace Spaces:
|
| 5 |
+
python ingest.py
|
| 6 |
+
|
| 7 |
+
Output: faiss_index/index.faiss + faiss_index/index.pkl
|
| 8 |
+
Commit both files to your repo — the Space loads them at startup.
|
| 9 |
+
|
| 10 |
+
WHY PRE-BUILD?
|
| 11 |
+
- Building the index requires downloading ~90MB sentence-transformers model
|
| 12 |
+
and embedding every chunk. On HF free CPU tier this takes 3-5 minutes
|
| 13 |
+
and risks OOM errors. Pre-building means the Space starts in ~3 seconds.
|
| 14 |
+
- Pattern: compute expensive artifacts locally, ship the result.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import os
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
|
| 20 |
+
from langchain_community.document_loaders import TextLoader, DirectoryLoader
|
| 21 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 22 |
+
from langchain_huggingface import HuggingFaceEmbeddings
|
| 23 |
+
from langchain_community.vectorstores import FAISS
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
# ── Configuration ────────────────────────────────────────────────────────────
|
| 27 |
+
|
| 28 |
+
DATA_DIRS = ["data/docs", "data/telemetry"]
|
| 29 |
+
INDEX_DIR = "faiss_index"
|
| 30 |
+
EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
|
| 31 |
+
CHUNK_SIZE = 500
|
| 32 |
+
CHUNK_OVERLAP = 50
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# ── Load documents ────────────────────────────────────────────────────────────
|
| 36 |
+
|
| 37 |
+
def load_documents(data_dirs: list[str]) -> list:
|
| 38 |
+
"""Load all .txt files from the given directories."""
|
| 39 |
+
all_docs = []
|
| 40 |
+
for data_dir in data_dirs:
|
| 41 |
+
if not os.path.exists(data_dir):
|
| 42 |
+
print(f" ⚠️ Directory not found, skipping: {data_dir}")
|
| 43 |
+
continue
|
| 44 |
+
loader = DirectoryLoader(
|
| 45 |
+
data_dir,
|
| 46 |
+
glob="**/*.txt",
|
| 47 |
+
loader_cls=TextLoader,
|
| 48 |
+
loader_kwargs={"encoding": "utf-8"},
|
| 49 |
+
show_progress=False,
|
| 50 |
+
)
|
| 51 |
+
docs = loader.load()
|
| 52 |
+
print(f" 📂 {data_dir}: {len(docs)} file(s) loaded")
|
| 53 |
+
all_docs.extend(docs)
|
| 54 |
+
return all_docs
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# ── Main ──────────────────────────────────────────────────────────────────────
|
| 58 |
+
|
| 59 |
+
def main():
|
| 60 |
+
print("=" * 60)
|
| 61 |
+
print("BGP RAG — FAISS Index Builder")
|
| 62 |
+
print("=" * 60)
|
| 63 |
+
|
| 64 |
+
# 1. Load raw documents
|
| 65 |
+
print("\n[1/4] Loading documents...")
|
| 66 |
+
docs = load_documents(DATA_DIRS)
|
| 67 |
+
if not docs:
|
| 68 |
+
raise RuntimeError("No documents found. Check data/ directory.")
|
| 69 |
+
print(f" ✅ Total documents loaded: {len(docs)}")
|
| 70 |
+
|
| 71 |
+
# 2. Split into chunks
|
| 72 |
+
print(f"\n[2/4] Splitting into chunks (size={CHUNK_SIZE}, overlap={CHUNK_OVERLAP})...")
|
| 73 |
+
splitter = RecursiveCharacterTextSplitter(
|
| 74 |
+
chunk_size=CHUNK_SIZE,
|
| 75 |
+
chunk_overlap=CHUNK_OVERLAP,
|
| 76 |
+
length_function=len,
|
| 77 |
+
separators=["\n\n", "\n", " ", ""],
|
| 78 |
+
)
|
| 79 |
+
chunks = splitter.split_documents(docs)
|
| 80 |
+
print(f" ✅ Chunks created: {len(chunks)}")
|
| 81 |
+
print(f" 📊 Avg chunk size: {sum(len(c.page_content) for c in chunks) // len(chunks)} chars")
|
| 82 |
+
|
| 83 |
+
# 3. Create embeddings
|
| 84 |
+
print(f"\n[3/4] Loading embedding model: {EMBEDDING_MODEL}")
|
| 85 |
+
print(" (First run downloads ~90MB model — subsequent runs use cache)")
|
| 86 |
+
embeddings = HuggingFaceEmbeddings(
|
| 87 |
+
model_name=EMBEDDING_MODEL,
|
| 88 |
+
model_kwargs={"device": "cpu"},
|
| 89 |
+
encode_kwargs={"normalize_embeddings": True},
|
| 90 |
+
)
|
| 91 |
+
print(" ✅ Embedding model loaded")
|
| 92 |
+
|
| 93 |
+
# 4. Build and save FAISS index
|
| 94 |
+
print(f"\n[4/4] Building FAISS index and saving to {INDEX_DIR}/...")
|
| 95 |
+
os.makedirs(INDEX_DIR, exist_ok=True)
|
| 96 |
+
vectorstore = FAISS.from_documents(chunks, embeddings)
|
| 97 |
+
vectorstore.save_local(INDEX_DIR)
|
| 98 |
+
|
| 99 |
+
# Verify files were written
|
| 100 |
+
index_file = Path(INDEX_DIR) / "index.faiss"
|
| 101 |
+
pkl_file = Path(INDEX_DIR) / "index.pkl"
|
| 102 |
+
if index_file.exists() and pkl_file.exists():
|
| 103 |
+
size_mb = (index_file.stat().st_size + pkl_file.stat().st_size) / (1024 * 1024)
|
| 104 |
+
print(f" ✅ Saved: {INDEX_DIR}/index.faiss")
|
| 105 |
+
print(f" ✅ Saved: {INDEX_DIR}/index.pkl")
|
| 106 |
+
print(f" 📦 Total index size: {size_mb:.2f} MB")
|
| 107 |
+
else:
|
| 108 |
+
raise RuntimeError("Index files not found after save — check permissions.")
|
| 109 |
+
|
| 110 |
+
print("\n" + "=" * 60)
|
| 111 |
+
print("✅ FAISS index built successfully!")
|
| 112 |
+
print(f" Documents: {len(docs)}")
|
| 113 |
+
print(f" Chunks: {len(chunks)}")
|
| 114 |
+
print(f" Location: {INDEX_DIR}/")
|
| 115 |
+
print("\nNext steps:")
|
| 116 |
+
print(" 1. git add faiss_index/")
|
| 117 |
+
print(" 2. git commit -m 'Add pre-built FAISS index'")
|
| 118 |
+
print(" 3. Push to HuggingFace Space")
|
| 119 |
+
print("=" * 60)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
if __name__ == "__main__":
|
| 123 |
+
main()
|
rag_chain.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
rag_chain.py — RAG chain using Groq (Llama 3.1) + pre-built FAISS index.
|
| 3 |
+
|
| 4 |
+
HOW API KEY INJECTION WORKS:
|
| 5 |
+
os.environ.get("GROQ_API_KEY") reads the key from the process environment.
|
| 6 |
+
On HuggingFace Spaces, you set this in:
|
| 7 |
+
Space Settings → Variables and Secrets → New Secret → GROQ_API_KEY
|
| 8 |
+
HF injects it as an environment variable at container startup.
|
| 9 |
+
The key NEVER appears in your code or git history — only in HF's encrypted vault.
|
| 10 |
+
This is identical to how AWS Secrets Manager, GCP Secret Manager, and
|
| 11 |
+
Azure Key Vault work: code references a name, runtime provides the value.
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
import os
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
|
| 17 |
+
from langchain_groq import ChatGroq
|
| 18 |
+
from langchain_huggingface import HuggingFaceEmbeddings
|
| 19 |
+
from langchain_community.vectorstores import FAISS
|
| 20 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 21 |
+
from langchain_core.output_parsers import StrOutputParser
|
| 22 |
+
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
# ── Configuration ─────────────────────────────────────────────────────────────
|
| 26 |
+
|
| 27 |
+
INDEX_DIR = "faiss_index"
|
| 28 |
+
EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
|
| 29 |
+
GROQ_MODEL = "llama-3.1-8b-instant"
|
| 30 |
+
TOP_K_CHUNKS = 4
|
| 31 |
+
|
| 32 |
+
BGP_PROMPT = ChatPromptTemplate.from_messages([
|
| 33 |
+
("system",
|
| 34 |
+
"You are a Cisco network engineer specialising in BGP troubleshooting.\n"
|
| 35 |
+
"Answer questions based only on the provided documentation and telemetry logs.\n"
|
| 36 |
+
"Always suggest the relevant show command to verify the issue.\n"
|
| 37 |
+
"If the answer is not in the context, say clearly: "
|
| 38 |
+
"'This information is not in the knowledge base.'\n\n"
|
| 39 |
+
"Context:\n{context}"),
|
| 40 |
+
("human", "{input}"),
|
| 41 |
+
])
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# ── Load embeddings (cached after first call) ─────────────────────────────────
|
| 45 |
+
|
| 46 |
+
_embeddings = None
|
| 47 |
+
|
| 48 |
+
def get_embeddings() -> HuggingFaceEmbeddings:
|
| 49 |
+
"""Return cached HuggingFaceEmbeddings instance."""
|
| 50 |
+
global _embeddings
|
| 51 |
+
if _embeddings is None:
|
| 52 |
+
_embeddings = HuggingFaceEmbeddings(
|
| 53 |
+
model_name=EMBEDDING_MODEL,
|
| 54 |
+
model_kwargs={"device": "cpu"},
|
| 55 |
+
encode_kwargs={"normalize_embeddings": True},
|
| 56 |
+
)
|
| 57 |
+
return _embeddings
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
# ── Load FAISS vector store ───────────────────────────────────────────────────
|
| 61 |
+
|
| 62 |
+
_vectorstore = None
|
| 63 |
+
|
| 64 |
+
def _build_index():
|
| 65 |
+
"""Build FAISS index from data/ files. Called automatically if index is missing."""
|
| 66 |
+
from langchain_community.document_loaders import DirectoryLoader, TextLoader
|
| 67 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 68 |
+
|
| 69 |
+
print("Building FAISS index from documents...")
|
| 70 |
+
all_docs = []
|
| 71 |
+
for data_dir in ["data/docs", "data/telemetry"]:
|
| 72 |
+
if not os.path.exists(data_dir):
|
| 73 |
+
continue
|
| 74 |
+
loader = DirectoryLoader(
|
| 75 |
+
data_dir, glob="**/*.txt", loader_cls=TextLoader,
|
| 76 |
+
loader_kwargs={"encoding": "utf-8"}, show_progress=False,
|
| 77 |
+
)
|
| 78 |
+
all_docs.extend(loader.load())
|
| 79 |
+
|
| 80 |
+
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
|
| 81 |
+
chunks = splitter.split_documents(all_docs)
|
| 82 |
+
|
| 83 |
+
vs = FAISS.from_documents(chunks, get_embeddings())
|
| 84 |
+
os.makedirs(INDEX_DIR, exist_ok=True)
|
| 85 |
+
vs.save_local(INDEX_DIR)
|
| 86 |
+
print(f"Index built — {len(chunks)} chunks saved to {INDEX_DIR}/")
|
| 87 |
+
return vs
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def get_vectorstore() -> FAISS:
|
| 91 |
+
"""Load FAISS index, building it first if it doesn't exist."""
|
| 92 |
+
global _vectorstore
|
| 93 |
+
if _vectorstore is None:
|
| 94 |
+
if not Path(INDEX_DIR).exists():
|
| 95 |
+
# Auto-build on first run (e.g. HF Spaces where binary files can't be committed)
|
| 96 |
+
_vectorstore = _build_index()
|
| 97 |
+
else:
|
| 98 |
+
_vectorstore = FAISS.load_local(
|
| 99 |
+
INDEX_DIR,
|
| 100 |
+
get_embeddings(),
|
| 101 |
+
allow_dangerous_deserialization=True,
|
| 102 |
+
)
|
| 103 |
+
return _vectorstore
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# ── Build RAG chain ───────────────────────────────────────────────────────────
|
| 107 |
+
|
| 108 |
+
_qa_chain = None
|
| 109 |
+
|
| 110 |
+
def _format_docs(docs: list) -> str:
|
| 111 |
+
"""Concatenate document chunks into a single context string."""
|
| 112 |
+
return "\n\n".join(doc.page_content for doc in docs)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def get_qa_chain():
|
| 116 |
+
"""Build and cache the RAG chain using pure LCEL (langchain-core only)."""
|
| 117 |
+
global _qa_chain
|
| 118 |
+
if _qa_chain is None:
|
| 119 |
+
llm = ChatGroq(
|
| 120 |
+
model=GROQ_MODEL,
|
| 121 |
+
api_key=os.environ.get("GROQ_API_KEY"),
|
| 122 |
+
temperature=0.1,
|
| 123 |
+
max_tokens=1024,
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
retriever = get_vectorstore().as_retriever(
|
| 127 |
+
search_type="similarity",
|
| 128 |
+
search_kwargs={"k": TOP_K_CHUNKS},
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
# LCEL chain — runs retriever and passthrough in parallel, then calls LLM
|
| 132 |
+
# RunnableParallel fetches context docs AND passes the question through simultaneously
|
| 133 |
+
# Result: {"answer": "...", "context": [doc, doc, ...]}
|
| 134 |
+
_qa_chain = RunnableParallel(
|
| 135 |
+
answer=(
|
| 136 |
+
{"context": retriever | _format_docs, "input": RunnablePassthrough()}
|
| 137 |
+
| BGP_PROMPT
|
| 138 |
+
| llm
|
| 139 |
+
| StrOutputParser()
|
| 140 |
+
),
|
| 141 |
+
context=retriever,
|
| 142 |
+
)
|
| 143 |
+
return _qa_chain
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
# ── Public API ────────────────────────────────────────────────────────────────
|
| 147 |
+
|
| 148 |
+
def query_bgp(question: str) -> dict:
|
| 149 |
+
"""
|
| 150 |
+
Run a BGP question through the RAG pipeline.
|
| 151 |
+
|
| 152 |
+
Returns:
|
| 153 |
+
{
|
| 154 |
+
"answer": str,
|
| 155 |
+
"sources": list[str], # Unique filenames of retrieved docs
|
| 156 |
+
"source_documents": list # Raw LangChain Document objects
|
| 157 |
+
}
|
| 158 |
+
"""
|
| 159 |
+
chain = get_qa_chain()
|
| 160 |
+
# LCEL chain takes the question string directly
|
| 161 |
+
# Returns {"answer": str, "context": list[Document]}
|
| 162 |
+
result = chain.invoke(question)
|
| 163 |
+
|
| 164 |
+
source_docs = result.get("context", [])
|
| 165 |
+
sources = list(dict.fromkeys(
|
| 166 |
+
Path(doc.metadata.get("source", "unknown")).name
|
| 167 |
+
for doc in source_docs
|
| 168 |
+
))
|
| 169 |
+
|
| 170 |
+
return {
|
| 171 |
+
"answer": result["answer"],
|
| 172 |
+
"sources": sources,
|
| 173 |
+
"source_documents": source_docs,
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def get_chunk_count() -> int:
|
| 178 |
+
"""Return total number of chunks in the FAISS index (for sidebar display)."""
|
| 179 |
+
try:
|
| 180 |
+
vs = get_vectorstore()
|
| 181 |
+
return vs.index.ntotal
|
| 182 |
+
except Exception:
|
| 183 |
+
return 0
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
# ── Quick test ────────────────────────────────────────────────────────────────
|
| 187 |
+
|
| 188 |
+
if __name__ == "__main__":
|
| 189 |
+
import sys
|
| 190 |
+
|
| 191 |
+
if not os.environ.get("GROQ_API_KEY"):
|
| 192 |
+
print("❌ GROQ_API_KEY not set.")
|
| 193 |
+
print(" Export it: export GROQ_API_KEY=gsk_...")
|
| 194 |
+
sys.exit(1)
|
| 195 |
+
|
| 196 |
+
print("Loading RAG chain...")
|
| 197 |
+
test_question = "Why is my BGP neighbor stuck in IDLE state?"
|
| 198 |
+
print(f"\nQuestion: {test_question}\n")
|
| 199 |
+
|
| 200 |
+
result = query_bgp(test_question)
|
| 201 |
+
print("Answer:")
|
| 202 |
+
print(result["answer"])
|
| 203 |
+
print(f"\nSources retrieved: {result['sources']}")
|
requirements.txt
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BGP RAG Chatbot — Cloud Edition
|
| 2 |
+
# HuggingFace Spaces auto-installs these from requirements.txt at deploy time.
|
| 3 |
+
#
|
| 4 |
+
# WHY torch AND transformers?
|
| 5 |
+
# sentence-transformers (used for HuggingFaceEmbeddings) is built on top of
|
| 6 |
+
# the transformers library, which in turn requires PyTorch as its compute backend.
|
| 7 |
+
# Even though we're not running a local LLM — Groq handles inference remotely —
|
| 8 |
+
# the embedding model (all-MiniLM-L6-v2) runs locally inside the Space to convert
|
| 9 |
+
# questions and documents into vectors. That local embedding step needs torch.
|
| 10 |
+
# torch on CPU (faiss-cpu) is sufficient; no GPU required.
|
| 11 |
+
|
| 12 |
+
# ── LangChain core ────────────────────────────────────────────────────────────
|
| 13 |
+
langchain>=0.2.0
|
| 14 |
+
langchain-community>=0.2.0
|
| 15 |
+
langchain-text-splitters>=0.2.0
|
| 16 |
+
langchain-groq>=0.1.6
|
| 17 |
+
langchain-huggingface>=0.0.3
|
| 18 |
+
|
| 19 |
+
# ── LLM inference (cloud) ────────────────────────────────────────────────────
|
| 20 |
+
groq>=0.9.0
|
| 21 |
+
|
| 22 |
+
# ── Embeddings (local, CPU) ──────────────────────────────────────────────────
|
| 23 |
+
sentence-transformers>=2.7.0
|
| 24 |
+
transformers>=4.40.0
|
| 25 |
+
torch>=2.2.0
|
| 26 |
+
torchvision>=0.17.0
|
| 27 |
+
|
| 28 |
+
# ── Vector store ─────────────────────────────────────────────────────────────
|
| 29 |
+
faiss-cpu>=1.8.0
|
| 30 |
+
|
| 31 |
+
# ── UI ────────────────────────────────────────────────────────────────────────
|
| 32 |
+
streamlit>=1.35.0
|
| 33 |
+
python-dotenv>=1.0.0
|
| 34 |
+
python-dotenv
|