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