Annotation of XNU/bsd/netinet/ip_flow.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*-
        !            23:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
        !            24:  * All rights reserved.
        !            25:  *
        !            26:  * This code is derived from software contributed to The NetBSD Foundation
        !            27:  * by the 3am Software Foundry ("3am").  It was developed by Matt Thomas.
        !            28:  *
        !            29:  * Redistribution and use in source and binary forms, with or without
        !            30:  * modification, are permitted provided that the following conditions
        !            31:  * are met:
        !            32:  * 1. Redistributions of source code must retain the above copyright
        !            33:  *    notice, this list of conditions and the following disclaimer.
        !            34:  * 2. Redistributions in binary form must reproduce the above copyright
        !            35:  *    notice, this list of conditions and the following disclaimer in the
        !            36:  *    documentation and/or other materials provided with the distribution.
        !            37:  * 3. All advertising materials mentioning features or use of this software
        !            38:  *    must display the following acknowledgement:
        !            39:  *     This product includes software developed by the NetBSD
        !            40:  *     Foundation, Inc. and its contributors.
        !            41:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            42:  *    contributors may be used to endorse or promote products derived
        !            43:  *    from this software without specific prior written permission.
        !            44:  *
        !            45:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            46:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            47:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            48:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            49:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            50:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            51:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            52:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            53:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            54:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            55:  * POSSIBILITY OF SUCH DAMAGE.
        !            56:  *
        !            57:  */
        !            58: 
        !            59: #include <sys/param.h>
        !            60: #include <sys/systm.h>
        !            61: #include <sys/malloc.h>
        !            62: #include <sys/mbuf.h>
        !            63: #include <sys/protosw.h>
        !            64: #include <sys/socket.h>
        !            65: #include <sys/kernel.h>
        !            66: 
        !            67: #include <sys/sysctl.h>
        !            68: 
        !            69: #include <net/if.h>
        !            70: #include <net/route.h>
        !            71: 
        !            72: #include <netinet/in.h>
        !            73: #include <netinet/in_systm.h>
        !            74: #include <netinet/ip.h>
        !            75: #include <netinet/in_var.h>
        !            76: #include <netinet/ip_var.h>
        !            77: #include <netinet/ip_flow.h>
        !            78: #include <net/dlil.h>
        !            79: 
        !            80: #define        IPFLOW_TIMER            (5 * PR_SLOWHZ)
        !            81: #define IPFLOW_HASHBITS                6       /* should not be a multiple of 8 */
        !            82: #define        IPFLOW_HASHSIZE         (1 << IPFLOW_HASHBITS)
        !            83: static LIST_HEAD(ipflowhead, ipflow) ipflows[IPFLOW_HASHSIZE];
        !            84: static int ipflow_inuse;
        !            85: #define        IPFLOW_MAX              256
        !            86: 
        !            87: #if ISFB31
        !            88: #else
        !            89: #define M_IPFLOW M_TEMP
        !            90: #endif
        !            91: 
        !            92: static int ipflow_active = 0;
        !            93: SYSCTL_INT(_net_inet_ip, IPCTL_FASTFORWARDING, fastforwarding, CTLFLAG_RW,
        !            94:           &ipflow_active, 0, "");
        !            95: 
        !            96: MALLOC_DEFINE(M_IPFLOW, "ip_flow", "IP flow");
        !            97: 
        !            98: static unsigned
        !            99: ipflow_hash(
        !           100:        struct in_addr dst,
        !           101:        struct in_addr src,
        !           102:        unsigned tos)
        !           103: {
        !           104:        unsigned hash = tos;
        !           105:        int idx;
        !           106:        for (idx = 0; idx < 32; idx += IPFLOW_HASHBITS)
        !           107:                hash += (dst.s_addr >> (32 - idx)) + (src.s_addr >> idx);
        !           108:        return hash & (IPFLOW_HASHSIZE-1);
        !           109: }
        !           110: 
        !           111: static struct ipflow *
        !           112: ipflow_lookup(
        !           113:        const struct ip *ip)
        !           114: {
        !           115:        unsigned hash;
        !           116:        struct ipflow *ipf;
        !           117: 
        !           118:        hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
        !           119: 
        !           120:        ipf = LIST_FIRST(&ipflows[hash]);
        !           121:        while (ipf != NULL) {
        !           122:                if (ip->ip_dst.s_addr == ipf->ipf_dst.s_addr
        !           123:                    && ip->ip_src.s_addr == ipf->ipf_src.s_addr
        !           124:                    && ip->ip_tos == ipf->ipf_tos)
        !           125:                        break;
        !           126:                ipf = LIST_NEXT(ipf, ipf_next);
        !           127:        }
        !           128:        return ipf;
        !           129: }
        !           130: 
        !           131: int
        !           132: ipflow_fastforward(
        !           133:        struct mbuf *m)
        !           134: {
        !           135:        struct ip *ip;
        !           136:        struct ipflow *ipf;
        !           137:        struct rtentry *rt;
        !           138:        int error;
        !           139: 
        !           140:        /*
        !           141:         * Are we forwarding packets?  Big enough for an IP packet?
        !           142:         */
        !           143:        if (!ipforwarding || !ipflow_active || m->m_len < sizeof(struct ip))
        !           144:                return 0;
        !           145:        /*
        !           146:         * IP header with no option and valid version and length
        !           147:         */
        !           148:        ip = mtod(m, struct ip *);
        !           149:        if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2)
        !           150:            || ntohs(ip->ip_len) > m->m_pkthdr.len)
        !           151:                return 0;
        !           152:        /*
        !           153:         * Find a flow.
        !           154:         */
        !           155:        if ((ipf = ipflow_lookup(ip)) == NULL)
        !           156:                return 0;
        !           157: 
        !           158:        /*
        !           159:         * Route and interface still up?
        !           160:         */
        !           161:        rt = ipf->ipf_ro.ro_rt;
        !           162:        if ((rt->rt_flags & RTF_UP) == 0 || (rt->rt_ifp->if_flags & IFF_UP) == 0)
        !           163:                return 0;
        !           164: 
        !           165:        /*
        !           166:         * Packet size OK?  TTL?
        !           167:         */
        !           168:        if (m->m_pkthdr.len > rt->rt_ifp->if_mtu || ip->ip_ttl <= IPTTLDEC)
        !           169:                return 0;
        !           170: 
        !           171:        /*
        !           172:         * Everything checks out and so we can forward this packet.
        !           173:         * Modify the TTL and incrementally change the checksum.
        !           174:         */
        !           175:        ip->ip_ttl -= IPTTLDEC;
        !           176:        if (ip->ip_sum >= htons(0xffff - (IPTTLDEC << 8))) {
        !           177:                ip->ip_sum += htons(IPTTLDEC << 8) + 1;
        !           178:        } else {
        !           179:                ip->ip_sum += htons(IPTTLDEC << 8);
        !           180:        }
        !           181: 
        !           182:        /*
        !           183:         * Send the packet on its way.  All we can get back is ENOBUFS
        !           184:         */
        !           185:        ipf->ipf_uses++;
        !           186:        ipf->ipf_timer = IPFLOW_TIMER;
        !           187: 
        !           188:        /* Not sure the rt_dlt is valid here !! XXX */
        !           189:        if ((error = dlil_output((u_long)rt->rt_dlt, m, (caddr_t) rt, &ipf->ipf_ro.ro_dst, 0)) != 0) {
        !           190:                if (error == ENOBUFS)
        !           191:                        ipf->ipf_dropped++;
        !           192:                else
        !           193:                        ipf->ipf_errors++;
        !           194:        }
        !           195:        return 1;
        !           196: }
        !           197: 
        !           198: static void
        !           199: ipflow_addstats(
        !           200:        struct ipflow *ipf)
        !           201: {
        !           202:        ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
        !           203:        ipstat.ips_cantforward += ipf->ipf_errors + ipf->ipf_dropped;
        !           204:        ipstat.ips_forward += ipf->ipf_uses;
        !           205:        ipstat.ips_fastforward += ipf->ipf_uses;
        !           206: }
        !           207: 
        !           208: static void
        !           209: ipflow_free(
        !           210:        struct ipflow *ipf)
        !           211: {
        !           212:        int s;
        !           213:        /*
        !           214:         * Remove the flow from the hash table (at elevated IPL).
        !           215:         * Once it's off the list, we can deal with it at normal
        !           216:         * network IPL.
        !           217:         */
        !           218:        s = splimp();
        !           219:        LIST_REMOVE(ipf, ipf_next);
        !           220:        splx(s);
        !           221:        ipflow_addstats(ipf);
        !           222:        RTFREE(ipf->ipf_ro.ro_rt);
        !           223:        ipflow_inuse--;
        !           224:        FREE(ipf, M_IPFLOW);
        !           225: }
        !           226: 
        !           227: static struct ipflow *
        !           228: ipflow_reap(
        !           229:        void)
        !           230: {
        !           231:        struct ipflow *ipf, *maybe_ipf = NULL;
        !           232:        int idx;
        !           233:        int s;
        !           234: 
        !           235:        for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
        !           236:                ipf = LIST_FIRST(&ipflows[idx]);
        !           237:                while (ipf != NULL) {
        !           238:                        /*
        !           239:                         * If this no longer points to a valid route
        !           240:                         * reclaim it.
        !           241:                         */
        !           242:                        if ((ipf->ipf_ro.ro_rt->rt_flags & RTF_UP) == 0)
        !           243:                                goto done;
        !           244:                        /*
        !           245:                         * choose the one that's been least recently used
        !           246:                         * or has had the least uses in the last 1.5 
        !           247:                         * intervals.
        !           248:                         */
        !           249:                        if (maybe_ipf == NULL
        !           250:                            || ipf->ipf_timer < maybe_ipf->ipf_timer
        !           251:                            || (ipf->ipf_timer == maybe_ipf->ipf_timer
        !           252:                                && ipf->ipf_last_uses + ipf->ipf_uses <
        !           253:                                      maybe_ipf->ipf_last_uses +
        !           254:                                        maybe_ipf->ipf_uses))
        !           255:                                maybe_ipf = ipf;
        !           256:                        ipf = LIST_NEXT(ipf, ipf_next);
        !           257:                }
        !           258:        }
        !           259:        ipf = maybe_ipf;
        !           260:     done:
        !           261:        /*
        !           262:         * Remove the entry from the flow table.
        !           263:         */
        !           264:        s = splimp();
        !           265:        LIST_REMOVE(ipf, ipf_next);
        !           266:        splx(s);
        !           267:        ipflow_addstats(ipf);
        !           268:        RTFREE(ipf->ipf_ro.ro_rt);
        !           269:        return ipf;
        !           270: }
        !           271: 
        !           272: void
        !           273: ipflow_slowtimo(
        !           274:        void)
        !           275: {
        !           276:        struct ipflow *ipf;
        !           277:        int idx;
        !           278: 
        !           279:        for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
        !           280:                ipf = LIST_FIRST(&ipflows[idx]);
        !           281:                while (ipf != NULL) {
        !           282:                        struct ipflow *next_ipf = LIST_NEXT(ipf, ipf_next);
        !           283:                        if (--ipf->ipf_timer == 0) {
        !           284:                                ipflow_free(ipf);
        !           285:                        } else {
        !           286:                                ipf->ipf_last_uses = ipf->ipf_uses;
        !           287:                                ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
        !           288:                                ipstat.ips_forward += ipf->ipf_uses;
        !           289:                                ipstat.ips_fastforward += ipf->ipf_uses;
        !           290:                                ipf->ipf_uses = 0;
        !           291:                        }
        !           292:                        ipf = next_ipf;
        !           293:                }
        !           294:        }
        !           295: }
        !           296: 
        !           297: void
        !           298: ipflow_create(
        !           299:        const struct route *ro,
        !           300:        struct mbuf *m)
        !           301: {
        !           302:        const struct ip *const ip = mtod(m, struct ip *);
        !           303:        struct ipflow *ipf;
        !           304:        unsigned hash;
        !           305:        int s;
        !           306: 
        !           307:        /*
        !           308:         * Don't create cache entries for ICMP messages.
        !           309:         */
        !           310:        if (!ipflow_active || ip->ip_p == IPPROTO_ICMP)
        !           311:                return;
        !           312:        /*
        !           313:         * See if an existing flow struct exists.  If so remove it from it's
        !           314:         * list and free the old route.  If not, try to malloc a new one
        !           315:         * (if we aren't at our limit).
        !           316:         */
        !           317:        ipf = ipflow_lookup(ip);
        !           318:        if (ipf == NULL) {
        !           319:                if (ipflow_inuse == IPFLOW_MAX) {
        !           320:                        ipf = ipflow_reap();
        !           321:                } else {
        !           322:                        ipf = (struct ipflow *) _MALLOC(sizeof(*ipf), M_IPFLOW,
        !           323:                                                       M_NOWAIT);
        !           324:                        if (ipf == NULL)
        !           325:                                return;
        !           326:                        ipflow_inuse++;
        !           327:                }
        !           328:                bzero((caddr_t) ipf, sizeof(*ipf));
        !           329:        } else {
        !           330:                s = splimp();
        !           331:                LIST_REMOVE(ipf, ipf_next);
        !           332:                splx(s);
        !           333:                ipflow_addstats(ipf);
        !           334:                RTFREE(ipf->ipf_ro.ro_rt);
        !           335:                ipf->ipf_uses = ipf->ipf_last_uses = 0;
        !           336:                ipf->ipf_errors = ipf->ipf_dropped = 0;
        !           337:        }
        !           338: 
        !           339:        /*
        !           340:         * Fill in the updated information.
        !           341:         */
        !           342:        ipf->ipf_ro = *ro;
        !           343:        ro->ro_rt->rt_refcnt++;
        !           344:        ipf->ipf_dst = ip->ip_dst;
        !           345:        ipf->ipf_src = ip->ip_src;
        !           346:        ipf->ipf_tos = ip->ip_tos;
        !           347:        ipf->ipf_timer = IPFLOW_TIMER;
        !           348:        /*
        !           349:         * Insert into the approriate bucket of the flow table.
        !           350:         */
        !           351:        hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
        !           352:        s = splimp();
        !           353:        LIST_INSERT_HEAD(&ipflows[hash], ipf, ipf_next);
        !           354:        splx(s);
        !           355: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.