ip_fastfwd.c (302408) | ip_fastfwd.c (310771) |
---|---|
1/*- 2 * Copyright (c) 2003 Andre Oppermann, Internet Business Solutions AG 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 60 unchanged lines hidden (view full) --- 69 */ 70 71/* 72 * Many thanks to Matt Thomas of NetBSD for basic structure of ip_flow.c which 73 * is being followed here. 74 */ 75 76#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2003 Andre Oppermann, Internet Business Solutions AG 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 60 unchanged lines hidden (view full) --- 69 */ 70 71/* 72 * Many thanks to Matt Thomas of NetBSD for basic structure of ip_flow.c which 73 * is being followed here. 74 */ 75 76#include <sys/cdefs.h> |
77__FBSDID("$FreeBSD: stable/11/sys/netinet/ip_fastfwd.c 301717 2016-06-09 05:48:34Z ae $"); | 77__FBSDID("$FreeBSD: stable/11/sys/netinet/ip_fastfwd.c 310771 2016-12-29 09:50:37Z ae $"); |
78 79#include "opt_ipstealth.h" 80 81#include <sys/param.h> 82#include <sys/systm.h> 83#include <sys/kernel.h> 84#include <sys/malloc.h> 85#include <sys/mbuf.h> --- 6 unchanged lines hidden (view full) --- 92#include <net/if.h> 93#include <net/if_types.h> 94#include <net/if_var.h> 95#include <net/if_dl.h> 96#include <net/route.h> 97#include <net/vnet.h> 98 99#include <netinet/in.h> | 78 79#include "opt_ipstealth.h" 80 81#include <sys/param.h> 82#include <sys/systm.h> 83#include <sys/kernel.h> 84#include <sys/malloc.h> 85#include <sys/mbuf.h> --- 6 unchanged lines hidden (view full) --- 92#include <net/if.h> 93#include <net/if_types.h> 94#include <net/if_var.h> 95#include <net/if_dl.h> 96#include <net/route.h> 97#include <net/vnet.h> 98 99#include <netinet/in.h> |
100#include <netinet/in_fib.h> |
|
100#include <netinet/in_kdtrace.h> 101#include <netinet/in_systm.h> 102#include <netinet/in_var.h> 103#include <netinet/ip.h> 104#include <netinet/ip_var.h> 105#include <netinet/ip_icmp.h> 106#include <netinet/ip_options.h> 107 108#include <machine/in_cksum.h> 109 | 101#include <netinet/in_kdtrace.h> 102#include <netinet/in_systm.h> 103#include <netinet/in_var.h> 104#include <netinet/ip.h> 105#include <netinet/ip_var.h> 106#include <netinet/ip_icmp.h> 107#include <netinet/ip_options.h> 108 109#include <machine/in_cksum.h> 110 |
110static struct sockaddr_in * 111ip_findroute(struct route *ro, struct in_addr dest, struct mbuf *m) | 111static int 112ip_findroute(struct nhop4_basic *pnh, struct in_addr dest, struct mbuf *m) |
112{ | 113{ |
113 struct sockaddr_in *dst; 114 struct rtentry *rt; | |
115 | 114 |
115 bzero(pnh, sizeof(*pnh)); 116 if (fib4_lookup_nh_basic(M_GETFIB(m), dest, 0, 0, pnh) != 0) { 117 IPSTAT_INC(ips_noroute); 118 IPSTAT_INC(ips_cantforward); 119 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 120 return (EHOSTUNREACH); 121 } |
|
116 /* | 122 /* |
117 * Find route to destination. | 123 * Drop blackholed traffic and directed broadcasts. |
118 */ | 124 */ |
119 bzero(ro, sizeof(*ro)); 120 dst = (struct sockaddr_in *)&ro->ro_dst; 121 dst->sin_family = AF_INET; 122 dst->sin_len = sizeof(*dst); 123 dst->sin_addr.s_addr = dest.s_addr; 124 in_rtalloc_ign(ro, 0, M_GETFIB(m)); | 125 if ((pnh->nh_flags & (NHF_BLACKHOLE | NHF_BROADCAST)) != 0) { 126 IPSTAT_INC(ips_cantforward); 127 m_freem(m); 128 return (EHOSTUNREACH); 129 } |
125 | 130 |
126 /* 127 * Route there and interface still up? 128 */ 129 rt = ro->ro_rt; 130 if (rt && (rt->rt_flags & RTF_UP) && 131 (rt->rt_ifp->if_flags & IFF_UP) && 132 (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) { 133 if (rt->rt_flags & RTF_GATEWAY) 134 dst = (struct sockaddr_in *)rt->rt_gateway; 135 } else { 136 IPSTAT_INC(ips_noroute); | 131 if (pnh->nh_flags & NHF_REJECT) { |
137 IPSTAT_INC(ips_cantforward); | 132 IPSTAT_INC(ips_cantforward); |
138 if (rt) 139 RTFREE(rt); | |
140 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | 133 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); |
141 return NULL; | 134 return (EHOSTUNREACH); |
142 } | 135 } |
143 return dst; | 136 137 return (0); |
144} 145 146/* 147 * Try to forward a packet based on the destination address. 148 * This is a fast path optimized for the plain forwarding case. 149 * If the packet is handled (and consumed) here then we return NULL; 150 * otherwise mbuf is returned and the packet should be delivered 151 * to ip_input for full processing. 152 */ 153struct mbuf * 154ip_tryforward(struct mbuf *m) 155{ 156 struct ip *ip; 157 struct mbuf *m0 = NULL; | 138} 139 140/* 141 * Try to forward a packet based on the destination address. 142 * This is a fast path optimized for the plain forwarding case. 143 * If the packet is handled (and consumed) here then we return NULL; 144 * otherwise mbuf is returned and the packet should be delivered 145 * to ip_input for full processing. 146 */ 147struct mbuf * 148ip_tryforward(struct mbuf *m) 149{ 150 struct ip *ip; 151 struct mbuf *m0 = NULL; |
158 struct route ro; 159 struct sockaddr_in *dst = NULL; 160 struct ifnet *ifp; | 152 struct nhop4_basic nh; 153 struct sockaddr_in dst; |
161 struct in_addr odest, dest; 162 uint16_t ip_len, ip_off; 163 int error = 0; | 154 struct in_addr odest, dest; 155 uint16_t ip_len, ip_off; 156 int error = 0; |
164 int mtu; | |
165 struct m_tag *fwd_tag = NULL; 166 167 /* 168 * Are we active and forwarding packets? 169 */ 170 171 M_ASSERTVALID(m); 172 M_ASSERTPKTHDR(m); 173 | 157 struct m_tag *fwd_tag = NULL; 158 159 /* 160 * Are we active and forwarding packets? 161 */ 162 163 M_ASSERTVALID(m); 164 M_ASSERTPKTHDR(m); 165 |
174 bzero(&ro, sizeof(ro)); 175 176 | |
177#ifdef ALTQ 178 /* 179 * Is packet dropped by traffic conditioner? 180 */ 181 if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) 182 goto drop; 183#endif 184 --- 115 unchanged lines hidden (view full) --- 300 ip->ip_sum += htons(IPTTLDEC << 8); 301#ifdef IPSTEALTH 302 } 303#endif 304 305 /* 306 * Find route to destination. 307 */ | 166#ifdef ALTQ 167 /* 168 * Is packet dropped by traffic conditioner? 169 */ 170 if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) 171 goto drop; 172#endif 173 --- 115 unchanged lines hidden (view full) --- 289 ip->ip_sum += htons(IPTTLDEC << 8); 290#ifdef IPSTEALTH 291 } 292#endif 293 294 /* 295 * Find route to destination. 296 */ |
308 if ((dst = ip_findroute(&ro, dest, m)) == NULL) 309 return NULL; /* icmp unreach already sent */ 310 ifp = ro.ro_rt->rt_ifp; | 297 if (ip_findroute(&nh, dest, m) != 0) 298 return (NULL); /* icmp unreach already sent */ |
311 312 /* | 299 300 /* |
313 * Immediately drop blackholed traffic, and directed broadcasts 314 * for either the all-ones or all-zero subnet addresses on 315 * locally attached networks. 316 */ 317 if ((ro.ro_rt->rt_flags & (RTF_BLACKHOLE|RTF_BROADCAST)) != 0) 318 goto drop; 319 320 /* | |
321 * Step 5: outgoing firewall packet processing 322 */ | 301 * Step 5: outgoing firewall packet processing 302 */ |
323 324 /* 325 * Run through list of hooks for output packets. 326 */ | |
327 if (!PFIL_HOOKED(&V_inet_pfil_hook)) 328 goto passout; 329 | 303 if (!PFIL_HOOKED(&V_inet_pfil_hook)) 304 goto passout; 305 |
330 if (pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, NULL) || m == NULL) { | 306 if (pfil_run_hooks(&V_inet_pfil_hook, &m, nh.nh_ifp, PFIL_OUT, NULL) || 307 m == NULL) { |
331 goto drop; 332 } 333 334 M_ASSERTVALID(m); 335 M_ASSERTPKTHDR(m); 336 337 ip = mtod(m, struct ip *); 338 dest.s_addr = ip->ip_dst.s_addr; --- 8 unchanged lines hidden (view full) --- 347 * Is it now for a local address on this host? 348 */ 349 if (m->m_flags & M_FASTFWD_OURS || in_localip(dest)) { 350forwardlocal: 351 /* 352 * Return packet for processing by ip_input(). 353 */ 354 m->m_flags |= M_FASTFWD_OURS; | 308 goto drop; 309 } 310 311 M_ASSERTVALID(m); 312 M_ASSERTPKTHDR(m); 313 314 ip = mtod(m, struct ip *); 315 dest.s_addr = ip->ip_dst.s_addr; --- 8 unchanged lines hidden (view full) --- 324 * Is it now for a local address on this host? 325 */ 326 if (m->m_flags & M_FASTFWD_OURS || in_localip(dest)) { 327forwardlocal: 328 /* 329 * Return packet for processing by ip_input(). 330 */ 331 m->m_flags |= M_FASTFWD_OURS; |
355 if (ro.ro_rt) 356 RTFREE(ro.ro_rt); 357 return m; | 332 return (m); |
358 } 359 /* 360 * Redo route lookup with new destination address 361 */ 362 if (fwd_tag) { 363 dest.s_addr = ((struct sockaddr_in *) 364 (fwd_tag + 1))->sin_addr.s_addr; 365 m_tag_delete(m, fwd_tag); 366 m->m_flags &= ~M_IP_NEXTHOP; 367 } | 333 } 334 /* 335 * Redo route lookup with new destination address 336 */ 337 if (fwd_tag) { 338 dest.s_addr = ((struct sockaddr_in *) 339 (fwd_tag + 1))->sin_addr.s_addr; 340 m_tag_delete(m, fwd_tag); 341 m->m_flags &= ~M_IP_NEXTHOP; 342 } |
368 RTFREE(ro.ro_rt); 369 if ((dst = ip_findroute(&ro, dest, m)) == NULL) 370 return NULL; /* icmp unreach already sent */ 371 ifp = ro.ro_rt->rt_ifp; | 343 if (ip_findroute(&nh, dest, m) != 0) 344 return (NULL); /* icmp unreach already sent */ |
372 } 373 374passout: 375 /* 376 * Step 6: send off the packet 377 */ 378 ip_len = ntohs(ip->ip_len); 379 ip_off = ntohs(ip->ip_off); 380 | 345 } 346 347passout: 348 /* 349 * Step 6: send off the packet 350 */ 351 ip_len = ntohs(ip->ip_len); 352 ip_off = ntohs(ip->ip_off); 353 |
381 /* 382 * Check if route is dampned (when ARP is unable to resolve) 383 */ 384 if ((ro.ro_rt->rt_flags & RTF_REJECT) && 385 (ro.ro_rt->rt_expire == 0 || time_uptime < ro.ro_rt->rt_expire)) { 386 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 387 goto consumed; 388 } | 354 bzero(&dst, sizeof(dst)); 355 dst.sin_family = AF_INET; 356 dst.sin_len = sizeof(dst); 357 dst.sin_addr = nh.nh_addr; |
389 390 /* | 358 359 /* |
391 * Check if media link state of interface is not down 392 */ 393 if (ifp->if_link_state == LINK_STATE_DOWN) { 394 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 395 goto consumed; 396 } 397 398 /* | |
399 * Check if packet fits MTU or if hardware will fragment for us 400 */ | 360 * Check if packet fits MTU or if hardware will fragment for us 361 */ |
401 if (ro.ro_rt->rt_mtu) 402 mtu = min(ro.ro_rt->rt_mtu, ifp->if_mtu); 403 else 404 mtu = ifp->if_mtu; 405 406 if (ip_len <= mtu) { | 362 if (ip_len <= nh.nh_mtu) { |
407 /* 408 * Avoid confusing lower layers. 409 */ 410 m_clrprotoflags(m); 411 /* 412 * Send off the packet via outgoing interface 413 */ | 363 /* 364 * Avoid confusing lower layers. 365 */ 366 m_clrprotoflags(m); 367 /* 368 * Send off the packet via outgoing interface 369 */ |
414 IP_PROBE(send, NULL, NULL, ip, ifp, ip, NULL); 415 error = (*ifp->if_output)(ifp, m, 416 (struct sockaddr *)dst, &ro); | 370 IP_PROBE(send, NULL, NULL, ip, nh.nh_ifp, ip, NULL); 371 error = (*nh.nh_ifp->if_output)(nh.nh_ifp, m, 372 (struct sockaddr *)&dst, NULL); |
417 } else { 418 /* 419 * Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery 420 */ 421 if (ip_off & IP_DF) { 422 IPSTAT_INC(ips_cantfrag); 423 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, | 373 } else { 374 /* 375 * Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery 376 */ 377 if (ip_off & IP_DF) { 378 IPSTAT_INC(ips_cantfrag); 379 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, |
424 0, mtu); | 380 0, nh.nh_mtu); |
425 goto consumed; 426 } else { 427 /* 428 * We have to fragment the packet 429 */ 430 m->m_pkthdr.csum_flags |= CSUM_IP; | 381 goto consumed; 382 } else { 383 /* 384 * We have to fragment the packet 385 */ 386 m->m_pkthdr.csum_flags |= CSUM_IP; |
431 if (ip_fragment(ip, &m, mtu, ifp->if_hwassist)) | 387 if (ip_fragment(ip, &m, nh.nh_mtu, 388 nh.nh_ifp->if_hwassist) != 0) |
432 goto drop; 433 KASSERT(m != NULL, ("null mbuf and no error")); 434 /* 435 * Send off the fragments via outgoing interface 436 */ 437 error = 0; 438 do { 439 m0 = m->m_nextpkt; 440 m->m_nextpkt = NULL; 441 /* 442 * Avoid confusing lower layers. 443 */ 444 m_clrprotoflags(m); 445 | 389 goto drop; 390 KASSERT(m != NULL, ("null mbuf and no error")); 391 /* 392 * Send off the fragments via outgoing interface 393 */ 394 error = 0; 395 do { 396 m0 = m->m_nextpkt; 397 m->m_nextpkt = NULL; 398 /* 399 * Avoid confusing lower layers. 400 */ 401 m_clrprotoflags(m); 402 |
446 IP_PROBE(send, NULL, NULL, ip, ifp, ip, NULL); 447 error = (*ifp->if_output)(ifp, m, 448 (struct sockaddr *)dst, &ro); | 403 IP_PROBE(send, NULL, NULL, ip, nh.nh_ifp, 404 ip, NULL); 405 /* XXX: we can use cached route here */ 406 error = (*nh.nh_ifp->if_output)(nh.nh_ifp, m, 407 (struct sockaddr *)&dst, NULL); |
449 if (error) 450 break; 451 } while ((m = m0) != NULL); 452 if (error) { 453 /* Reclaim remaining fragments */ 454 for (m = m0; m; m = m0) { 455 m0 = m->m_nextpkt; 456 m_freem(m); 457 } 458 } else 459 IPSTAT_INC(ips_fragmented); 460 } 461 } 462 463 if (error != 0) 464 IPSTAT_INC(ips_odropped); 465 else { | 408 if (error) 409 break; 410 } while ((m = m0) != NULL); 411 if (error) { 412 /* Reclaim remaining fragments */ 413 for (m = m0; m; m = m0) { 414 m0 = m->m_nextpkt; 415 m_freem(m); 416 } 417 } else 418 IPSTAT_INC(ips_fragmented); 419 } 420 } 421 422 if (error != 0) 423 IPSTAT_INC(ips_odropped); 424 else { |
466 counter_u64_add(ro.ro_rt->rt_pksent, 1); | |
467 IPSTAT_INC(ips_forward); 468 IPSTAT_INC(ips_fastforward); 469 } 470consumed: | 425 IPSTAT_INC(ips_forward); 426 IPSTAT_INC(ips_fastforward); 427 } 428consumed: |
471 RTFREE(ro.ro_rt); | |
472 return NULL; 473drop: 474 if (m) 475 m_freem(m); | 429 return NULL; 430drop: 431 if (m) 432 m_freem(m); |
476 if (ro.ro_rt) 477 RTFREE(ro.ro_rt); | |
478 return NULL; 479} | 433 return NULL; 434} |