]> git.proxmox.com Git - mirror_frr.git/blame - zebra/irdp_main.c
lib: msg: refactor common connection code from mgmtd
[mirror_frr.git] / zebra / irdp_main.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
ca776988 2/*
3 *
4 * Copyright (C) 2000 Robert Olsson.
5 * Swedish University of Agricultural Sciences
ca776988 6 */
7
d62a17ae 8/*
ca776988 9 * This work includes work with the following copywrite:
10 *
11 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
12 *
13 */
14
d62a17ae 15/*
43e52561 16 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
ca776988 17 * for reviewing and tests.
18 */
19
20
21#include <zebra.h>
22
ca776988 23#include "if.h"
24#include "vty.h"
25#include "sockunion.h"
c9e52be3 26#include "sockopt.h"
ca776988 27#include "prefix.h"
28#include "command.h"
29#include "memory.h"
30#include "stream.h"
31#include "ioctl.h"
32#include "connected.h"
33#include "log.h"
34#include "zclient.h"
24a58196 35#include "frrevent.h"
25dac855 36#include "privs.h"
ead4ee99 37#include "libfrr.h"
43e52561 38#include "lib_errors.h"
09781197 39#include "lib/version.h"
ca776988 40#include "zebra/interface.h"
41#include "zebra/rtadv.h"
42#include "zebra/rib.h"
3801e764 43#include "zebra/zebra_router.h"
ca776988 44#include "zebra/redistribute.h"
45#include "zebra/irdp.h"
364fed6b 46#include "zebra/zebra_errors.h"
ca776988 47#include <netinet/ip_icmp.h>
48
ab0f6155 49#include "checksum.h"
ca776988 50#include "if.h"
51#include "sockunion.h"
52#include "log.h"
5920b3eb 53#include "network.h"
ca776988 54
55/* GLOBAL VARS */
56
25dac855 57extern struct zebra_privs_t zserv_privs;
58
e6685141 59struct event *t_irdp_raw;
ca776988 60
61/* Timer interval of irdp. */
62int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
63
d62a17ae 64int irdp_sock_init(void)
ca776988 65{
d62a17ae 66 int ret, i;
67 int save_errno;
68 int sock;
69
0cf6db21 70 frr_with_privs(&zserv_privs) {
d62a17ae 71
01b9e3fd
DL
72 sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
73 save_errno = errno;
d62a17ae 74
01b9e3fd 75 }
d62a17ae 76
77 if (sock < 0) {
1c50c1c0 78 flog_err_sys(EC_LIB_SOCKET, "IRDP: can't create irdp socket %s",
9df414fe 79 safe_strerror(save_errno));
d62a17ae 80 return sock;
81 };
82
83 i = 1;
84 ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&i, sizeof(i));
85 if (ret < 0) {
450971aa 86 flog_err_sys(EC_LIB_SOCKET, "IRDP: can't do irdp sockopt %s",
9df414fe 87 safe_strerror(errno));
d62a17ae 88 close(sock);
89 return ret;
90 };
91
92 ret = setsockopt_ifindex(AF_INET, sock, 1);
93 if (ret < 0) {
450971aa 94 flog_err_sys(EC_LIB_SOCKET, "IRDP: can't do irdp sockopt %s",
9df414fe 95 safe_strerror(errno));
d62a17ae 96 close(sock);
97 return ret;
98 };
99
907a2395 100 event_add_read(zrouter.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
d62a17ae 101
102 return sock;
ca776988 103}
104
105
d62a17ae 106static int get_pref(struct irdp_interface *irdp, struct prefix *p)
ca776988 107{
d62a17ae 108 struct listnode *node;
109 struct Adv *adv;
110
111 /* Use default preference or use the override pref */
112
113 if (irdp->AdvPrefList == NULL)
114 return irdp->Preference;
115
116 for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv))
117 if (p->u.prefix4.s_addr == adv->ip.s_addr)
118 return adv->pref;
119
120 return irdp->Preference;
ca776988 121}
122
123/* Make ICMP Router Advertisement Message. */
d62a17ae 124static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
125 struct stream *s)
ca776988 126{
d62a17ae 127 struct zebra_if *zi = ifp->info;
ead4ee99 128 struct irdp_interface *irdp = zi->irdp;
d62a17ae 129 int size;
130 int pref;
d7c0a89a 131 uint16_t checksum;
d62a17ae 132
133 pref = get_pref(irdp, p);
134
135 stream_putc(s, ICMP_ROUTERADVERT); /* Type. */
136 stream_putc(s, 0); /* Code. */
137 stream_putw(s, 0); /* Checksum. */
138 stream_putc(s, 1); /* Num address. */
139 stream_putc(s, 2); /* Address Entry Size. */
140
141 if (irdp->flags & IF_SHUTDOWN)
142 stream_putw(s, 0);
143 else
144 stream_putw(s, irdp->Lifetime);
145
146 stream_putl(s, htonl(p->u.prefix4.s_addr)); /* Router address. */
147 stream_putl(s, pref);
148
149 /* in_cksum return network byte order value */
150 size = 16;
151 checksum = in_cksum(s->data, size);
152 stream_putw_at(s, 2, htons(checksum));
153
154 return size;
ca776988 155}
156
d62a17ae 157static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
ca776988 158{
d62a17ae 159 struct zebra_if *zi = ifp->info;
ead4ee99 160 struct irdp_interface *irdp = zi->irdp;
d7c0a89a
QY
161 uint32_t dst;
162 uint32_t ttl = 1;
d62a17ae 163
ead4ee99
DL
164 if (!irdp)
165 return;
d62a17ae 166 if (!(ifp->flags & IFF_UP))
167 return;
168
169 if (irdp->flags & IF_BROADCAST)
170 dst = INADDR_BROADCAST;
171 else
172 dst = htonl(INADDR_ALLHOSTS_GROUP);
173
174 if (irdp->flags & IF_DEBUG_MESSAGES)
2dbe669b
DA
175 zlog_debug(
176 "IRDP: TX Advert on %s %pFX Holdtime=%d Preference=%d",
177 ifp->name, p,
178 irdp->flags & IF_SHUTDOWN ? 0 : irdp->Lifetime,
179 get_pref(irdp, p));
d62a17ae 180
181 send_packet(ifp, s, dst, p, ttl);
ca776988 182}
183
d62a17ae 184static void irdp_advertisement(struct interface *ifp, struct prefix *p)
ca776988 185{
d62a17ae 186 struct stream *s;
187 s = stream_new(128);
188 make_advertisement_packet(ifp, p, s);
189 irdp_send(ifp, p, s);
190 stream_free(s);
ca776988 191}
192
e6685141 193void irdp_send_thread(struct event *t_advert)
ca776988 194{
d7c0a89a 195 uint32_t timer, tmp;
e16d030c 196 struct interface *ifp = EVENT_ARG(t_advert);
d62a17ae 197 struct zebra_if *zi = ifp->info;
ead4ee99 198 struct irdp_interface *irdp = zi->irdp;
d62a17ae 199 struct prefix *p;
200 struct listnode *node, *nnode;
201 struct connected *ifc;
202
ead4ee99 203 if (!irdp)
cc9f21da 204 return;
ead4ee99 205
d62a17ae 206 irdp->flags &= ~IF_SOLICIT;
207
208 if (ifp->connected)
209 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
210 p = ifc->address;
211
212 if (p->family != AF_INET)
213 continue;
214
215 irdp_advertisement(ifp, p);
216 irdp->irdp_sent++;
217 }
218
219 tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval;
5920b3eb 220 timer = frr_weak_random() % (tmp + 1);
d62a17ae 221 timer = irdp->MinAdvertInterval + timer;
222
223 if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
224 && timer > MAX_INITIAL_ADVERT_INTERVAL)
225 timer = MAX_INITIAL_ADVERT_INTERVAL;
226
227 if (irdp->flags & IF_DEBUG_MISC)
9165c5f5 228 zlog_debug("IRDP: New timer for %s set to %u", ifp->name,
d62a17ae 229 timer);
230
231 irdp->t_advertise = NULL;
907a2395
DS
232 event_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
233 &irdp->t_advertise);
ca776988 234}
235
236void irdp_advert_off(struct interface *ifp)
237{
d62a17ae 238 struct zebra_if *zi = ifp->info;
ead4ee99 239 struct irdp_interface *irdp = zi->irdp;
d62a17ae 240 struct listnode *node, *nnode;
241 int i;
242 struct connected *ifc;
243 struct prefix *p;
244
ead4ee99
DL
245 if (!irdp)
246 return;
247
e16d030c 248 EVENT_OFF(irdp->t_advertise);
d62a17ae 249
250 if (ifp->connected)
251 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
252 p = ifc->address;
253
254 /* Output some packets with Lifetime 0
255 we should add a wait...
256 */
257
258 for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) {
259 irdp->irdp_sent++;
260 irdp_advertisement(ifp, p);
261 }
262 }
ca776988 263}
264
265
d62a17ae 266void process_solicit(struct interface *ifp)
ca776988 267{
d62a17ae 268 struct zebra_if *zi = ifp->info;
ead4ee99 269 struct irdp_interface *irdp = zi->irdp;
d7c0a89a 270 uint32_t timer;
ca776988 271
ead4ee99
DL
272 if (!irdp)
273 return;
274
d62a17ae 275 /* When SOLICIT is active we reject further incoming solicits
276 this keeps down the answering rate so we don't have think
277 about DoS attacks here. */
ca776988 278
d62a17ae 279 if (irdp->flags & IF_SOLICIT)
280 return;
ca776988 281
d62a17ae 282 irdp->flags |= IF_SOLICIT;
e16d030c 283 EVENT_OFF(irdp->t_advertise);
ca776988 284
5920b3eb 285 timer = (frr_weak_random() % MAX_RESPONSE_DELAY) + 1;
ca776988 286
d62a17ae 287 irdp->t_advertise = NULL;
907a2395
DS
288 event_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
289 &irdp->t_advertise);
ca776988 290}
291
2eb27eec 292static int irdp_finish(void)
ca776988 293{
d62a17ae 294 struct vrf *vrf;
d62a17ae 295 struct interface *ifp;
296 struct zebra_if *zi;
297 struct irdp_interface *irdp;
298
299 zlog_info("IRDP: Received shutdown notification.");
300
a2addae8 301 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
451fda4f 302 FOR_ALL_INTERFACES (vrf, ifp) {
a2addae8
RW
303 zi = ifp->info;
304
305 if (!zi)
306 continue;
307 irdp = zi->irdp;
308 if (!irdp)
309 continue;
310
311 if (irdp->flags & IF_ACTIVE) {
312 irdp->flags |= IF_SHUTDOWN;
313 irdp_advert_off(ifp);
314 }
d62a17ae 315 }
ead4ee99 316 return 0;
ca776988 317}
318
cd9d0537 319static int irdp_init(struct event_loop *master)
2eb27eec
DL
320{
321 irdp_if_init();
322
323 hook_register(frr_early_fini, irdp_finish);
8dc1f7fc
DL
324 return 0;
325}
326
327static int irdp_module_init(void)
328{
329 hook_register(frr_late_init, irdp_init);
330 return 0;
2eb27eec
DL
331}
332
996c9314 333FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION,
80413c20
DL
334 .description = "zebra IRDP module", .init = irdp_module_init,
335);