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