]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_network.c
Merge pull request #10590 from donaldsharp/bgp_error_codes
[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"
6ae7ed45 40#include "lib_errors.h"
7f57883e 41
7f57883e
DS
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
952248db
DS
51static int eigrp_network_match_iface(const struct prefix *connected_prefix,
52 const struct prefix *prefix);
d62a17ae 53static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
54 struct interface *);
7f57883e 55
128ed760 56int eigrp_sock_init(struct vrf *vrf)
7f57883e 57{
38513e88 58 int eigrp_sock = -1;
029a775e 59 int ret;
60#ifdef IP_HDRINCL
61 int hincl = 1;
62#endif
d62a17ae 63
38513e88
DS
64 if (!vrf)
65 return eigrp_sock;
66
0cf6db21 67 frr_with_privs(&eigrpd_privs) {
128ed760
DS
68 eigrp_sock = vrf_socket(
69 AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id,
70 vrf->vrf_id != VRF_DEFAULT ? vrf->name : NULL);
6bb30c2c
DL
71 if (eigrp_sock < 0) {
72 zlog_err("eigrp_read_sock_init: socket: %s",
73 safe_strerror(errno));
74 exit(1);
75 }
7f57883e
DS
76
77#ifdef IP_HDRINCL
6bb30c2c
DL
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 }
d62a17ae 85#elif defined(IPTOS_PREC_INTERNETCONTROL)
7f57883e
DS
86#warning "IP_HDRINCL not available on this system"
87#warning "using IPTOS_PREC_INTERNETCONTROL"
6bb30c2c
DL
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 }
7f57883e
DS
96#else /* !IPTOS_PREC_INTERNETCONTROL */
97#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
6bb30c2c 98 zlog_warn("IP_HDRINCL option not available");
7f57883e
DS
99#endif /* IP_HDRINCL */
100
6bb30c2c
DL
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);
d62a17ae 105 }
7f57883e 106
d62a17ae 107 return eigrp_sock;
7f57883e
DS
108}
109
d62a17ae 110void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
7f57883e 111{
d62a17ae 112 int newbuflen;
113 /* Check if any work has to be done at all. */
114 if (eigrp->maxsndbuflen >= buflen)
115 return;
d62a17ae 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 */
338b8e91
RW
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__);
7f57883e
DS
133}
134
d62a17ae 135int eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p,
136 unsigned int ifindex)
7f57883e 137{
d7c0a89a 138 uint8_t val;
d62a17ae 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(
37b4b3cc
DS
163 "can't setsockopt IP_MULTICAST_IF (fd %d, addr %pI4, ifindex %u): %s",
164 top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
d62a17ae 165
166 return ret;
7f57883e
DS
167}
168
169/* Join to the EIGRP multicast group. */
d62a17ae 170int eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
171 unsigned int ifindex)
7f57883e 172{
d62a17ae 173 int ret;
174
175 ret = setsockopt_ipv4_multicast(
176 top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4,
177 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
178 if (ret < 0)
179 zlog_warn(
37b4b3cc
DS
180 "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
181 top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
d62a17ae 182 else
37b4b3cc
DS
183 zlog_debug("interface %pI4 [%u] join EIGRP Multicast group.",
184 &p->u.prefix4, ifindex);
d62a17ae 185
186 return ret;
7f57883e
DS
187}
188
d62a17ae 189int eigrp_if_drop_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_DROP_MEMBERSHIP, p->u.prefix4,
196 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
197 if (ret < 0)
198 zlog_warn(
37b4b3cc
DS
199 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
200 top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
d62a17ae 201 else
37b4b3cc
DS
202 zlog_debug("interface %pI4 [%u] leave EIGRP Multicast group.",
203 &p->u.prefix4, ifindex);
d62a17ae 204
205 return ret;
7f57883e
DS
206}
207
cd6c066e 208int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
7f57883e 209{
d0ac2662 210 struct vrf *vrf = vrf_lookup_by_id(eigrp->vrf_id);
d62a17ae 211 struct route_node *rn;
212 struct interface *ifp;
d62a17ae 213
c4efd0f4 214 rn = route_node_get(eigrp->networks, p);
d62a17ae 215 if (rn->info) {
216 /* There is already same network statement. */
217 route_unlock_node(rn);
218 return 0;
219 }
220
a96029f8 221 struct prefix *pref = prefix_new();
b08dcc3f 222 prefix_copy(pref, p);
d62a17ae 223 rn->info = (void *)pref;
224
225 /* Schedule Router ID Update. */
975a328e 226 if (eigrp->router_id.s_addr == INADDR_ANY)
d62a17ae 227 eigrp_router_id_update(eigrp);
228 /* Run network config now. */
229 /* Get target interface. */
451fda4f 230 FOR_ALL_INTERFACES (vrf, ifp) {
d62a17ae 231 zlog_debug("Setting up %s", ifp->name);
a96029f8 232 eigrp_network_run_interface(eigrp, p, ifp);
d62a17ae 233 }
234 return 1;
7f57883e
DS
235}
236
237/* Check whether interface matches given network
238 * returns: 1, true. 0, false
239 */
952248db 240static int eigrp_network_match_iface(const struct prefix *co_prefix,
d62a17ae 241 const struct prefix *net)
7f57883e 242{
d62a17ae 243 /* new approach: more elegant and conceptually clean */
952248db 244 return prefix_match_network_statement(net, co_prefix);
7f57883e
DS
245}
246
d62a17ae 247static void eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
248 struct interface *ifp)
7f57883e 249{
b748db67 250 struct eigrp_interface *ei;
d62a17ae 251 struct listnode *cnode;
252 struct connected *co;
253
254 /* if interface prefix is match specified prefix,
255 then create socket and join multicast group. */
256 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) {
257
258 if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY))
259 continue;
260
996c9314 261 if (p->family == co->address->family && !ifp->info
952248db 262 && eigrp_network_match_iface(co->address, p)) {
d62a17ae 263
264 ei = eigrp_if_new(eigrp, ifp, co->address);
d62a17ae 265
d62a17ae 266 /* Relate eigrp interface to eigrp instance. */
267 ei->eigrp = eigrp;
268
d62a17ae 269 /* if router_id is not configured, dont bring up
270 * interfaces.
271 * eigrp_router_id_update() will call eigrp_if_update
272 * whenever r-id is configured instead.
273 */
274 if (if_is_operative(ifp))
275 eigrp_if_up(ei);
276 }
277 }
7f57883e
DS
278}
279
d62a17ae 280void eigrp_if_update(struct interface *ifp)
7f57883e 281{
d62a17ae 282 struct listnode *node, *nnode;
283 struct route_node *rn;
7d7acfc7 284 struct eigrp *eigrp;
d62a17ae 285
286 /*
287 * In the event there are multiple eigrp autonymnous systems running,
288 * we need to check eac one and add the interface as approperate
289 */
290 for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
096f7609 291 if (ifp->vrf->vrf_id != eigrp->vrf_id)
88a3b65e
DS
292 continue;
293
d62a17ae 294 /* EIGRP must be on and Router-ID must be configured. */
3a6290bd 295 if (eigrp->router_id.s_addr == INADDR_ANY)
d62a17ae 296 continue;
297
298 /* Run each network for this interface. */
299 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
300 if (rn->info != NULL) {
301 eigrp_network_run_interface(eigrp, &rn->p, ifp);
302 }
303 }
7f57883e
DS
304}
305
cd6c066e 306int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
7f57883e 307{
d62a17ae 308 struct route_node *rn;
309 struct listnode *node, *nnode;
310 struct eigrp_interface *ei;
311 struct prefix *pref;
312
cd6c066e 313 rn = route_node_lookup(eigrp->networks, p);
d62a17ae 314 if (rn == NULL)
315 return 0;
316
317 pref = rn->info;
318 route_unlock_node(rn);
319
cd6c066e 320 if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4))
d62a17ae 321 return 0;
322
63265b5c 323 prefix_ipv4_free((struct prefix_ipv4 **)&rn->info);
d62a17ae 324 route_unlock_node(rn); /* initial reference */
325
326 /* Find interfaces that not configured already. */
327 for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei)) {
952248db 328 bool found = false;
d62a17ae 329
330 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) {
331 if (rn->info == NULL)
332 continue;
333
b245781a 334 if (eigrp_network_match_iface(&ei->address, &rn->p)) {
952248db 335 found = true;
d62a17ae 336 route_unlock_node(rn);
337 break;
338 }
339 }
340
952248db 341 if (!found) {
d62a17ae 342 eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
343 }
344 }
345
346 return 1;
7f57883e
DS
347}
348
d62a17ae 349void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
7f57883e 350{
7f57883e 351}