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