VP21 commited on
Commit
491f25a
·
0 Parent(s):

BGP RAG cloud chatbot — initial commit

Browse files
.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