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 return (void *)m; 209 } 210 211 void * 212 ff_mbuf_get(void *m, void *data, uint16_t len) 213 { 214 struct mbuf *prev = (struct mbuf *)m; 215 struct mbuf *mb = m_get(M_NOWAIT, MT_DATA); 216 217 if (mb == NULL) { 218 return NULL; 219 } 220 221 m_extadd(mb, data, len, NULL, NULL, NULL, 0, 0); 222 223 mb->m_next = NULL; 224 mb->m_nextpkt = NULL; 225 mb->m_len = len; 226 227 if (prev != NULL) { 228 prev->m_next = mb; 229 } 230 231 return (void *)mb; 232 } 233 234 void 235 ff_veth_process_packet(void *arg, void *m) 236 { 237 struct ifnet *ifp = (struct ifnet *)arg; 238 struct mbuf *mb = (struct mbuf *)m; 239 240 mb->m_pkthdr.rcvif = ifp; 241 242 ifp->if_input(ifp, mb); 243 } 244 245 static int 246 ff_veth_transmit(struct ifnet *ifp, struct mbuf *m) 247 { 248 struct ff_veth_softc *sc = (struct ff_veth_softc *)ifp->if_softc; 249 return ff_dpdk_if_send(sc->host_ctx, (void*)m, m->m_pkthdr.len); 250 } 251 252 static void 253 ff_veth_qflush(struct ifnet *ifp) 254 { 255 256 } 257 258 static int 259 ff_veth_setaddr(struct ff_veth_softc *sc) 260 { 261 struct in_aliasreq req; 262 bzero(&req, sizeof req); 263 strcpy(req.ifra_name, sc->ifp->if_dname); 264 265 struct sockaddr_in sa; 266 bzero(&sa, sizeof(sa)); 267 sa.sin_len = sizeof(sa); 268 sa.sin_family = AF_INET; 269 sa.sin_addr.s_addr = sc->ip; 270 bcopy(&sa, &req.ifra_addr, sizeof(sa)); 271 272 sa.sin_addr.s_addr = sc->netmask; 273 bcopy(&sa, &req.ifra_mask, sizeof(sa)); 274 275 sa.sin_addr.s_addr = sc->broadcast; 276 bcopy(&sa, &req.ifra_broadaddr, sizeof(sa)); 277 278 struct socket *so = NULL; 279 socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread); 280 int ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread); 281 282 sofree(so); 283 284 return ret; 285 } 286 287 static int 288 ff_veth_set_gateway(struct ff_veth_softc *sc) 289 { 290 struct sockaddr_in gw; 291 bzero(&gw, sizeof(gw)); 292 gw.sin_len = sizeof(gw); 293 gw.sin_family = AF_INET; 294 gw.sin_addr.s_addr = sc->gateway; 295 296 struct sockaddr_in dst; 297 bzero(&dst, sizeof(dst)); 298 dst.sin_len = sizeof(dst); 299 dst.sin_family = AF_INET; 300 dst.sin_addr.s_addr = 0; 301 302 struct sockaddr_in nm; 303 bzero(&nm, sizeof(nm)); 304 nm.sin_len = sizeof(nm); 305 nm.sin_family = AF_INET; 306 nm.sin_addr.s_addr = 0; 307 308 return rtrequest_fib(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw, 309 (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 310 } 311 312 static int 313 ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg) 314 { 315 struct ifnet *ifp; 316 317 ifp = sc->ifp = if_alloc(IFT_ETHER); 318 319 ifp->if_init = ff_veth_init; 320 ifp->if_softc = sc; 321 322 if_initname(ifp, sc->host_ifname, IF_DUNIT_NONE); 323 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 324 ifp->if_ioctl = ff_veth_ioctl; 325 ifp->if_start = ff_veth_start; 326 ifp->if_transmit = ff_veth_transmit; 327 ifp->if_qflush = ff_veth_qflush; 328 ether_ifattach(ifp, sc->mac); 329 330 if (cfg->hw_features.rx_csum) { 331 ifp->if_capabilities |= IFCAP_RXCSUM; 332 } 333 if (cfg->hw_features.tx_csum_ip) { 334 ifp->if_capabilities |= IFCAP_TXCSUM; 335 ifp->if_hwassist |= CSUM_IP; 336 } 337 if (cfg->hw_features.tx_csum_l4) { 338 ifp->if_hwassist |= CSUM_DELAY_DATA; 339 } 340 if (cfg->hw_features.tx_tso) { 341 ifp->if_capabilities |= IFCAP_TSO; 342 ifp->if_hwassist |= CSUM_TSO; 343 } 344 345 ifp->if_capenable = ifp->if_capabilities; 346 347 sc->host_ctx = ff_dpdk_register_if((void *)sc, (void *)sc->ifp, cfg); 348 if (sc->host_ctx == NULL) { 349 printf("%s: Failed to register dpdk interface\n", sc->host_ifname); 350 return -1; 351 } 352 353 //set ip 354 int ret = ff_veth_setaddr(sc); 355 if (ret != 0) { 356 printf("ff_veth_setaddr failed\n"); 357 } 358 ret = ff_veth_set_gateway(sc); 359 if (ret != 0) { 360 printf("ff_veth_set_gateway failed\n"); 361 } 362 363 return (0); 364 } 365 366 void * 367 ff_veth_attach(struct ff_port_cfg *cfg) 368 { 369 struct ff_veth_softc *sc = NULL; 370 int error; 371 372 sc = malloc(sizeof(struct ff_veth_softc), M_DEVBUF, M_WAITOK); 373 if (NULL == sc) { 374 printf("ff_veth_softc allocation failed\n"); 375 goto fail; 376 } 377 memset(sc, 0, sizeof(struct ff_veth_softc)); 378 379 snprintf(sc->host_ifname, sizeof(sc->host_ifname), ff_IF_NAME, cfg->port_id); 380 381 error = ff_veth_config(sc, cfg); 382 if (0 != error) { 383 goto fail; 384 } 385 386 if (0 != ff_veth_setup_interface(sc, cfg)) { 387 goto fail; 388 } 389 390 return sc->host_ctx; 391 392 fail: 393 if (sc) { 394 if (sc->host_ctx) 395 ff_dpdk_deregister_if(sc->host_ctx); 396 397 free(sc, M_DEVBUF); 398 } 399 400 return NULL; 401 } 402 403 int 404 ff_veth_detach(void *arg) 405 { 406 struct ff_veth_softc *sc = (struct ff_veth_softc *)arg; 407 if (sc) { 408 ff_dpdk_deregister_if(sc->host_ctx); 409 free(sc, M_DEVBUF); 410 } 411 412 return (0); 413 } 414 415 void * 416 ff_veth_softc_to_hostc(void *softc) 417 { 418 struct ff_veth_softc *sc = (struct ff_veth_softc *)softc; 419 return (void *)sc->host_ctx; 420 } 421 422 void 423 ff_mbuf_set_vlan_info(void *hdr, uint16_t vlan_tci) { 424 struct mbuf *m = (struct mbuf *)hdr; 425 m->m_pkthdr.ether_vtag = vlan_tci; 426 m->m_flags |= M_VLANTAG; 427 return; 428 } 429