]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_network.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / eigrpd / eigrp_network.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
7f57883e
DS
2/*
3 * EIGRP Network Related Functions.
4 * Copyright (C) 2013-2014
5 * Authors:
6 * Donnie Savage
7 * Jan Janovic
8 * Matej Perina
9 * Peter Orsag
10 * Peter Paluch
7f57883e
DS
11 */
12
13#include <zebra.h>
14
15#include "thread.h"
16#include "linklist.h"
17#include "prefix.h"
18#include "if.h"
19#include "sockunion.h"
20#include "log.h"
21#include "sockopt.h"
22#include "privs.h"
23#include "table.h"
24#include "vty.h"
6ae7ed45 25#include "lib_errors.h"
7f57883e 26
7f57883e
DS
27#include "eigrpd/eigrp_structs.h"
28#include "eigrpd/eigrpd.h"
29#include "eigrpd/eigrp_interface.h"
30#include "eigrpd/eigrp_neighbor.h"
31#include "eigrpd/eigrp_packet.h"
32#include "eigrpd/eigrp_zebra.h"
33#include "eigrpd/eigrp_vty.h"
34#include "eigrpd/eigrp_network.h"
35
952248db
DS
36static int eigrp_network_match_iface(const struct prefix *connected_prefix,
37 const struct prefix *prefix);
d62a17ae 38static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
39 struct interface *);
7f57883e 40
128ed760 41int eigrp_sock_init(struct vrf *vrf)
7f57883e 42{
38513e88 43 int eigrp_sock = -1;
029a775e 44 int ret;
45#ifdef IP_HDRINCL
46 int hincl = 1;
47#endif
d62a17ae 48
38513e88
DS
49 if (!vrf)
50 return eigrp_sock;
51
0cf6db21 52 frr_with_privs(&eigrpd_privs) {
128ed760
DS
53 eigrp_sock = vrf_socket(
54 AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id,
55 vrf->vrf_id != VRF_DEFAULT ? vrf->name : NULL);
6bb30c2c 56 if (eigrp_sock < 0) {
04b267e4 57 zlog_err("%s: socket: %s",
58 __func__, safe_strerror(errno));
6bb30c2c
DL
59 exit(1);
60 }
7f57883e
DS
61
62#ifdef IP_HDRINCL
6bb30c2c
DL
63 /* we will include IP header with packet */
64 ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
65 sizeof(hincl));
66 if (ret < 0) {
67 zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
68 eigrp_sock, safe_strerror(errno));
69 }
d62a17ae 70#elif defined(IPTOS_PREC_INTERNETCONTROL)
7f57883e
DS
71#warning "IP_HDRINCL not available on this system"
72#warning "using IPTOS_PREC_INTERNETCONTROL"
6bb30c2c
DL
73 ret = setsockopt_ipv4_tos(eigrp_sock,
74 IPTOS_PREC_INTERNETCONTROL);
75 if (ret < 0) {
76 zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s",
77 tos, eigrp_sock, safe_strerror(errno));
78 close(eigrp_sock); /* Prevent sd leak. */
79 return ret;
80 }
7f57883e
DS
81#else /* !IPTOS_PREC_INTERNETCONTROL */
82#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
6bb30c2c 83 zlog_warn("IP_HDRINCL option not available");
7f57883e
DS
84#endif /* IP_HDRINCL */
85
6bb30c2c
DL
86 ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
87 if (ret < 0)
88 zlog_warn("Can't set pktinfo option for fd %d",
89 eigrp_sock);
d62a17ae 90 }
7f57883e 91
d62a17ae 92 return eigrp_sock;
7f57883e
DS
93}
94
d62a17ae 95void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
7f57883e 96{
d62a17ae 97 int newbuflen;
98 /* Check if any work has to be done at all. */
99 if (eigrp->maxsndbuflen >= buflen)
100 return;
d62a17ae 101
102 /* Now we try to set SO_SNDBUF to what our caller has requested
103 * (the MTU of a newly added interface). However, if the OS has
104 * truncated the actual buffer size to somewhat less size, try
105 * to detect it and update our records appropriately. The OS
106 * may allocate more buffer space, than requested, this isn't
107 * a error.
108 */
338b8e91
RW
109 setsockopt_so_sendbuf(eigrp->fd, buflen);
110 newbuflen = getsockopt_so_sendbuf(eigrp->fd);
111 if (newbuflen < 0 || newbuflen < (int)buflen)
112 zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
113 __func__, buflen, newbuflen);
114 if (newbuflen >= 0)
115 eigrp->maxsndbuflen = (unsigned int)newbuflen;
116 else
117 zlog_warn("%s: failed to get SO_SNDBUF", __func__);
7f57883e
DS
118}
119
d62a17ae 120int eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p,
121 unsigned int ifindex)
7f57883e 122{
d7c0a89a 123 uint8_t val;
d62a17ae 124 int ret, len;
125
126 val = 0;
127 len = sizeof(val);
128
129 /* Prevent receiving self-origined multicast packets. */
130 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val,
131 len);
132 if (ret < 0)
133 zlog_warn(
134 "can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s",
135 top->fd, safe_strerror(errno));
136
137 /* Explicitly set multicast ttl to 1 -- endo. */
138 val = 1;
139 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val,
140 len);
141 if (ret < 0)
142 zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s",
143 top->fd, safe_strerror(errno));
144
145 ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
146 if (ret < 0)
147 zlog_warn(
37b4b3cc
DS
148 "can't setsockopt IP_MULTICAST_IF (fd %d, addr %pI4, ifindex %u): %s",
149 top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
d62a17ae 150
151 return ret;
7f57883e
DS
152}
153
154/* Join to the EIGRP multicast group. */
d62a17ae 155int eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
156 unsigned int ifindex)
7f57883e 157{
d62a17ae 158 int ret;
159
160 ret = setsockopt_ipv4_multicast(
161 top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4,
162 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
163 if (ret < 0)
164 zlog_warn(
37b4b3cc
DS
165 "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?",
166 top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
d62a17ae 167 else
37b4b3cc
DS
168 zlog_debug("interface %pI4 [%u] join EIGRP Multicast group.",
169 &p->u.prefix4, ifindex);
d62a17ae 170
171 return ret;
7f57883e
DS
172}
173
d62a17ae 174int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
175 unsigned int ifindex)
7f57883e 176{
d62a17ae 177 int ret;
178
179 ret = setsockopt_ipv4_multicast(
180 top->fd, IP_DROP_MEMBERSHIP, p->u.prefix4,
181 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
182 if (ret < 0)
183 zlog_warn(
37b4b3cc
DS
184 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
185 top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
d62a17ae 186 else
37b4b3cc
DS
187 zlog_debug("interface %pI4 [%u] leave EIGRP Multicast group.",
188 &p->u.prefix4, ifindex);
d62a17ae 189
190 return ret;
7f57883e
DS
191}
192
cd6c066e 193int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
7f57883e 194{
d0ac2662 195 struct vrf *vrf = vrf_lookup_by_id(eigrp->vrf_id);
d62a17ae 196 struct route_node *rn;
197 struct interface *ifp;
d62a17ae 198
c4efd0f4 199 rn = route_node_get(eigrp->networks, p);
d62a17ae 200 if (rn->info) {
201 /* There is already same network statement. */
202 route_unlock_node(rn);
203 return 0;
204 }
205
a96029f8 206 struct prefix *pref = prefix_new();
b08dcc3f 207 prefix_copy(pref, p);
d62a17ae 208 rn->info = (void *)pref;
209
210 /* Schedule Router ID Update. */
975a328e 211 if (eigrp->router_id.s_addr == INADDR_ANY)
d62a17ae 212 eigrp_router_id_update(eigrp);
213 /* Run network config now. */
214 /* Get target interface. */
451fda4f 215 FOR_ALL_INTERFACES (vrf, ifp) {
d62a17ae 216 zlog_debug("Setting up %s", ifp->name);
a96029f8 217 eigrp_network_run_interface(eigrp, p, ifp);
d62a17ae 218 }
219 return 1;
7f57883e
DS
220}
221
222/* Check whether interface matches given network
223 * returns: 1, true. 0, false
224 */
952248db 225static int eigrp_network_match_iface(const struct prefix *co_prefix,
d62a17ae 226 const struct prefix *net)
7f57883e 227{
d62a17ae 228 /* new approach: more elegant and conceptually clean */
952248db 229 return prefix_match_network_statement(net, co_prefix);
7f57883e
DS
230}
231
d62a17ae 232static void eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
233 struct interface *ifp)
7f57883e 234{
b748db67 235 struct eigrp_interface *ei;
d62a17ae 236 struct listnode *cnode;
237 struct connected *co;
238
239 /* if interface prefix is match specified prefix,
240 then create socket and join multicast group. */
241 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) {
242
243 if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY))
244 continue;
245
996c9314 246 if (p->family == co->address->family && !ifp->info
952248db 247 && eigrp_network_match_iface(co->address, p)) {
d62a17ae 248
249 ei = eigrp_if_new(eigrp, ifp, co->address);
d62a17ae 250
d62a17ae 251 /* Relate eigrp interface to eigrp instance. */
252 ei->eigrp = eigrp;
253
d62a17ae 254 /* if router_id is not configured, dont bring up
255 * interfaces.
256 * eigrp_router_id_update() will call eigrp_if_update
257 * whenever r-id is configured instead.
258 */
259 if (if_is_operative(ifp))
260 eigrp_if_up(ei);
261 }
262 }
7f57883e
DS
263}
264
d62a17ae 265void eigrp_if_update(struct interface *ifp)
7f57883e 266{
d62a17ae 267 struct listnode *node, *nnode;
268 struct route_node *rn;
7d7acfc7 269 struct eigrp *eigrp;
d62a17ae 270
271 /*
272 * In the event there are multiple eigrp autonymnous systems running,
273 * we need to check eac one and add the interface as approperate
274 */
275 for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
096f7609 276 if (ifp->vrf->vrf_id != eigrp->vrf_id)
88a3b65e
DS
277 continue;
278
d62a17ae 279 /* EIGRP must be on and Router-ID must be configured. */
3a6290bd 280 if (eigrp->router_id.s_addr == INADDR_ANY)
d62a17ae 281 continue;
282
283 /* Run each network for this interface. */
284 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
285 if (rn->info != NULL) {
286 eigrp_network_run_interface(eigrp, &rn->p, ifp);
287 }
288 }
7f57883e
DS
289}
290
cd6c066e 291int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
7f57883e 292{
d62a17ae 293 struct route_node *rn;
294 struct listnode *node, *nnode;
295 struct eigrp_interface *ei;
296 struct prefix *pref;
297
cd6c066e 298 rn = route_node_lookup(eigrp->networks, p);
d62a17ae 299 if (rn == NULL)
300 return 0;
301
302 pref = rn->info;
303 route_unlock_node(rn);
304
cd6c066e 305 if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4))
d62a17ae 306 return 0;
307
63265b5c 308 prefix_ipv4_free((struct prefix_ipv4 **)&rn->info);
d62a17ae 309 route_unlock_node(rn); /* initial reference */
310
311 /* Find interfaces that not configured already. */
312 for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei)) {
952248db 313 bool found = false;
d62a17ae 314
315 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) {
316 if (rn->info == NULL)
317 continue;
318
b245781a 319 if (eigrp_network_match_iface(&ei->address, &rn->p)) {
952248db 320 found = true;
d62a17ae 321 route_unlock_node(rn);
322 break;
323 }
324 }
325
952248db 326 if (!found) {
d62a17ae 327 eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
328 }
329 }
330
331 return 1;
7f57883e
DS
332}
333
d62a17ae 334void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
7f57883e 335{
7f57883e 336}