]> git.proxmox.com Git - mirror_frr.git/blame - zebra/if_ioctl_solaris.c
Merge pull request #3775 from pguibert6WIND/ospf_missing_interface_handling_2
[mirror_frr.git] / zebra / if_ioctl_solaris.c
CommitLineData
8842468c 1/*
2 * Interface looking up by ioctl () on Solaris.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
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 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
8842468c 20 */
21
22#include <zebra.h>
23
ddfeb486
DL
24#ifdef SUNOS_5
25
8842468c 26#include "if.h"
27#include "sockunion.h"
28#include "prefix.h"
29#include "ioctl.h"
30#include "connected.h"
31#include "memory.h"
4a1ab8e4 32#include "zebra_memory.h"
8842468c 33#include "log.h"
48a46fa0 34#include "privs.h"
8f7d9fc0 35#include "vrf.h"
82283592 36#include "vty.h"
174482ef 37#include "lib_errors.h"
8842468c 38
39#include "zebra/interface.h"
8d610213 40#include "zebra/ioctl_solaris.h"
8f7d9fc0 41#include "zebra/rib.h"
ae9eebca 42#include "zebra/rt.h"
364fed6b 43#include "zebra/zebra_errors.h"
8842468c 44
d62a17ae 45static int if_get_addr(struct interface *, struct sockaddr *, const char *);
46static void interface_info_ioctl(struct interface *);
48a46fa0 47extern struct zebra_privs_t zserv_privs;
8842468c 48
d62a17ae 49static int interface_list_ioctl(int af)
8842468c 50{
d62a17ae 51 int ret;
52 int sock;
8842468c 53#define IFNUM_BASE 32
d62a17ae 54 struct lifnum lifn;
55 int ifnum;
56 struct lifreq *lifreq;
57 struct lifconf lifconf;
58 struct interface *ifp;
59 int n;
d62a17ae 60 size_t needed, lastneeded = 0;
61 char *buf = NULL;
4c634658 62 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
d62a17ae 63
01b9e3fd 64 frr_elevate_privs(&zserv_privs) {
01b9e3fd 65 sock = socket(af, SOCK_DGRAM, 0);
6bb30c2c 66 }
d62a17ae 67
6bb30c2c 68 if (sock < 0) {
450971aa 69 flog_err_sys(EC_LIB_SOCKET, "Can't make %s socket stream: %s",
9df414fe
QY
70 (af == AF_INET ? "AF_INET" : "AF_INET6"),
71 safe_strerror(errno));
6bb30c2c
DL
72 return -1;
73 }
d62a17ae 74
6bb30c2c
DL
75calculate_lifc_len:
76 frr_elevate_privs(&zserv_privs) {
01b9e3fd 77 lifn.lifn_family = af;
6bb30c2c
DL
78 lifn.lifn_flags = LIFC_NOXMIT;
79 /* we want NOXMIT interfaces too */
01b9e3fd 80 ret = ioctl(sock, SIOCGLIFNUM, &lifn);
01b9e3fd 81 }
d62a17ae 82
83 if (ret < 0) {
450971aa 84 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe 85 "interface_list_ioctl: SIOCGLIFNUM failed %s",
e991eff5 86 safe_strerror(errno));
d62a17ae 87 close(sock);
88 return -1;
89 }
90 ifnum = lifn.lifn_count;
91
92 /*
93 * When calculating the buffer size needed, add a small number
94 * of interfaces to those we counted. We do this to capture
95 * the interface status of potential interfaces which may have
96 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
97 */
98 needed = (ifnum + 4) * sizeof(struct lifreq);
99 if (needed > lastneeded || needed < lastneeded / 2) {
100 if (buf != NULL)
101 XFREE(MTYPE_TMP, buf);
0ce1ca80 102 buf = XMALLOC(MTYPE_TMP, needed);
d62a17ae 103 }
104 lastneeded = needed;
105
106 lifconf.lifc_family = af;
107 lifconf.lifc_flags = LIFC_NOXMIT;
108 lifconf.lifc_len = needed;
109 lifconf.lifc_buf = buf;
110
6bb30c2c
DL
111 frr_elevate_privs(&zserv_privs) {
112 ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
113 }
d62a17ae 114
115 if (ret < 0) {
116 if (errno == EINVAL)
6bb30c2c 117 goto calculate_lifc_len;
d62a17ae 118
450971aa 119 flog_err_sys(EC_LIB_SYSTEM_CALL, "SIOCGLIFCONF: %s",
9df414fe 120 safe_strerror(errno));
d62a17ae 121 goto end;
122 }
123
d62a17ae 124 /* Allocate interface. */
125 lifreq = lifconf.lifc_req;
126
127 for (n = 0; n < lifconf.lifc_len; n += sizeof(struct lifreq)) {
128 /* we treat Solaris logical interfaces as addresses, because
129 * that is
130 * how PF_ROUTE on Solaris treats them. Hence we can not
131 * directly use
132 * the lifreq_name to get the ifp. We need to normalise the
133 * name
134 * before attempting get.
135 *
136 * Solaris logical interface names are in the form of:
137 * <interface name>:<logical interface id>
138 */
139 unsigned int normallen = 0;
140 uint64_t lifflags;
141
142 /* We should exclude ~IFF_UP interfaces, as we'll find out about
143 * them
144 * coming up later through RTM_NEWADDR message on the route
145 * socket.
146 */
147 if (if_get_flags_direct(lifreq->lifr_name, &lifflags,
148 lifreq->lifr_addr.ss_family)
149 || !CHECK_FLAG(lifflags, IFF_UP)) {
150 lifreq++;
151 continue;
152 }
153
154 /* Find the normalised name */
155 while ((normallen < sizeof(lifreq->lifr_name))
156 && (*(lifreq->lifr_name + normallen) != '\0')
157 && (*(lifreq->lifr_name + normallen) != ':'))
158 normallen++;
159
4c634658 160 ifp = if_get_by_name(lifreq->lifr_name, vrf);
d62a17ae 161
162 if (lifreq->lifr_addr.ss_family == AF_INET)
163 ifp->flags |= IFF_IPV4;
164
165 if (lifreq->lifr_addr.ss_family == AF_INET6) {
166 ifp->flags |= IFF_IPV6;
167 }
168
169 if_add_update(ifp);
170
171 interface_info_ioctl(ifp);
172
173 /* If a logical interface pass the full name so it can be
174 * as a label on the address
175 */
176 if (*(lifreq->lifr_name + normallen) != '\0')
177 if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
178 lifreq->lifr_name);
179 else
180 if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
181 NULL);
182
183 /* Poke the interface flags. Lets IFF_UP mangling kick in */
184 if_flags_update(ifp, ifp->flags);
185
186 lifreq++;
187 }
8842468c 188
189end:
d62a17ae 190 close(sock);
191 XFREE(MTYPE_TMP, lifconf.lifc_buf);
192 return ret;
8842468c 193}
194
195/* Get interface's index by ioctl. */
d62a17ae 196static int if_get_index(struct interface *ifp)
8842468c 197{
d62a17ae 198 int ret;
199 struct lifreq lifreq;
8842468c 200
d62a17ae 201 lifreq_set_name(&lifreq, ifp->name);
8842468c 202
d62a17ae 203 if (ifp->flags & IFF_IPV4)
204 ret = AF_IOCTL(AF_INET, SIOCGLIFINDEX, (caddr_t)&lifreq);
205 else if (ifp->flags & IFF_IPV6)
206 ret = AF_IOCTL(AF_INET6, SIOCGLIFINDEX, (caddr_t)&lifreq);
207 else
208 ret = -1;
8842468c 209
d62a17ae 210 if (ret < 0) {
450971aa 211 flog_err_sys(EC_LIB_SYSTEM_CALL, "SIOCGLIFINDEX(%s) failed",
9df414fe 212 ifp->name);
d62a17ae 213 return ret;
214 }
8842468c 215
d62a17ae 216/* OK we got interface index. */
8842468c 217#ifdef ifr_ifindex
ff880b78 218 if_set_index(ifp, lifreq.lifr_ifindex);
8842468c 219#else
ff880b78 220 if_set_index(ifp, lifreq.lifr_index);
8842468c 221#endif
d62a17ae 222 return ifp->ifindex;
8842468c 223}
224
225
226/* Interface address lookup by ioctl. This function only looks up
227 IPv4 address. */
d62a17ae 228#define ADDRLEN(sa) \
229 (((sa)->sa_family == AF_INET ? sizeof(struct sockaddr_in) \
230 : sizeof(struct sockaddr_in6)))
8842468c 231
232#define SIN(s) ((struct sockaddr_in *)(s))
233#define SIN6(s) ((struct sockaddr_in6 *)(s))
234
0752ef0b 235/* Retrieve address information for the given ifp */
d62a17ae 236static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
237 const char *label)
8842468c 238{
d62a17ae 239 int ret;
240 struct lifreq lifreq;
241 struct sockaddr_storage mask, dest;
242 char *dest_pnt = NULL;
d7c0a89a 243 uint8_t prefixlen = 0;
d62a17ae 244 afi_t af;
245 int flags = 0;
246
247 /* Interface's name and address family.
248 * We need to use the logical interface name / label, if we've been
249 * given one, in order to get the right address
250 */
138a4965
QY
251 strlcpy(lifreq.lifr_name, (label ? label : ifp->name),
252 sizeof(lifreq.lifr_name));
d62a17ae 253
254 /* Interface's address. */
255 memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr));
256 af = addr->sa_family;
257
258 /* Point to point or broad cast address pointer init. */
259 dest_pnt = NULL;
260
261 if (AF_IOCTL(af, SIOCGLIFDSTADDR, (caddr_t)&lifreq) >= 0) {
262 memcpy(&dest, &lifreq.lifr_dstaddr, ADDRLEN(addr));
263 if (af == AF_INET)
264 dest_pnt = (char *)&(SIN(&dest)->sin_addr);
265 else
266 dest_pnt = (char *)&(SIN6(&dest)->sin6_addr);
267 flags = ZEBRA_IFA_PEER;
fb6724a6 268 }
d62a17ae 269
270 if (af == AF_INET) {
271 ret = if_ioctl(SIOCGLIFNETMASK, (caddr_t)&lifreq);
272
273 if (ret < 0) {
274 if (errno != EADDRNOTAVAIL) {
450971aa 275 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
276 "SIOCGLIFNETMASK (%s) fail: %s",
277 ifp->name, safe_strerror(errno));
d62a17ae 278 return ret;
279 }
280 return 0;
281 }
282 memcpy(&mask, &lifreq.lifr_addr, ADDRLEN(addr));
283
284 prefixlen = ip_masklen(SIN(&mask)->sin_addr);
285 if (!dest_pnt
286 && (if_ioctl(SIOCGLIFBRDADDR, (caddr_t)&lifreq) >= 0)) {
287 memcpy(&dest, &lifreq.lifr_broadaddr,
288 sizeof(struct sockaddr_in));
289 dest_pnt = (char *)&SIN(&dest)->sin_addr;
290 }
291 } else if (af == AF_INET6) {
292 if (if_ioctl_ipv6(SIOCGLIFSUBNET, (caddr_t)&lifreq) < 0) {
293 if (ifp->flags & IFF_POINTOPOINT)
294 prefixlen = IPV6_MAX_BITLEN;
295 else
450971aa 296 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
297 "SIOCGLIFSUBNET (%s) fail: %s",
298 ifp->name, safe_strerror(errno));
d62a17ae 299 } else {
300 prefixlen = lifreq.lifr_addrlen;
301 }
fb6724a6 302 }
8842468c 303
d62a17ae 304 /* Set address to the interface. */
305 if (af == AF_INET)
306 connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
cde1af84
AK
307 (struct in_addr *)dest_pnt, label,
308 METRIC_MAX);
d62a17ae 309 else if (af == AF_INET6)
60c0687a 310 connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
cde1af84 311 prefixlen, label, METRIC_MAX);
8842468c 312
d62a17ae 313 return 0;
8842468c 314}
315
316/* Fetch interface information via ioctl(). */
d62a17ae 317static void interface_info_ioctl(struct interface *ifp)
8842468c 318{
d62a17ae 319 if_get_index(ifp);
320 if_get_flags(ifp);
321 if_get_mtu(ifp);
322 if_get_metric(ifp);
8842468c 323}
324
325/* Lookup all interface information. */
d62a17ae 326void interface_list(struct zebra_ns *zns)
8842468c 327{
d62a17ae 328 if (zns->ns_id != NS_DEFAULT) {
9df414fe 329 zlog_debug("interface_list: ignore NS %u", zns->ns_id);
d62a17ae 330 return;
331 }
332 interface_list_ioctl(AF_INET);
333 interface_list_ioctl(AF_INET6);
334 interface_list_ioctl(AF_UNSPEC);
8842468c 335}
336
d62a17ae 337struct connected *if_lookup_linklocal(struct interface *ifp)
8842468c 338{
d62a17ae 339 struct listnode *node;
340 struct connected *ifc;
8842468c 341
d62a17ae 342 if (ifp == NULL)
343 return NULL;
8842468c 344
d62a17ae 345 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
346 if ((ifc->address->family == AF_INET6)
347 && (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)))
348 return ifc;
349 }
5b73a671 350
d62a17ae 351 return NULL;
8842468c 352}
ddfeb486
DL
353
354#endif /* SUNOS_5 */