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