Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* VPN Related functions |
3 | | * Copyright (C) 2017 6WIND |
4 | | * |
5 | | * This file is part of FRRouting |
6 | | */ |
7 | | |
8 | | #include <zebra.h> |
9 | | #include "command.h" |
10 | | #include "prefix.h" |
11 | | #include "lib/json.h" |
12 | | #include "lib/printfrr.h" |
13 | | |
14 | | #include "bgpd/bgpd.h" |
15 | | #include "bgpd/bgp_route.h" |
16 | | #include "bgpd/bgp_table.h" |
17 | | #include "bgpd/bgp_attr.h" |
18 | | #include "bgpd/bgp_mplsvpn.h" |
19 | | #include "bgpd/bgp_vpn.h" |
20 | | #include "bgpd/bgp_updgrp.h" |
21 | | |
22 | | int show_adj_route_vpn(struct vty *vty, struct peer *peer, |
23 | | struct prefix_rd *prd, afi_t afi, safi_t safi, |
24 | | bool use_json) |
25 | 0 | { |
26 | 0 | struct bgp *bgp; |
27 | 0 | struct bgp_table *table; |
28 | 0 | struct bgp_dest *dest; |
29 | 0 | struct bgp_dest *rm; |
30 | 0 | int rd_header; |
31 | 0 | int header = 1; |
32 | 0 | json_object *json = NULL; |
33 | 0 | json_object *json_scode = NULL; |
34 | 0 | json_object *json_ocode = NULL; |
35 | 0 | json_object *json_adv = NULL; |
36 | 0 | json_object *json_routes = NULL; |
37 | 0 | char rd_str[BUFSIZ]; |
38 | 0 | unsigned long output_count = 0; |
39 | |
|
40 | 0 | bgp = bgp_get_default(); |
41 | 0 | if (bgp == NULL) { |
42 | 0 | if (!use_json) |
43 | 0 | vty_out(vty, "No BGP process is configured\n"); |
44 | 0 | else |
45 | 0 | vty_out(vty, "{}\n"); |
46 | 0 | return CMD_WARNING; |
47 | 0 | } |
48 | | |
49 | 0 | if (use_json) { |
50 | 0 | json_scode = json_object_new_object(); |
51 | 0 | json_ocode = json_object_new_object(); |
52 | 0 | json = json_object_new_object(); |
53 | 0 | json_adv = json_object_new_object(); |
54 | |
|
55 | 0 | json_object_string_add(json_scode, "suppressed", "s"); |
56 | 0 | json_object_string_add(json_scode, "damped", "d"); |
57 | 0 | json_object_string_add(json_scode, "history", "h"); |
58 | 0 | json_object_string_add(json_scode, "valid", "*"); |
59 | 0 | json_object_string_add(json_scode, "best", ">"); |
60 | 0 | json_object_string_add(json_scode, "internal", "i"); |
61 | |
|
62 | 0 | json_object_string_add(json_ocode, "igp", "i"); |
63 | 0 | json_object_string_add(json_ocode, "egp", "e"); |
64 | 0 | json_object_string_add(json_ocode, "incomplete", "?"); |
65 | 0 | } |
66 | |
|
67 | 0 | for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; |
68 | 0 | dest = bgp_route_next(dest)) { |
69 | 0 | const struct prefix *dest_p = bgp_dest_get_prefix(dest); |
70 | |
|
71 | 0 | if (prd && memcmp(dest_p->u.val, prd->val, 8) != 0) |
72 | 0 | continue; |
73 | | |
74 | 0 | table = bgp_dest_get_bgp_table_info(dest); |
75 | 0 | if (table == NULL) |
76 | 0 | continue; |
77 | | |
78 | | /* |
79 | | * Initialize variables for each RD |
80 | | * All prefixes under an RD is aggregated within "json_routes" |
81 | | */ |
82 | 0 | rd_header = 1; |
83 | 0 | memset(rd_str, 0, sizeof(rd_str)); |
84 | 0 | json_routes = NULL; |
85 | |
|
86 | 0 | for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) { |
87 | 0 | struct bgp_adj_out *adj = NULL; |
88 | 0 | struct attr *attr = NULL; |
89 | 0 | struct peer_af *paf = NULL; |
90 | |
|
91 | 0 | RB_FOREACH (adj, bgp_adj_out_rb, &rm->adj_out) |
92 | 0 | SUBGRP_FOREACH_PEER (adj->subgroup, paf) { |
93 | 0 | if (paf->peer != peer || !adj->attr) |
94 | 0 | continue; |
95 | | |
96 | 0 | attr = adj->attr; |
97 | 0 | break; |
98 | 0 | } |
99 | |
|
100 | 0 | if (bgp_dest_get_bgp_path_info(rm) == NULL) |
101 | 0 | continue; |
102 | | |
103 | 0 | if (!attr) |
104 | 0 | continue; |
105 | | |
106 | 0 | if (header) { |
107 | 0 | if (use_json) { |
108 | 0 | json_object_int_add( |
109 | 0 | json, "bgpTableVersion", 0); |
110 | 0 | json_object_string_addf( |
111 | 0 | json, "bgpLocalRouterId", |
112 | 0 | "%pI4", &bgp->router_id); |
113 | 0 | json_object_int_add( |
114 | 0 | json, |
115 | 0 | "defaultLocPrf", |
116 | 0 | bgp->default_local_pref); |
117 | 0 | json_object_int_add( |
118 | 0 | json, "localAS", |
119 | 0 | bgp->as); |
120 | 0 | json_object_object_add(json, |
121 | 0 | "bgpStatusCodes", |
122 | 0 | json_scode); |
123 | 0 | json_object_object_add(json, |
124 | 0 | "bgpOriginCodes", |
125 | 0 | json_ocode); |
126 | 0 | } else { |
127 | 0 | vty_out(vty, |
128 | 0 | "BGP table version is 0, local router ID is %pI4\n", |
129 | 0 | &bgp->router_id); |
130 | 0 | vty_out(vty, "Default local pref %u, ", |
131 | 0 | bgp->default_local_pref); |
132 | 0 | vty_out(vty, "local AS %u\n", bgp->as); |
133 | 0 | vty_out(vty, |
134 | 0 | "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n"); |
135 | 0 | vty_out(vty, |
136 | 0 | "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"); |
137 | 0 | vty_out(vty, V4_HEADER); |
138 | 0 | } |
139 | 0 | header = 0; |
140 | 0 | } |
141 | |
|
142 | 0 | if (rd_header) { |
143 | 0 | uint16_t type; |
144 | 0 | struct rd_as rd_as = {0}; |
145 | 0 | struct rd_ip rd_ip = {0}; |
146 | 0 | #ifdef ENABLE_BGP_VNC |
147 | 0 | struct rd_vnc_eth rd_vnc_eth = {0}; |
148 | 0 | #endif |
149 | 0 | const uint8_t *pnt; |
150 | |
|
151 | 0 | pnt = dest_p->u.val; |
152 | | |
153 | | /* Decode RD type. */ |
154 | 0 | type = decode_rd_type(pnt); |
155 | | /* Decode RD value. */ |
156 | 0 | if (type == RD_TYPE_AS) |
157 | 0 | decode_rd_as(pnt + 2, &rd_as); |
158 | 0 | else if (type == RD_TYPE_AS4) |
159 | 0 | decode_rd_as4(pnt + 2, &rd_as); |
160 | 0 | else if (type == RD_TYPE_IP) |
161 | 0 | decode_rd_ip(pnt + 2, &rd_ip); |
162 | 0 | #ifdef ENABLE_BGP_VNC |
163 | 0 | else if (type == RD_TYPE_VNC_ETH) |
164 | 0 | decode_rd_vnc_eth(pnt, &rd_vnc_eth); |
165 | 0 | #endif |
166 | 0 | if (use_json) { |
167 | 0 | json_routes = json_object_new_object(); |
168 | |
|
169 | 0 | if (type == RD_TYPE_AS |
170 | 0 | || type == RD_TYPE_AS4) |
171 | 0 | snprintf(rd_str, sizeof(rd_str), |
172 | 0 | "%u:%d", rd_as.as, |
173 | 0 | rd_as.val); |
174 | 0 | else if (type == RD_TYPE_IP) |
175 | 0 | snprintfrr(rd_str, |
176 | 0 | sizeof(rd_str), |
177 | 0 | "%pI4:%d", &rd_ip.ip, |
178 | 0 | rd_ip.val); |
179 | 0 | json_object_string_add( |
180 | 0 | json_routes, |
181 | 0 | "rd", rd_str); |
182 | 0 | } else { |
183 | 0 | vty_out(vty, "Route Distinguisher: "); |
184 | |
|
185 | 0 | if (type == RD_TYPE_AS |
186 | 0 | || type == RD_TYPE_AS4) |
187 | 0 | vty_out(vty, "%u:%d", rd_as.as, |
188 | 0 | rd_as.val); |
189 | 0 | else if (type == RD_TYPE_IP) |
190 | 0 | vty_out(vty, "%pI4:%d", |
191 | 0 | &rd_ip.ip, rd_ip.val); |
192 | 0 | #ifdef ENABLE_BGP_VNC |
193 | 0 | else if (type == RD_TYPE_VNC_ETH) |
194 | 0 | vty_out(vty, |
195 | 0 | "%u:%02x:%02x:%02x:%02x:%02x:%02x", |
196 | 0 | rd_vnc_eth.local_nve_id, |
197 | 0 | rd_vnc_eth.macaddr |
198 | 0 | .octet[0], |
199 | 0 | rd_vnc_eth.macaddr |
200 | 0 | .octet[1], |
201 | 0 | rd_vnc_eth.macaddr |
202 | 0 | .octet[2], |
203 | 0 | rd_vnc_eth.macaddr |
204 | 0 | .octet[3], |
205 | 0 | rd_vnc_eth.macaddr |
206 | 0 | .octet[4], |
207 | 0 | rd_vnc_eth.macaddr |
208 | 0 | .octet[5]); |
209 | 0 | #endif |
210 | |
|
211 | 0 | vty_out(vty, "\n"); |
212 | 0 | } |
213 | 0 | rd_header = 0; |
214 | 0 | } |
215 | 0 | route_vty_out_tmp(vty, rm, bgp_dest_get_prefix(rm), |
216 | 0 | attr, safi, use_json, json_routes, |
217 | 0 | false); |
218 | 0 | output_count++; |
219 | 0 | } |
220 | |
|
221 | 0 | if (use_json && json_routes) |
222 | 0 | json_object_object_add(json_adv, rd_str, json_routes); |
223 | 0 | } |
224 | |
|
225 | 0 | if (use_json) { |
226 | 0 | json_object_object_add(json, "advertisedRoutes", json_adv); |
227 | 0 | json_object_int_add(json, |
228 | 0 | "totalPrefixCounter", output_count); |
229 | 0 | vty_json(vty, json); |
230 | 0 | } else |
231 | 0 | vty_out(vty, "\nTotal number of prefixes %ld\n", output_count); |
232 | |
|
233 | 0 | return CMD_SUCCESS; |
234 | 0 | } |