]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: GPL-2.0-or-later | |
2 | /* RIPd and zebra interface. | |
3 | * Copyright (C) 1997, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> | |
4 | */ | |
5 | ||
6 | #include <zebra.h> | |
7 | ||
8 | #include "command.h" | |
9 | #include "prefix.h" | |
10 | #include "table.h" | |
11 | #include "stream.h" | |
12 | #include "memory.h" | |
13 | #include "zclient.h" | |
14 | #include "log.h" | |
15 | #include "vrf.h" | |
16 | #include "bfd.h" | |
17 | #include "ripd/ripd.h" | |
18 | #include "ripd/rip_debug.h" | |
19 | #include "ripd/rip_interface.h" | |
20 | ||
21 | /* All information about zebra. */ | |
22 | struct zclient *zclient = NULL; | |
23 | ||
24 | /* Send ECMP routes to zebra. */ | |
25 | static void rip_zebra_ipv4_send(struct rip *rip, struct route_node *rp, | |
26 | uint8_t cmd) | |
27 | { | |
28 | struct list *list = (struct list *)rp->info; | |
29 | struct zapi_route api; | |
30 | struct zapi_nexthop *api_nh; | |
31 | struct listnode *listnode = NULL; | |
32 | struct rip_info *rinfo = NULL; | |
33 | int count = 0; | |
34 | ||
35 | memset(&api, 0, sizeof(api)); | |
36 | api.vrf_id = rip->vrf->vrf_id; | |
37 | api.type = ZEBRA_ROUTE_RIP; | |
38 | api.safi = SAFI_UNICAST; | |
39 | ||
40 | SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); | |
41 | for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { | |
42 | if (count >= MULTIPATH_NUM) | |
43 | break; | |
44 | api_nh = &api.nexthops[count]; | |
45 | api_nh->vrf_id = rip->vrf->vrf_id; | |
46 | api_nh->gate = rinfo->nh.gate; | |
47 | api_nh->type = NEXTHOP_TYPE_IPV4; | |
48 | if (cmd == ZEBRA_ROUTE_ADD) | |
49 | SET_FLAG(rinfo->flags, RIP_RTF_FIB); | |
50 | else | |
51 | UNSET_FLAG(rinfo->flags, RIP_RTF_FIB); | |
52 | count++; | |
53 | } | |
54 | ||
55 | api.prefix = rp->p; | |
56 | api.nexthop_num = count; | |
57 | ||
58 | rinfo = listgetdata(listhead(list)); | |
59 | ||
60 | SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); | |
61 | api.metric = rinfo->metric; | |
62 | ||
63 | if (rinfo->distance && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) { | |
64 | SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); | |
65 | api.distance = rinfo->distance; | |
66 | } | |
67 | ||
68 | if (rinfo->tag) { | |
69 | SET_FLAG(api.message, ZAPI_MESSAGE_TAG); | |
70 | api.tag = rinfo->tag; | |
71 | } | |
72 | ||
73 | zclient_route_send(cmd, zclient, &api); | |
74 | ||
75 | if (IS_RIP_DEBUG_ZEBRA) { | |
76 | if (rip->ecmp) | |
77 | zlog_debug("%s: %pFX nexthops %d", | |
78 | (cmd == ZEBRA_ROUTE_ADD) | |
79 | ? "Install into zebra" | |
80 | : "Delete from zebra", | |
81 | &rp->p, count); | |
82 | else | |
83 | zlog_debug("%s: %pFX", | |
84 | (cmd == ZEBRA_ROUTE_ADD) | |
85 | ? "Install into zebra" | |
86 | : "Delete from zebra", &rp->p); | |
87 | } | |
88 | ||
89 | rip->counters.route_changes++; | |
90 | } | |
91 | ||
92 | /* Add/update ECMP routes to zebra. */ | |
93 | void rip_zebra_ipv4_add(struct rip *rip, struct route_node *rp) | |
94 | { | |
95 | rip_zebra_ipv4_send(rip, rp, ZEBRA_ROUTE_ADD); | |
96 | } | |
97 | ||
98 | /* Delete ECMP routes from zebra. */ | |
99 | void rip_zebra_ipv4_delete(struct rip *rip, struct route_node *rp) | |
100 | { | |
101 | rip_zebra_ipv4_send(rip, rp, ZEBRA_ROUTE_DELETE); | |
102 | } | |
103 | ||
104 | /* Zebra route add and delete treatment. */ | |
105 | static int rip_zebra_read_route(ZAPI_CALLBACK_ARGS) | |
106 | { | |
107 | struct rip *rip; | |
108 | struct zapi_route api; | |
109 | struct nexthop nh; | |
110 | ||
111 | rip = rip_lookup_by_vrf_id(vrf_id); | |
112 | if (!rip) | |
113 | return 0; | |
114 | ||
115 | if (zapi_route_decode(zclient->ibuf, &api) < 0) | |
116 | return -1; | |
117 | ||
118 | memset(&nh, 0, sizeof(nh)); | |
119 | nh.type = api.nexthops[0].type; | |
120 | nh.gate.ipv4 = api.nexthops[0].gate.ipv4; | |
121 | nh.ifindex = api.nexthops[0].ifindex; | |
122 | ||
123 | /* Then fetch IPv4 prefixes. */ | |
124 | if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) | |
125 | rip_redistribute_add(rip, api.type, RIP_ROUTE_REDISTRIBUTE, | |
126 | (struct prefix_ipv4 *)&api.prefix, &nh, | |
127 | api.metric, api.distance, api.tag); | |
128 | else if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_DEL) | |
129 | rip_redistribute_delete(rip, api.type, RIP_ROUTE_REDISTRIBUTE, | |
130 | (struct prefix_ipv4 *)&api.prefix, | |
131 | nh.ifindex); | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
136 | void rip_redistribute_conf_update(struct rip *rip, int type) | |
137 | { | |
138 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, | |
139 | type, 0, rip->vrf->vrf_id); | |
140 | } | |
141 | ||
142 | void rip_redistribute_conf_delete(struct rip *rip, int type) | |
143 | { | |
144 | if (zclient->sock > 0) | |
145 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, | |
146 | AFI_IP, type, 0, rip->vrf->vrf_id); | |
147 | ||
148 | /* Remove the routes from RIP table. */ | |
149 | rip_redistribute_withdraw(rip, type); | |
150 | } | |
151 | ||
152 | int rip_redistribute_check(struct rip *rip, int type) | |
153 | { | |
154 | return rip->redist[type].enabled; | |
155 | } | |
156 | ||
157 | void rip_redistribute_enable(struct rip *rip) | |
158 | { | |
159 | for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
160 | if (!rip_redistribute_check(rip, i)) | |
161 | continue; | |
162 | ||
163 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, | |
164 | i, 0, rip->vrf->vrf_id); | |
165 | } | |
166 | } | |
167 | ||
168 | void rip_redistribute_disable(struct rip *rip) | |
169 | { | |
170 | for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
171 | if (!rip_redistribute_check(rip, i)) | |
172 | continue; | |
173 | ||
174 | zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, | |
175 | AFI_IP, i, 0, rip->vrf->vrf_id); | |
176 | } | |
177 | } | |
178 | ||
179 | void rip_show_redistribute_config(struct vty *vty, struct rip *rip) | |
180 | { | |
181 | for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
182 | if (i == zclient->redist_default | |
183 | || !rip_redistribute_check(rip, i)) | |
184 | continue; | |
185 | ||
186 | vty_out(vty, " %s", zebra_route_string(i)); | |
187 | } | |
188 | } | |
189 | ||
190 | void rip_zebra_vrf_register(struct vrf *vrf) | |
191 | { | |
192 | if (vrf->vrf_id == VRF_DEFAULT) | |
193 | return; | |
194 | ||
195 | if (IS_RIP_DEBUG_EVENT) | |
196 | zlog_debug("%s: register VRF %s(%u) to zebra", __func__, | |
197 | vrf->name, vrf->vrf_id); | |
198 | ||
199 | zclient_send_reg_requests(zclient, vrf->vrf_id); | |
200 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf->vrf_id); | |
201 | } | |
202 | ||
203 | void rip_zebra_vrf_deregister(struct vrf *vrf) | |
204 | { | |
205 | if (vrf->vrf_id == VRF_DEFAULT) | |
206 | return; | |
207 | ||
208 | if (IS_RIP_DEBUG_EVENT) | |
209 | zlog_debug("%s: deregister VRF %s(%u) from zebra.", __func__, | |
210 | vrf->name, vrf->vrf_id); | |
211 | ||
212 | zclient_send_dereg_requests(zclient, vrf->vrf_id); | |
213 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_DEREGISTER, vrf->vrf_id); | |
214 | } | |
215 | ||
216 | static void rip_zebra_connected(struct zclient *zclient) | |
217 | { | |
218 | zclient_send_reg_requests(zclient, VRF_DEFAULT); | |
219 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); | |
220 | } | |
221 | ||
222 | zclient_handler *const rip_handlers[] = { | |
223 | [ZEBRA_INTERFACE_ADDRESS_ADD] = rip_interface_address_add, | |
224 | [ZEBRA_INTERFACE_ADDRESS_DELETE] = rip_interface_address_delete, | |
225 | [ZEBRA_INTERFACE_VRF_UPDATE] = rip_interface_vrf_update, | |
226 | [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = rip_zebra_read_route, | |
227 | [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = rip_zebra_read_route, | |
228 | }; | |
229 | ||
230 | void rip_zclient_init(struct event_loop *master) | |
231 | { | |
232 | /* Set default value to the zebra client structure. */ | |
233 | zclient = zclient_new(master, &zclient_options_default, rip_handlers, | |
234 | array_size(rip_handlers)); | |
235 | zclient_init(zclient, ZEBRA_ROUTE_RIP, 0, &ripd_privs); | |
236 | zclient->zebra_connected = rip_zebra_connected; | |
237 | } | |
238 | ||
239 | void rip_zclient_stop(void) | |
240 | { | |
241 | zclient_stop(zclient); | |
242 | zclient_free(zclient); | |
243 | } |