1 /*- 2 * Copyright (c) 2015 Dmitry Chagin <dchagin@FreeBSD.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/kernel.h> 29 #include <sys/ctype.h> 30 #include <sys/eventhandler.h> 31 #include <sys/jail.h> 32 #include <sys/socket.h> 33 #include <sys/sysctl.h> 34 #include <net/if.h> 35 #include <net/if_dl.h> 36 #include <net/if_types.h> 37 #include <net/if_var.h> 38 #include <net/if_private.h> 39 #include <net/vnet.h> 40 41 #include <compat/linux/linux.h> 42 #include <compat/linux/linux_common.h> 43 #include <compat/linux/linux_mib.h> 44 45 _Static_assert(LINUX_IFNAMSIZ == IFNAMSIZ, "Linux IFNAMSIZ"); 46 47 static bool use_real_ifnames = true; 48 static int 49 sysctl_linux_use_real_ifnames(SYSCTL_HANDLER_ARGS) 50 { 51 int error; 52 53 error = sysctl_handle_bool(oidp, &use_real_ifnames, arg2, req); 54 if (error != 0 || req->newptr == NULL) 55 return (error); 56 if (!use_real_ifnames) 57 gone_in(17, "linux(4): %s: conversion of native interface " 58 "names to ethN is not needed to emulate modern Linux. " 59 "See https://systemd.io/PREDICTABLE_INTERFACE_NAMES. ", 60 oidp->oid_name); 61 return (0); 62 } 63 SYSCTL_PROC(_compat_linux, OID_AUTO, use_real_ifnames, 64 CTLTYPE_U8 | CTLFLAG_RWTUN, 0, 0, sysctl_linux_use_real_ifnames, "CU", 65 "Use FreeBSD interface names instead of generating ethN aliases"); 66 67 VNET_DEFINE_STATIC(struct unrhdr *, linux_eth_unr); 68 #define V_linux_eth_unr VNET(linux_eth_unr) 69 70 static eventhandler_tag ifnet_arrival_tag; 71 static eventhandler_tag ifnet_departure_tag; 72 73 static void 74 linux_ifnet_arrival(void *arg __unused, struct ifnet *ifp) 75 { 76 if (ifp->if_type == IFT_ETHER) 77 ifp->if_linux_ethno = alloc_unr(V_linux_eth_unr); 78 } 79 80 static void 81 linux_ifnet_departure(void *arg __unused, struct ifnet *ifp) 82 { 83 if (ifp->if_type == IFT_ETHER) 84 free_unr(V_linux_eth_unr, ifp->if_linux_ethno); 85 } 86 87 void 88 linux_ifnet_init(void) 89 { 90 ifnet_arrival_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event, 91 linux_ifnet_arrival, NULL, EVENTHANDLER_PRI_FIRST); 92 ifnet_departure_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, 93 linux_ifnet_departure, NULL, EVENTHANDLER_PRI_LAST); 94 } 95 96 void 97 linux_ifnet_uninit(void) 98 { 99 EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ifnet_arrival_tag); 100 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifnet_departure_tag); 101 } 102 103 static void 104 linux_ifnet_vnet_init(void *arg __unused) 105 { 106 struct epoch_tracker et; 107 struct if_iter it; 108 if_t ifp; 109 110 V_linux_eth_unr = new_unrhdr(0, INT_MAX, NULL); 111 NET_EPOCH_ENTER(et); 112 for (ifp = if_iter_start(&it); ifp != NULL; ifp = if_iter_next(&it)) 113 linux_ifnet_arrival(NULL, ifp); 114 NET_EPOCH_EXIT(et); 115 } 116 VNET_SYSINIT(linux_ifnet_vnet_init, SI_SUB_PROTO_IF, SI_ORDER_ANY, 117 linux_ifnet_vnet_init, NULL); 118 119 static void 120 linux_ifnet_vnet_uninit(void *arg __unused) 121 { 122 /* 123 * All cloned interfaces are already gone at this point, as well 124 * as interfaces that were if_vmove'd into this vnet. However, 125 * if a jail has created IFT_ETHER interfaces in self, or has had 126 * physical Ethernet drivers attached in self, than we may have 127 * allocated entries in the unr(9), so clear it to avoid KASSERT. 128 */ 129 clear_unrhdr(V_linux_eth_unr); 130 delete_unrhdr(V_linux_eth_unr); 131 } 132 VNET_SYSUNINIT(linux_ifnet_vnet_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY, 133 linux_ifnet_vnet_uninit, NULL); 134 135 /* 136 * Translate a FreeBSD interface name to a Linux interface name 137 * by interface index, and return the number of bytes copied to lxname. 138 */ 139 int 140 ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len) 141 { 142 struct epoch_tracker et; 143 struct ifnet *ifp; 144 int ret; 145 146 ret = 0; 147 CURVNET_SET(TD_TO_VNET(curthread)); 148 NET_EPOCH_ENTER(et); 149 ifp = ifnet_byindex(idx); 150 if (ifp != NULL) 151 ret = ifname_bsd_to_linux_ifp(ifp, lxname, len); 152 NET_EPOCH_EXIT(et); 153 CURVNET_RESTORE(); 154 return (ret); 155 } 156 157 /* 158 * Translate a FreeBSD interface name to a Linux interface name, 159 * and return the number of bytes copied to lxname, 0 if interface 160 * not found, -1 on error. 161 */ 162 int 163 ifname_bsd_to_linux_ifp(const struct ifnet *ifp, char *lxname, size_t len) 164 { 165 /* 166 * Linux loopback interface name is lo (not lo0), 167 * we translate lo to lo0, loX to loX. 168 */ 169 if (ifp->if_type == IFT_LOOP && 170 strncmp(ifp->if_xname, "lo0", IFNAMSIZ) == 0) 171 return (strlcpy(lxname, "lo", len)); 172 173 /* Short-circuit non ethernet interfaces. */ 174 if (ifp->if_type != IFT_ETHER || use_real_ifnames) 175 return (strlcpy(lxname, ifp->if_xname, len)); 176 177 /* Determine the (relative) unit number for ethernet interfaces. */ 178 return (snprintf(lxname, len, "eth%d", ifp->if_linux_ethno)); 179 } 180 181 /* 182 * Translate a Linux interface name to a FreeBSD interface name, 183 * and return the associated ifnet structure 184 * bsdname and lxname need to be least IFNAMSIZ bytes long, but 185 * can point to the same buffer. 186 */ 187 struct ifname_linux_to_ifp_cb_s { 188 bool is_lo; 189 bool is_eth; 190 int unit; 191 const char *lxname; 192 if_t ifp; 193 }; 194 195 static int 196 ifname_linux_to_ifp_cb(if_t ifp, void *arg) 197 { 198 struct ifname_linux_to_ifp_cb_s *cbs = arg; 199 200 NET_EPOCH_ASSERT(); 201 202 /* 203 * Allow Linux programs to use FreeBSD names. Don't presume 204 * we never have an interface named "eth", so don't make 205 * the test optional based on is_eth. 206 */ 207 if (strncmp(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0) 208 goto out; 209 if (cbs->is_eth && ifp->if_type == IFT_ETHER && 210 ifp->if_linux_ethno == cbs->unit) 211 goto out; 212 if (cbs->is_lo && ifp->if_type == IFT_LOOP) 213 goto out; 214 return (0); 215 216 out: 217 cbs->ifp = ifp; 218 return (1); 219 } 220 221 struct ifnet * 222 ifname_linux_to_ifp(const char *lxname) 223 { 224 struct ifname_linux_to_ifp_cb_s arg = { 225 .lxname = lxname, 226 }; 227 int len; 228 char *ep; 229 230 NET_EPOCH_ASSERT(); 231 232 for (len = 0; len < LINUX_IFNAMSIZ; ++len) 233 if (!isalpha(lxname[len]) || lxname[len] == '\0') 234 break; 235 if (len == 0 || len == LINUX_IFNAMSIZ) 236 return (NULL); 237 /* 238 * Linux loopback interface name is lo (not lo0), 239 * we translate lo to lo0, loX to loX. 240 */ 241 arg.is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0); 242 arg.unit = (int)strtoul(lxname + len, &ep, 10); 243 if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) && 244 arg.is_lo == 0) 245 return (NULL); 246 arg.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0); 247 248 if_foreach(ifname_linux_to_ifp_cb, &arg); 249 return (arg.ifp); 250 } 251 252 int 253 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) 254 { 255 struct epoch_tracker et; 256 struct ifnet *ifp; 257 258 CURVNET_SET(TD_TO_VNET(td)); 259 NET_EPOCH_ENTER(et); 260 ifp = ifname_linux_to_ifp(lxname); 261 if (ifp != NULL && bsdname != NULL) 262 strlcpy(bsdname, if_name(ifp), IFNAMSIZ); 263 NET_EPOCH_EXIT(et); 264 CURVNET_RESTORE(); 265 return (ifp != NULL ? 0 : EINVAL); 266 } 267 268 unsigned short 269 linux_ifflags(struct ifnet *ifp) 270 { 271 unsigned short flags; 272 273 NET_EPOCH_ASSERT(); 274 275 flags = if_getflags(ifp) | if_getdrvflags(ifp); 276 return (bsd_to_linux_ifflags(flags)); 277 } 278 279 unsigned short 280 bsd_to_linux_ifflags(int fl) 281 { 282 unsigned short flags = 0; 283 284 if (fl & IFF_UP) 285 flags |= LINUX_IFF_UP; 286 if (fl & IFF_BROADCAST) 287 flags |= LINUX_IFF_BROADCAST; 288 if (fl & IFF_DEBUG) 289 flags |= LINUX_IFF_DEBUG; 290 if (fl & IFF_LOOPBACK) 291 flags |= LINUX_IFF_LOOPBACK; 292 if (fl & IFF_POINTOPOINT) 293 flags |= LINUX_IFF_POINTOPOINT; 294 if (fl & IFF_DRV_RUNNING) 295 flags |= LINUX_IFF_RUNNING; 296 if (fl & IFF_NOARP) 297 flags |= LINUX_IFF_NOARP; 298 if (fl & IFF_PROMISC) 299 flags |= LINUX_IFF_PROMISC; 300 if (fl & IFF_ALLMULTI) 301 flags |= LINUX_IFF_ALLMULTI; 302 if (fl & IFF_MULTICAST) 303 flags |= LINUX_IFF_MULTICAST; 304 return (flags); 305 } 306 307 static u_int 308 linux_ifhwaddr_cb(void *arg, struct ifaddr *ifa, u_int count) 309 { 310 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; 311 struct l_sockaddr *lsa = arg; 312 313 if (count > 0) 314 return (0); 315 if (sdl->sdl_type != IFT_ETHER) 316 return (0); 317 bzero(lsa, sizeof(*lsa)); 318 lsa->sa_family = LINUX_ARPHRD_ETHER; 319 bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN); 320 return (1); 321 } 322 323 int 324 linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa) 325 { 326 327 NET_EPOCH_ASSERT(); 328 329 if (ifp->if_type == IFT_LOOP) { 330 bzero(lsa, sizeof(*lsa)); 331 lsa->sa_family = LINUX_ARPHRD_LOOPBACK; 332 return (0); 333 } 334 if (ifp->if_type != IFT_ETHER) 335 return (ENOENT); 336 if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0) 337 return (0); 338 return (ENOENT); 339 } 340