]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_network.c
eigrpd: Add EIGRP_ERR_XXX for zlog_err to zlog_ferr
[mirror_frr.git] / eigrpd / eigrp_network.c
1 /*
2 * EIGRP Network Related Functions.
3 * Copyright (C) 2013-2014
4 * Authors:
5 * Donnie Savage
6 * Jan Janovic
7 * Matej Perina
8 * Peter Orsag
9 * Peter Paluch
10 *
11 * This file is part of GNU Zebra.
12 *
13 * GNU Zebra is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2, or (at your option) any
16 * later version.
17 *
18 * GNU Zebra is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; see the file COPYING; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28 #include <zebra.h>
29
30 #include "thread.h"
31 #include "linklist.h"
32 #include "prefix.h"
33 #include "if.h"
34 #include "sockunion.h"
35 #include "log.h"
36 #include "sockopt.h"
37 #include "privs.h"
38 #include "table.h"
39 #include "vty.h"
40 #include "lib_errors.h"
41
42 #include "eigrpd/eigrp_structs.h"
43 #include "eigrpd/eigrpd.h"
44 #include "eigrpd/eigrp_interface.h"
45 #include "eigrpd/eigrp_neighbor.h"
46 #include "eigrpd/eigrp_packet.h"
47 #include "eigrpd/eigrp_zebra.h"
48 #include "eigrpd/eigrp_vty.h"
49 #include "eigrpd/eigrp_network.h"
50
51 static int eigrp_network_match_iface(const struct connected *,
52 const struct prefix *);
53 static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
54 struct interface *);
55
56 int eigrp_sock_init(void)
57 {
58 int eigrp_sock;
59 int ret;
60 #ifdef IP_HDRINCL
61 int hincl = 1;
62 #endif
63
64 if (eigrpd_privs.change(ZPRIVS_RAISE))
65 zlog_ferr(LIB_ERR_PRIVILEGES,
66 "eigrp_sock_init: could not raise privs, %s",
67 safe_strerror(errno));
68
69 eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
70 if (eigrp_sock < 0) {
71 int save_errno = errno;
72 if (eigrpd_privs.change(ZPRIVS_LOWER))
73 zlog_ferr(LIB_ERR_PRIVILEGES,
74 "eigrp_sock_init: could not lower privs, %s",
75 safe_strerror(errno));
76 zlog_ferr(LIB_ERR_SOCKET, "eigrp_read_sock_init: socket: %s",
77 safe_strerror(save_errno));
78 exit(1);
79 }
80
81 #ifdef IP_HDRINCL
82 /* we will include IP header with packet */
83 ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
84 sizeof(hincl));
85 if (ret < 0) {
86 int save_errno = errno;
87 if (eigrpd_privs.change(ZPRIVS_LOWER))
88 zlog_ferr(LIB_ERR_PRIVILEGES,
89 "eigrp_sock_init: could not lower privs, %s",
90 safe_strerror(errno));
91 zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
92 eigrp_sock, safe_strerror(save_errno));
93 }
94 #elif defined(IPTOS_PREC_INTERNETCONTROL)
95 #warning "IP_HDRINCL not available on this system"
96 #warning "using IPTOS_PREC_INTERNETCONTROL"
97 ret = setsockopt_ipv4_tos(eigrp_sock, IPTOS_PREC_INTERNETCONTROL);
98 if (ret < 0) {
99 int save_errno = errno;
100 if (eigrpd_privs.change(ZPRIVS_LOWER))
101 zlog_ferr(LIB_ERR_PRIVILEGES,
102 "eigrpd_sock_init: could not lower privs, %s",
103 safe_strerror(errno));
104 zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s", tos,
105 eigrp_sock, safe_strerror(save_errno));
106 close(eigrp_sock); /* Prevent sd leak. */
107 return ret;
108 }
109 #else /* !IPTOS_PREC_INTERNETCONTROL */
110 #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
111 zlog_warn("IP_HDRINCL option not available");
112 #endif /* IP_HDRINCL */
113
114 ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
115
116 if (ret < 0)
117 zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock);
118
119 if (eigrpd_privs.change(ZPRIVS_LOWER)) {
120 zlog_ferr(LIB_ERR_PRIVILEGES,
121 "eigrp_sock_init: could not lower privs, %s",
122 safe_strerror(errno));
123 }
124
125 return eigrp_sock;
126 }
127
128 void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
129 {
130 int newbuflen;
131 /* Check if any work has to be done at all. */
132 if (eigrp->maxsndbuflen >= buflen)
133 return;
134 if (eigrpd_privs.change(ZPRIVS_RAISE))
135 zlog_ferr(LIB_ERR_PRIVILEGES, "%s: could not raise privs, %s",
136 __func__, safe_strerror(errno));
137
138 /* Now we try to set SO_SNDBUF to what our caller has requested
139 * (the MTU of a newly added interface). However, if the OS has
140 * truncated the actual buffer size to somewhat less size, try
141 * to detect it and update our records appropriately. The OS
142 * may allocate more buffer space, than requested, this isn't
143 * a error.
144 */
145 setsockopt_so_sendbuf(eigrp->fd, buflen);
146 newbuflen = getsockopt_so_sendbuf(eigrp->fd);
147 if (newbuflen < 0 || newbuflen < (int)buflen)
148 zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
149 __func__, buflen, newbuflen);
150 if (newbuflen >= 0)
151 eigrp->maxsndbuflen = (unsigned int)newbuflen;
152 else
153 zlog_warn("%s: failed to get SO_SNDBUF", __func__);
154 if (eigrpd_privs.change(ZPRIVS_LOWER))
155 zlog_ferr(LIB_ERR_PRIVILEGES, "%s: could not lower privs, %s",
156 __func__, safe_strerror(errno));
157 }
158
159 int eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p,
160 unsigned int ifindex)
161 {
162 uint8_t val;
163 int ret, len;
164
165 val = 0;
166 len = sizeof(val);
167
168 /* Prevent receiving self-origined multicast packets. */
169 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val,
170 len);
171 if (ret < 0)
172 zlog_warn(
173 "can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s",
174 top->fd, safe_strerror(errno));
175
176 /* Explicitly set multicast ttl to 1 -- endo. */
177 val = 1;
178 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val,
179 len);
180 if (ret < 0)
181 zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s",
182 top->fd, safe_strerror(errno));
183
184 ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
185 if (ret < 0)
186 zlog_warn(
187 "can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, "
188 "ifindex %u): %s",
189 top->fd, inet_ntoa(p->u.prefix4), ifindex,
190 safe_strerror(errno));
191
192 return ret;
193 }
194
195 /* Join to the EIGRP multicast group. */
196 int eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
197 unsigned int ifindex)
198 {
199 int ret;
200
201 ret = setsockopt_ipv4_multicast(
202 top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4,
203 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
204 if (ret < 0)
205 zlog_warn(
206 "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
207 "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit "
208 "on # of multicast group memberships has been exceeded?",
209 top->fd, inet_ntoa(p->u.prefix4), ifindex,
210 safe_strerror(errno));
211 else
212 zlog_debug("interface %s [%u] join EIGRP Multicast group.",
213 inet_ntoa(p->u.prefix4), ifindex);
214
215 return ret;
216 }
217
218 int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
219 unsigned int ifindex)
220 {
221 int ret;
222
223 ret = setsockopt_ipv4_multicast(
224 top->fd, IP_DROP_MEMBERSHIP, p->u.prefix4,
225 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
226 if (ret < 0)
227 zlog_warn(
228 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
229 "ifindex %u, AllSPFRouters): %s",
230 top->fd, inet_ntoa(p->u.prefix4), ifindex,
231 safe_strerror(errno));
232 else
233 zlog_debug("interface %s [%u] leave EIGRP Multicast group.",
234 inet_ntoa(p->u.prefix4), ifindex);
235
236 return ret;
237 }
238
239 int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
240 {
241 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
242 struct route_node *rn;
243 struct interface *ifp;
244
245 rn = route_node_get(eigrp->networks, (struct prefix *)p);
246 if (rn->info) {
247 /* There is already same network statement. */
248 route_unlock_node(rn);
249 return 0;
250 }
251
252 struct prefix *pref = prefix_new();
253 PREFIX_COPY_IPV4(pref, p);
254 rn->info = (void *)pref;
255
256 /* Schedule Router ID Update. */
257 if (eigrp->router_id == 0)
258 eigrp_router_id_update(eigrp);
259 /* Run network config now. */
260 /* Get target interface. */
261 FOR_ALL_INTERFACES (vrf, ifp) {
262 zlog_debug("Setting up %s", ifp->name);
263 eigrp_network_run_interface(eigrp, p, ifp);
264 }
265 return 1;
266 }
267
268 /* Check whether interface matches given network
269 * returns: 1, true. 0, false
270 */
271 static int eigrp_network_match_iface(const struct connected *co,
272 const struct prefix *net)
273 {
274 /* new approach: more elegant and conceptually clean */
275 return prefix_match_network_statement(net, CONNECTED_PREFIX(co));
276 }
277
278 static void eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
279 struct interface *ifp)
280 {
281 struct eigrp_interface *ei;
282 struct listnode *cnode;
283 struct connected *co;
284
285 /* if interface prefix is match specified prefix,
286 then create socket and join multicast group. */
287 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) {
288
289 if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY))
290 continue;
291
292 if (p->family == co->address->family && !ifp->info
293 && eigrp_network_match_iface(co, p)) {
294
295 ei = eigrp_if_new(eigrp, ifp, co->address);
296 ei->connected = co;
297
298 /* Relate eigrp interface to eigrp instance. */
299 ei->eigrp = eigrp;
300
301 /* if router_id is not configured, dont bring up
302 * interfaces.
303 * eigrp_router_id_update() will call eigrp_if_update
304 * whenever r-id is configured instead.
305 */
306 if (if_is_operative(ifp))
307 eigrp_if_up(ei);
308 }
309 }
310 }
311
312 void eigrp_if_update(struct interface *ifp)
313 {
314 struct listnode *node, *nnode;
315 struct route_node *rn;
316 struct eigrp *eigrp;
317
318 /*
319 * In the event there are multiple eigrp autonymnous systems running,
320 * we need to check eac one and add the interface as approperate
321 */
322 for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
323 /* EIGRP must be on and Router-ID must be configured. */
324 if (!eigrp || eigrp->router_id == 0)
325 continue;
326
327 /* Run each network for this interface. */
328 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
329 if (rn->info != NULL) {
330 eigrp_network_run_interface(eigrp, &rn->p, ifp);
331 }
332 }
333 }
334
335 int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
336 {
337 struct route_node *rn;
338 struct listnode *node, *nnode;
339 struct eigrp_interface *ei;
340 struct prefix *pref;
341
342 rn = route_node_lookup(eigrp->networks, p);
343 if (rn == NULL)
344 return 0;
345
346 pref = rn->info;
347 route_unlock_node(rn);
348
349 if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4))
350 return 0;
351
352 prefix_ipv4_free(rn->info);
353 rn->info = NULL;
354 route_unlock_node(rn); /* initial reference */
355
356 /* Find interfaces that not configured already. */
357 for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei)) {
358 int found = 0;
359 struct connected *co = ei->connected;
360
361 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) {
362 if (rn->info == NULL)
363 continue;
364
365 if (eigrp_network_match_iface(co, &rn->p)) {
366 found = 1;
367 route_unlock_node(rn);
368 break;
369 }
370 }
371
372 if (found == 0) {
373 eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
374 }
375 }
376
377 return 1;
378 }
379
380 uint32_t eigrp_calculate_metrics(struct eigrp *eigrp,
381 struct eigrp_metrics metric)
382 {
383 uint64_t temp_metric;
384 temp_metric = 0;
385
386 if (metric.delay == EIGRP_MAX_METRIC)
387 return EIGRP_MAX_METRIC;
388
389 // EIGRP Metric =
390 // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
391
392 if (eigrp->k_values[0])
393 temp_metric += (eigrp->k_values[0] * metric.bandwidth);
394 if (eigrp->k_values[1])
395 temp_metric += ((eigrp->k_values[1] * metric.bandwidth)
396 / (256 - metric.load));
397 if (eigrp->k_values[2])
398 temp_metric += (eigrp->k_values[2] * metric.delay);
399 if (eigrp->k_values[3] && !eigrp->k_values[4])
400 temp_metric *= eigrp->k_values[3];
401 if (!eigrp->k_values[3] && eigrp->k_values[4])
402 temp_metric *= (eigrp->k_values[4] / metric.reliability);
403 if (eigrp->k_values[3] && eigrp->k_values[4])
404 temp_metric *= ((eigrp->k_values[4] / metric.reliability)
405 + eigrp->k_values[3]);
406
407 if (temp_metric <= EIGRP_MAX_METRIC)
408 return (uint32_t)temp_metric;
409 else
410 return EIGRP_MAX_METRIC;
411 }
412
413 uint32_t eigrp_calculate_total_metrics(struct eigrp *eigrp,
414 struct eigrp_nexthop_entry *entry)
415 {
416 struct eigrp_interface *ei = entry->ei;
417
418 entry->total_metric = entry->reported_metric;
419 uint64_t temp_delay =
420 (uint64_t)entry->total_metric.delay
421 + (uint64_t)eigrp_delay_to_scaled(ei->params.delay);
422 entry->total_metric.delay = temp_delay > EIGRP_MAX_METRIC
423 ? EIGRP_MAX_METRIC
424 : (uint32_t)temp_delay;
425
426 uint32_t bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
427 entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
428 ? bw
429 : entry->total_metric.bandwidth;
430
431 return eigrp_calculate_metrics(eigrp, entry->total_metric);
432 }
433
434 uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1,
435 struct eigrp_metrics metric2)
436 {
437 if ((metric1.bandwidth == metric2.bandwidth)
438 && (metric1.delay == metric2.delay)
439 && (metric1.hop_count == metric2.hop_count)
440 && (metric1.load == metric2.load)
441 && (metric1.reliability == metric2.reliability)
442 && (metric1.mtu[0] == metric2.mtu[0])
443 && (metric1.mtu[1] == metric2.mtu[1])
444 && (metric1.mtu[2] == metric2.mtu[2]))
445 return 1;
446
447 return 0; // if different
448 }
449
450 void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
451 {
452 }