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