]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * OSPF network related functions | |
3 | * Copyright (C) 1999 Toshiaki Takada | |
4 | * | |
5 | * This file is part of GNU Zebra. | |
6 | * | |
7 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * GNU Zebra is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
19 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 | * 02111-1307, USA. | |
21 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
25 | #include "thread.h" | |
26 | #include "linklist.h" | |
27 | #include "prefix.h" | |
28 | #include "if.h" | |
29 | #include "sockunion.h" | |
30 | #include "log.h" | |
31 | #include "sockopt.h" | |
edd7c245 | 32 | #include "privs.h" |
33 | ||
34 | extern struct zebra_privs_t ospfd_privs; | |
718e3744 | 35 | |
36 | #include "ospfd/ospfd.h" | |
37 | #include "ospfd/ospf_network.h" | |
38 | #include "ospfd/ospf_interface.h" | |
39 | #include "ospfd/ospf_asbr.h" | |
40 | #include "ospfd/ospf_lsa.h" | |
41 | #include "ospfd/ospf_lsdb.h" | |
42 | #include "ospfd/ospf_neighbor.h" | |
43 | #include "ospfd/ospf_packet.h" | |
b7fe4141 | 44 | #include "ospfd/ospf_dump.h" |
718e3744 | 45 | |
edd7c245 | 46 | |
47 | ||
718e3744 | 48 | /* Join to the OSPF ALL SPF ROUTERS multicast group. */ |
49 | int | |
50 | ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, | |
51 | unsigned int ifindex) | |
52 | { | |
53 | int ret; | |
54 | ||
69bf3a39 DT |
55 | ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, |
56 | htonl (OSPF_ALLSPFROUTERS), | |
718e3744 | 57 | ifindex); |
58 | if (ret < 0) | |
3dc56b5b | 59 | zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " |
60 | "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit " | |
61 | "on # of multicast group memberships has been exceeded?", | |
62 | top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); | |
718e3744 | 63 | else |
ec70497b | 64 | zlog_debug ("interface %s [%u] join AllSPFRouters Multicast group.", |
42c98199 | 65 | inet_ntoa (p->u.prefix4), ifindex); |
718e3744 | 66 | |
67 | return ret; | |
68 | } | |
69 | ||
70 | int | |
71 | ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, | |
72 | unsigned int ifindex) | |
73 | { | |
74 | int ret; | |
75 | ||
69bf3a39 DT |
76 | ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, |
77 | htonl (OSPF_ALLSPFROUTERS), | |
718e3744 | 78 | ifindex); |
79 | if (ret < 0) | |
3dc56b5b | 80 | zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " |
81 | "ifindex %u, AllSPFRouters): %s", | |
82 | top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); | |
718e3744 | 83 | else |
ec70497b PJ |
84 | zlog_debug ("interface %s [%u] leave AllSPFRouters Multicast group.", |
85 | inet_ntoa (p->u.prefix4), ifindex); | |
718e3744 | 86 | |
87 | return ret; | |
88 | } | |
89 | ||
90 | /* Join to the OSPF ALL Designated ROUTERS multicast group. */ | |
91 | int | |
92 | ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int | |
93 | ifindex) | |
94 | { | |
95 | int ret; | |
96 | ||
69bf3a39 DT |
97 | ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, |
98 | htonl (OSPF_ALLDROUTERS), | |
718e3744 | 99 | ifindex); |
100 | if (ret < 0) | |
3dc56b5b | 101 | zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " |
102 | "ifindex %u, AllDRouters): %s; perhaps a kernel limit " | |
103 | "on # of multicast group memberships has been exceeded?", | |
104 | top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); | |
718e3744 | 105 | else |
ec70497b PJ |
106 | zlog_debug ("interface %s [%u] join AllDRouters Multicast group.", |
107 | inet_ntoa (p->u.prefix4), ifindex); | |
718e3744 | 108 | |
109 | return ret; | |
110 | } | |
111 | ||
112 | int | |
113 | ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int | |
114 | ifindex) | |
115 | { | |
116 | int ret; | |
117 | ||
69bf3a39 DT |
118 | ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, |
119 | htonl (OSPF_ALLDROUTERS), | |
718e3744 | 120 | ifindex); |
121 | if (ret < 0) | |
3dc56b5b | 122 | zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " |
123 | "ifindex %u, AllDRouters): %s", | |
124 | top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); | |
718e3744 | 125 | else |
ec70497b PJ |
126 | zlog_debug ("interface %s [%u] leave AllDRouters Multicast group.", |
127 | inet_ntoa (p->u.prefix4), ifindex); | |
718e3744 | 128 | |
129 | return ret; | |
130 | } | |
131 | ||
132 | int | |
133 | ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) | |
134 | { | |
135 | u_char val; | |
136 | int ret, len; | |
137 | ||
138 | val = 0; | |
139 | len = sizeof (val); | |
140 | ||
141 | /* Prevent receiving self-origined multicast packets. */ | |
142 | ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); | |
143 | if (ret < 0) | |
3dc56b5b | 144 | zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s", |
145 | top->fd, safe_strerror(errno)); | |
718e3744 | 146 | |
147 | /* Explicitly set multicast ttl to 1 -- endo. */ | |
148 | val = 1; | |
149 | ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len); | |
150 | if (ret < 0) | |
3dc56b5b | 151 | zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s", |
152 | top->fd, safe_strerror (errno)); | |
718e3744 | 153 | |
69bf3a39 | 154 | ret = setsockopt_ipv4_multicast_if (top->fd, ifindex); |
718e3744 | 155 | if (ret < 0) |
3dc56b5b | 156 | zlog_warn("can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, " |
157 | "ifindex %u): %s", | |
158 | top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); | |
718e3744 | 159 | |
160 | return ret; | |
161 | } | |
162 | ||
163 | int | |
164 | ospf_sock_init (void) | |
165 | { | |
166 | int ospf_sock; | |
1423c809 | 167 | int ret, hincl = 1; |
a78d75b0 DS |
168 | int bufsize = (8 * 1024 * 1024); |
169 | int optval; | |
170 | socklen_t optlen = sizeof(optval); | |
718e3744 | 171 | |
edd7c245 | 172 | if ( ospfd_privs.change (ZPRIVS_RAISE) ) |
173 | zlog_err ("ospf_sock_init: could not raise privs, %s", | |
6099b3b5 | 174 | safe_strerror (errno) ); |
edd7c245 | 175 | |
718e3744 | 176 | ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); |
177 | if (ospf_sock < 0) | |
178 | { | |
0b7d97d2 | 179 | int save_errno = errno; |
edd7c245 | 180 | if ( ospfd_privs.change (ZPRIVS_LOWER) ) |
181 | zlog_err ("ospf_sock_init: could not lower privs, %s", | |
6099b3b5 | 182 | safe_strerror (errno) ); |
0b7d97d2 | 183 | zlog_err ("ospf_read_sock_init: socket: %s", safe_strerror (save_errno)); |
184 | exit(1); | |
718e3744 | 185 | } |
edd7c245 | 186 | |
5bd4189c | 187 | #ifdef IP_HDRINCL |
188 | /* we will include IP header with packet */ | |
189 | ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); | |
190 | if (ret < 0) | |
191 | { | |
0b7d97d2 | 192 | int save_errno = errno; |
5bd4189c | 193 | if ( ospfd_privs.change (ZPRIVS_LOWER) ) |
194 | zlog_err ("ospf_sock_init: could not lower privs, %s", | |
6099b3b5 | 195 | safe_strerror (errno) ); |
0b7d97d2 | 196 | zlog_warn ("Can't set IP_HDRINCL option for fd %d: %s", |
197 | ospf_sock, safe_strerror(save_errno)); | |
5bd4189c | 198 | } |
199 | #elif defined (IPTOS_PREC_INTERNETCONTROL) | |
200 | #warning "IP_HDRINCL not available on this system" | |
201 | #warning "using IPTOS_PREC_INTERNETCONTROL" | |
1423c809 | 202 | ret = setsockopt_ipv4_tos(ospf_sock, IPTOS_PREC_INTERNETCONTROL); |
718e3744 | 203 | if (ret < 0) |
204 | { | |
0b7d97d2 | 205 | int save_errno = errno; |
edd7c245 | 206 | if ( ospfd_privs.change (ZPRIVS_LOWER) ) |
207 | zlog_err ("ospf_sock_init: could not lower privs, %s", | |
6099b3b5 | 208 | safe_strerror (errno) ); |
0b7d97d2 | 209 | zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s", |
210 | tos, ospf_sock, safe_strerror(save_errno)); | |
718e3744 | 211 | close (ospf_sock); /* Prevent sd leak. */ |
212 | return ret; | |
213 | } | |
5bd4189c | 214 | #else /* !IPTOS_PREC_INTERNETCONTROL */ |
215 | #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL" | |
216 | zlog_warn ("IP_HDRINCL option not available"); | |
217 | #endif /* IP_HDRINCL */ | |
718e3744 | 218 | |
ac191232 | 219 | ret = setsockopt_ifindex (AF_INET, ospf_sock, 1); |
220 | ||
2dd8bb4e | 221 | if (ret < 0) |
3dc56b5b | 222 | zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock); |
edd7c245 | 223 | |
224 | if (ospfd_privs.change (ZPRIVS_LOWER)) | |
225 | { | |
226 | zlog_err ("ospf_sock_init: could not lower privs, %s", | |
6099b3b5 | 227 | safe_strerror (errno) ); |
edd7c245 | 228 | } |
a78d75b0 DS |
229 | |
230 | if ((ret = setsockopt (ospf_sock, SOL_SOCKET, SO_RCVBUF, | |
231 | &bufsize, sizeof (bufsize))) < 0) | |
232 | { | |
233 | zlog_err ("Couldn't increase raw rbuf size: %s\n", safe_strerror(errno)); | |
234 | } | |
235 | ||
236 | if ((ret = getsockopt (ospf_sock, SOL_SOCKET, SO_RCVBUF, | |
237 | &optval, &optlen)) < 0) | |
238 | { | |
239 | zlog_err("getsockopt of SO_RCVBUF failed with error %s\n", safe_strerror(errno)); | |
240 | } | |
241 | if (optval < bufsize) | |
242 | { | |
243 | zlog_err("Unable to SO_RCVBUF to %d, set to %d\n", bufsize, optval); | |
244 | } | |
245 | ||
246 | ||
247 | if ((ret = setsockopt (ospf_sock, SOL_SOCKET, SO_SNDBUF, | |
248 | &bufsize, sizeof (bufsize))) < 0) | |
249 | { | |
250 | zlog_err ("Couldn't increase raw wbuf size: %s\n", safe_strerror(errno)); | |
251 | } | |
252 | ||
253 | if ((ret = getsockopt (ospf_sock, SOL_SOCKET, SO_SNDBUF, | |
254 | &optval, &optlen)) < 0) | |
255 | { | |
256 | zlog_err ("getsockopt of SO_SNDBUF failed with error %s\n", safe_strerror(errno)); | |
257 | } | |
258 | if (optval < bufsize) | |
259 | { | |
260 | zlog_err ("Unable to SO_SNDBUF to %d, set to %d\n", bufsize, optval); | |
261 | } | |
718e3744 | 262 | |
263 | return ospf_sock; | |
264 | } | |
b7fe4141 DO |
265 | |
266 | void | |
0798cee3 | 267 | ospf_adjust_sndbuflen (struct ospf * ospf, unsigned int buflen) |
b7fe4141 DO |
268 | { |
269 | int ret, newbuflen; | |
270 | /* Check if any work has to be done at all. */ | |
271 | if (ospf->maxsndbuflen >= buflen) | |
272 | return; | |
273 | if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) | |
274 | zlog_debug ("%s: adjusting OSPF send buffer size to %d", | |
275 | __func__, buflen); | |
276 | if (ospfd_privs.change (ZPRIVS_RAISE)) | |
277 | zlog_err ("%s: could not raise privs, %s", __func__, | |
278 | safe_strerror (errno)); | |
279 | /* Now we try to set SO_SNDBUF to what our caller has requested | |
f102e75f DO |
280 | * (the MTU of a newly added interface). However, if the OS has |
281 | * truncated the actual buffer size to somewhat less size, try | |
282 | * to detect it and update our records appropriately. The OS | |
283 | * may allocate more buffer space, than requested, this isn't | |
284 | * a error. | |
b7fe4141 DO |
285 | */ |
286 | ret = setsockopt_so_sendbuf (ospf->fd, buflen); | |
287 | newbuflen = getsockopt_so_sendbuf (ospf->fd); | |
0798cee3 AC |
288 | if (ret < 0 || newbuflen < 0 || newbuflen < (int) buflen) |
289 | zlog_warn ("%s: tried to set SO_SNDBUF to %u, but got %d", | |
b7fe4141 DO |
290 | __func__, buflen, newbuflen); |
291 | if (newbuflen >= 0) | |
0798cee3 | 292 | ospf->maxsndbuflen = (unsigned int)newbuflen; |
b7fe4141 DO |
293 | else |
294 | zlog_warn ("%s: failed to get SO_SNDBUF", __func__); | |
295 | if (ospfd_privs.change (ZPRIVS_LOWER)) | |
296 | zlog_err ("%s: could not lower privs, %s", __func__, | |
297 | safe_strerror (errno)); | |
298 | } |