Deleted Added
full compact
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}