1 /* 2 * Copyright (c) 2010 Kip Macy. All rights reserved. 3 * Copyright (C) 2017 THL A29 Limited, a Tencent company. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * Derived in part from libplebnet's pn_veth.c. 27 * 28 */ 29 30 #include <sys/ctype.h> 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/socket.h> 35 #include <sys/socketvar.h> 36 #include <sys/module.h> 37 #include <sys/kernel.h> 38 #include <sys/proc.h> 39 #include <sys/kthread.h> 40 #include <sys/sched.h> 41 #include <sys/sockio.h> 42 43 #include <net/if.h> 44 #include <net/if_var.h> 45 #include <net/if_types.h> 46 #include <net/ethernet.h> 47 #include <net/if_arp.h> 48 #include <net/if_tap.h> 49 #include <net/if_dl.h> 50 #include <net/route.h> 51 52 #include <netinet/in.h> 53 #include <netinet/in_var.h> 54 55 #include <machine/atomic.h> 56 57 #include "ff_veth.h" 58 #include "ff_config.h" 59 #include "ff_dpdk_if.h" 60 61 struct ff_veth_softc { 62 struct ifnet *ifp; 63 uint8_t mac[ETHER_ADDR_LEN]; 64 char host_ifname[IF_NAMESIZE]; 65 66 in_addr_t ip; 67 in_addr_t netmask; 68 in_addr_t broadcast; 69 in_addr_t gateway; 70 71 struct ff_dpdk_if_context *host_ctx; 72 }; 73 74 static int 75 ff_veth_config(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) 76 { 77 memcpy(sc->mac, cfg->mac, ETHER_ADDR_LEN); 78 inet_pton(AF_INET, cfg->addr, &sc->ip); 79 inet_pton(AF_INET, cfg->netmask, &sc->netmask); 80 inet_pton(AF_INET, cfg->broadcast, &sc->broadcast); 81 inet_pton(AF_INET, cfg->gateway, &sc->gateway); 82 83 return 0; 84 } 85 86 static void 87 ff_veth_init(void *arg) 88 { 89 struct ff_veth_softc *sc = arg; 90 struct ifnet *ifp = sc->ifp; 91 92 ifp->if_drv_flags |= IFF_DRV_RUNNING; 93 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 94 } 95 96 static void 97 ff_veth_start(struct ifnet *ifp) 98 { 99 /* nothing to do */ 100 } 101 102 static void 103 ff_veth_stop(struct ff_veth_softc *sc) 104 { 105 struct ifnet *ifp = sc->ifp; 106 107 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); 108 } 109 110 static int 111 ff_veth_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 112 { 113 int error = 0; 114 struct ff_veth_softc *sc = ifp->if_softc; 115 116 switch (cmd) { 117 case SIOCSIFFLAGS: 118 if (ifp->if_flags & IFF_UP) { 119 ff_veth_init(sc); 120 } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 121 ff_veth_stop(sc); 122 break; 123 default: 124 error = ether_ioctl(ifp, cmd, data); 125 break; 126 } 127 128 return (error); 129 } 130 131 int 132 ff_mbuf_copydata(void *m, void *data, int off, int len) 133 { 134 int ret; 135 struct mbuf *mb = (struct mbuf *)m; 136 137 if (off + len > mb->m_pkthdr.len) { 138 return -1; 139 } 140 141 m_copydata(mb, off, len, data); 142 143 return 0; 144 } 145 146 void 147 ff_mbuf_tx_offload(void *m, struct ff_tx_offload *offload) 148 { 149 struct mbuf *mb = (struct mbuf *)m; 150 if (mb->m_pkthdr.csum_flags & CSUM_IP) { 151 offload->ip_csum = 1; 152 } 153 154 if (mb->m_pkthdr.csum_flags & CSUM_TCP) { 155 offload->tcp_csum = 1; 156 } 157 158 if (mb->m_pkthdr.csum_flags & CSUM_UDP) { 159 offload->udp_csum = 1; 160 } 161 162 if (mb->m_pkthdr.csum_flags & CSUM_SCTP) { 163 offload->sctp_csum = 1; 164 } 165 166 if (mb->m_pkthdr.csum_flags & CSUM_TSO) { 167 offload->tso_seg_size = mb->m_pkthdr.tso_segsz; 168 } 169 } 170 171 void 172 ff_mbuf_free(void *m) 173 { 174 m_freem((struct mbuf *)m); 175 } 176 177 static void 178 ff_mbuf_ext_free(struct mbuf *m, void *arg1, void *arg2) 179 { 180 ff_dpdk_pktmbuf_free(arg1); 181 } 182 183 void * 184 ff_mbuf_gethdr(void *pkt, uint16_t total, void *data, 185 uint16_t len, uint8_t rx_csum) 186 { 187 struct mbuf *m = m_gethdr(M_NOWAIT, MT_DATA); 188 if (m == NULL) { 189 return NULL; 190 } 191 192 if (m_pkthdr_init(m, M_NOWAIT) != 0) { 193 return NULL; 194 } 195 196 m_extadd(m, data, len, ff_mbuf_ext_free, pkt, NULL, 0, EXT_DISPOSABLE); 197 198 m->m_pkthdr.len = total; 199 m->m_len = len; 200 m->m_next = NULL; 201 m->m_nextpkt = NULL; 202 203 if (rx_csum) { 204 m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | 205 CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 206 m->m_pkthdr.csum_data = 0xffff; 207 } 208 209 return (void *)m; 210 } 211 212 void * 213 ff_mbuf_get(void *m, void *data, uint16_t len) 214 { 215 struct mbuf *prev = (struct mbuf *)m; 216 struct mbuf *mb = m_get(M_NOWAIT, MT_DATA); 217 218 if (mb == NULL) { 219 return NULL; 220 } 221 222 m_extadd(mb, data, len, NULL, NULL, NULL, 0, 0); 223 224 mb->m_next = NULL; 225 mb->m_nextpkt = NULL; 226 mb->m_len = len; 227 228 if (prev != NULL) { 229 prev->m_next = mb; 230 } 231 232 return (void *)mb; 233 } 234 235 void 236 ff_veth_process_packet(void *arg, void *m) 237 { 238 struct ifnet *ifp = (struct ifnet *)arg; 239 struct mbuf *mb = (struct mbuf *)m; 240 241 mb->m_pkthdr.rcvif = ifp; 242 243 ifp->if_input(ifp, mb); 244 } 245 246 static int 247 ff_veth_transmit(struct ifnet *ifp, struct mbuf *m) 248 { 249 struct ff_veth_softc *sc = (struct ff_veth_softc *)ifp->if_softc; 250 return ff_dpdk_if_send(sc->host_ctx, (void*)m, m->m_pkthdr.len); 251 } 252 253 static void 254 ff_veth_qflush(struct ifnet *ifp) 255 { 256 257 } 258 259 static int 260 ff_veth_setaddr(struct ff_veth_softc *sc) 261 { 262 struct in_aliasreq req; 263 bzero(&req, sizeof req); 264 strcpy(req.ifra_name, sc->ifp->if_dname); 265 266 struct sockaddr_in sa; 267 bzero(&sa, sizeof(sa)); 268 sa.sin_len = sizeof(sa); 269 sa.sin_family = AF_INET; 270 sa.sin_addr.s_addr = sc->ip; 271 bcopy(&sa, &req.ifra_addr, sizeof(sa)); 272 273 sa.sin_addr.s_addr = sc->netmask; 274 bcopy(&sa, &req.ifra_mask, sizeof(sa)); 275 276 sa.sin_addr.s_addr = sc->broadcast; 277 bcopy(&sa, &req.ifra_broadaddr, sizeof(sa)); 278 279 struct socket *so = NULL; 280 socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread); 281 int ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread); 282 283 sofree(so); 284 285 return ret; 286 } 287 288 static int 289 ff_veth_set_gateway(struct ff_veth_softc *sc) 290 { 291 struct sockaddr_in gw; 292 bzero(&gw, sizeof(gw)); 293 gw.sin_len = sizeof(gw); 294 gw.sin_family = AF_INET; 295 gw.sin_addr.s_addr = sc->gateway; 296 297 struct sockaddr_in dst; 298 bzero(&dst, sizeof(dst)); 299 dst.sin_len = sizeof(dst); 300 dst.sin_family = AF_INET; 301 dst.sin_addr.s_addr = 0; 302 303 struct sockaddr_in nm; 304 bzero(&nm, sizeof(nm)); 305 nm.sin_len = sizeof(nm); 306 nm.sin_family = AF_INET; 307 nm.sin_addr.s_addr = 0; 308 309 return rtrequest_fib(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw, 310 (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 311 } 312 313 static int 314 ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) 315 { 316 struct ifnet *ifp; 317 318 ifp = sc->ifp = if_alloc(IFT_ETHER); 319 320 ifp->if_init = ff_veth_init; 321 ifp->if_softc = sc; 322 323 if_initname(ifp, sc->host_ifname, IF_DUNIT_NONE); 324 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 325 ifp->if_ioctl = ff_veth_ioctl; 326 ifp->if_start = ff_veth_start; 327 ifp->if_transmit = ff_veth_transmit; 328 ifp->if_qflush = ff_veth_qflush; 329 ether_ifattach(ifp, sc->mac); 330 331 if (cfg->hw_features.rx_csum) { 332 ifp->if_capabilities |= IFCAP_RXCSUM; 333 } 334 if (cfg->hw_features.tx_csum_ip) { 335 ifp->if_capabilities |= IFCAP_TXCSUM; 336 ifp->if_hwassist |= CSUM_IP; 337 } 338 if (cfg->hw_features.tx_csum_l4) { 339 ifp->if_hwassist |= CSUM_DELAY_DATA; 340 } 341 if (cfg->hw_features.tx_tso) { 342 ifp->if_capabilities |= IFCAP_TSO; 343 ifp->if_hwassist |= CSUM_TSO; 344 } 345 346 ifp->if_capenable = ifp->if_capabilities; 347 348 sc->host_ctx = ff_dpdk_register_if((void *)sc, (void *)sc->ifp, cfg); 349 if (sc->host_ctx == NULL) { 350 printf("%s: Failed to register dpdk interface\n", sc->host_ifname); 351 return -1; 352 } 353 354 //set ip 355 int ret = ff_veth_setaddr(sc); 356 if (ret != 0) { 357 printf("ff_veth_setaddr failed\n"); 358 } 359 ret = ff_veth_set_gateway(sc); 360 if (ret != 0) { 361 printf("ff_veth_set_gateway failed\n"); 362 } 363 364 return (0); 365 } 366 367 void * 368 ff_veth_attach(struct ff_port_cfg *cfg) 369 { 370 struct ff_veth_softc *sc = NULL; 371 int error; 372 373 sc = malloc(sizeof(struct ff_veth_softc), M_DEVBUF, M_WAITOK); 374 if (NULL == sc) { 375 printf("%s: ff_veth_softc allocation failed\n", sc->host_ifname); 376 goto fail; 377 } 378 memset(sc, 0, sizeof(struct ff_veth_softc)); 379 380 snprintf(sc->host_ifname, sizeof(sc->host_ifname), ff_IF_NAME, cfg->port_id); 381 382 error = ff_veth_config(sc, cfg); 383 if (0 != error) { 384 goto fail; 385 } 386 387 if (0 != ff_veth_setup_interface(sc, cfg)) { 388 goto fail; 389 } 390 391 return sc->host_ctx; 392 393 fail: 394 if (sc) { 395 if (sc->host_ctx) 396 ff_dpdk_deregister_if(sc->host_ctx); 397 398 free(sc, M_DEVBUF); 399 } 400 401 return NULL; 402 } 403 404 int 405 ff_veth_detach(void *arg) 406 { 407 struct ff_veth_softc *sc = (struct ff_veth_softc *)arg; 408 if (sc) { 409 ff_dpdk_deregister_if(sc->host_ctx); 410 free(sc, M_DEVBUF); 411 } 412 413 return (0); 414 } 415 416 void * 417 ff_veth_softc_to_hostc(void *softc) 418 { 419 struct ff_veth_softc *sc = (struct ff_veth_softc *)softc; 420 return (void *)sc->host_ctx; 421 } 422 423