linux-old/net/ipv4/proc.c
<<
>>
Prefs
   1/*
   2 * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3 *              operating system.  INET is implemented using the  BSD Socket
   4 *              interface as the means of communication with the user level.
   5 *
   6 *              This file implements the various access functions for the
   7 *              PROC file system.  It is mainly used for debugging and
   8 *              statistics.
   9 *
  10 * Version:     $Id: proc.c,v 1.34 1999/02/08 11:20:34 davem Exp $
  11 *
  12 * Authors:     Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  13 *              Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
  14 *              Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
  15 *              Erik Schoenfelder, <schoenfr@ibr.cs.tu-bs.de>
  16 *
  17 * Fixes:
  18 *              Alan Cox        :       UDP sockets show the rxqueue/txqueue
  19 *                                      using hint flag for the netinfo.
  20 *      Pauline Middelink       :       identd support
  21 *              Alan Cox        :       Make /proc safer.
  22 *      Erik Schoenfelder       :       /proc/net/snmp
  23 *              Alan Cox        :       Handle dead sockets properly.
  24 *      Gerhard Koerting        :       Show both timers
  25 *              Alan Cox        :       Allow inode to be NULL (kernel socket)
  26 *      Andi Kleen              :       Add support for open_requests and 
  27 *                                      split functions for more readibility.
  28 *      Andi Kleen              :       Add support for /proc/net/netstat
  29 *
  30 *              This program is free software; you can redistribute it and/or
  31 *              modify it under the terms of the GNU General Public License
  32 *              as published by the Free Software Foundation; either version
  33 *              2 of the License, or (at your option) any later version.
  34 */
  35#include <asm/system.h>
  36#include <linux/sched.h>
  37#include <linux/socket.h>
  38#include <linux/net.h>
  39#include <linux/un.h>
  40#include <linux/in.h>
  41#include <linux/param.h>
  42#include <linux/inet.h>
  43#include <linux/netdevice.h>
  44#include <net/ip.h>
  45#include <net/icmp.h>
  46#include <net/protocol.h>
  47#include <net/tcp.h>
  48#include <net/udp.h>
  49#include <linux/skbuff.h>
  50#include <net/sock.h>
  51#include <net/raw.h>
  52
  53/* Format a single open_request into tmpbuf. */
  54static inline void get__openreq(struct sock *sk, struct open_request *req, 
  55                                char *tmpbuf, 
  56                                int i)
  57{
  58        sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
  59                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
  60                i,
  61                (long unsigned int)req->af.v4_req.loc_addr,
  62                ntohs(sk->sport),
  63                (long unsigned int)req->af.v4_req.rmt_addr,
  64                ntohs(req->rmt_port),
  65                TCP_SYN_RECV,
  66                0,0, /* could print option size, but that is af dependent. */
  67                1,   /* timers active (only the expire timer) */  
  68                (unsigned long)(req->expires - jiffies), 
  69                req->retrans,
  70                sk->socket ? sk->socket->inode->i_uid : 0,
  71                0,  /* non standard timer */  
  72                0 /* open_requests have no inode */
  73                ); 
  74}
  75
  76/* Format a single socket into tmpbuf. */
  77static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
  78{
  79        unsigned long  dest, src;
  80        unsigned short destp, srcp;
  81        int timer_active, timer_active1, timer_active2;
  82        int tw_bucket = 0;
  83        unsigned long timer_expires;
  84        struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
  85
  86        dest  = sp->daddr;
  87        src   = sp->rcv_saddr;
  88        destp = sp->dport;
  89        srcp  = sp->sport;
  90        
  91        /* FIXME: The fact that retransmit_timer occurs as a field
  92         * in two different parts of the socket structure is,
  93         * to say the least, confusing. This code now uses the
  94         * right retransmit_timer variable, but I'm not sure
  95         * the rest of the timer stuff is still correct.
  96         * In particular I'm not sure what the timeout value
  97         * is suppose to reflect (as opposed to tm->when). -- erics
  98         */
  99        
 100        destp = ntohs(destp);
 101        srcp  = ntohs(srcp);
 102        if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
 103                extern int tcp_tw_death_row_slot;
 104                struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
 105                int slot_dist;
 106
 107                tw_bucket       = 1;
 108                timer_active1   = timer_active2 = 0;
 109                timer_active    = 3;
 110                slot_dist       = tw->death_slot;
 111                if(slot_dist > tcp_tw_death_row_slot)
 112                        slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
 113                else
 114                        slot_dist = tcp_tw_death_row_slot - slot_dist;
 115                timer_expires   = jiffies + (slot_dist * TCP_TWKILL_PERIOD);
 116        } else {
 117                timer_active1 = del_timer(&tp->retransmit_timer);
 118                timer_active2 = del_timer(&sp->timer);
 119                if (!timer_active1) tp->retransmit_timer.expires=0;
 120                if (!timer_active2) sp->timer.expires=0;
 121                timer_active    = 0;
 122                timer_expires   = (unsigned) -1;
 123        }
 124        if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
 125                timer_active    = 1;
 126                timer_expires   = tp->retransmit_timer.expires;
 127        }
 128        if (timer_active2 && sp->timer.expires < timer_expires) {
 129                timer_active    = 2;
 130                timer_expires   = sp->timer.expires;
 131        }
 132        if(timer_active == 0)
 133                timer_expires = jiffies;
 134        sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
 135                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
 136                i, src, srcp, dest, destp, sp->state, 
 137                (tw_bucket ?
 138                 0 :
 139                 (format == 0) ?
 140                 tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
 141                (tw_bucket ?
 142                 0 :
 143                 (format == 0) ?
 144                 tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
 145                timer_active, timer_expires-jiffies,
 146                (tw_bucket ? 0 : tp->retransmits),
 147                (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
 148                (!tw_bucket && timer_active) ? sp->timeout : 0,
 149                (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
 150        
 151        if (timer_active1) add_timer(&tp->retransmit_timer);
 152        if (timer_active2) add_timer(&sp->timer);       
 153}
 154
 155/*
 156 * Get__netinfo returns the length of that string.
 157 *
 158 * KNOWN BUGS
 159 *  As in get_unix_netinfo, the buffer might be too small. If this
 160 *  happens, get__netinfo returns only part of the available infos.
 161 *
 162 *  Assumes that buffer length is a multiply of 128 - if not it will
 163 *  write past the end.   
 164 */
 165static int
 166get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
 167{
 168        struct sock *sp, *next;
 169        int len=0, i = 0;
 170        off_t pos=0;
 171        off_t begin;
 172        char tmpbuf[129];
 173  
 174        if (offset < 128) 
 175                len += sprintf(buffer, "%-127s\n",
 176                               "  sl  local_address rem_address   st tx_queue "
 177                               "rx_queue tr tm->when retrnsmt   uid  timeout inode");
 178        pos = 128;
 179        SOCKHASH_LOCK(); 
 180        sp = pro->sklist_next;
 181        while(sp != (struct sock *)pro) {
 182                if (format == 0 && sp->state == TCP_LISTEN) {
 183                        struct open_request *req;
 184
 185                        for (req = sp->tp_pinfo.af_tcp.syn_wait_queue; req;
 186                             i++, req = req->dl_next) {
 187                                if (req->sk)
 188                                        continue;
 189                                pos += 128;
 190                                if (pos < offset) 
 191                                        continue;
 192                                get__openreq(sp, req, tmpbuf, i); 
 193                                len += sprintf(buffer+len, "%-127s\n", tmpbuf);
 194                                if(len >= length) 
 195                                        goto out;
 196                        }
 197                }
 198                
 199                pos += 128;
 200                if (pos < offset)
 201                        goto next;
 202                
 203                get__sock(sp, tmpbuf, i, format);
 204                
 205                len += sprintf(buffer+len, "%-127s\n", tmpbuf);
 206                if(len >= length)
 207                        break;
 208        next:
 209                next = sp->sklist_next;
 210                sp = next;
 211                i++;
 212        }
 213out: 
 214        SOCKHASH_UNLOCK();
 215        
 216        begin = len - (pos - offset);
 217        *start = buffer + begin;
 218        len -= begin;
 219        if(len>length)
 220                len = length;
 221        if (len<0)
 222                len = 0; 
 223        return len;
 224} 
 225
 226int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 227{
 228        return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
 229}
 230
 231int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 232{
 233        return get__netinfo(&udp_prot, buffer,1, start, offset, length);
 234}
 235
 236int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 237{
 238        return get__netinfo(&raw_prot, buffer,1, start, offset, length);
 239}
 240
 241/*
 242 *      Report socket allocation statistics [mea@utu.fi]
 243 */
 244int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 245{
 246        /* From  net/socket.c  */
 247        extern int socket_get_info(char *, char **, off_t, int);
 248
 249        int len  = socket_get_info(buffer,start,offset,length);
 250
 251        len += sprintf(buffer+len,"TCP: inuse %d highest %d\n",
 252                       tcp_prot.inuse, tcp_prot.highestinuse);
 253        len += sprintf(buffer+len,"UDP: inuse %d highest %d\n",
 254                       udp_prot.inuse, udp_prot.highestinuse);
 255        len += sprintf(buffer+len,"RAW: inuse %d highest %d\n",
 256                       raw_prot.inuse, raw_prot.highestinuse);
 257        if (offset >= len)
 258        {
 259                *start = buffer;
 260                return 0;
 261        }
 262        *start = buffer + offset;
 263        len -= offset;
 264        if (len > length)
 265                len = length;
 266        if (len < 0)
 267                len = 0;
 268        return len;
 269}
 270
 271
 272/* 
 273 *      Called from the PROCfs module. This outputs /proc/net/snmp.
 274 */
 275 
 276int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 277{
 278        extern struct tcp_mib tcp_statistics;
 279        extern struct udp_mib udp_statistics;
 280        int len;
 281/*
 282  extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2;
 283*/
 284
 285        len = sprintf (buffer,
 286                "Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
 287                "Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
 288                    ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL, 
 289                    ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors, 
 290                    ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams, 
 291                    ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards, 
 292                    ip_statistics.IpInDelivers, ip_statistics.IpOutRequests, 
 293                    ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes, 
 294                    ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds, 
 295                    ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails, 
 296                    ip_statistics.IpFragOKs, ip_statistics.IpFragFails, 
 297                    ip_statistics.IpFragCreates);
 298                                
 299        len += sprintf (buffer + len,
 300                "Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
 301                "Icmp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
 302                    icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors,
 303                    icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds,
 304                    icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs,
 305                    icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos,
 306                    icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps,
 307                    icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks,
 308                    icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs,
 309                    icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs,
 310                    icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs,
 311                    icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects,
 312                    icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps,
 313                    icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps,
 314                    icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps);
 315        
 316        len += sprintf (buffer + len,
 317                "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
 318                "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
 319                    tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin,
 320                    tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn,
 321                    tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens,
 322                    tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets,
 323                    tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs,
 324                    tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs,
 325                    tcp_statistics.TcpInErrs, tcp_statistics.TcpOutRsts);
 326                
 327        len += sprintf (buffer + len,
 328                "Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n",
 329                    udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts,
 330                    udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams);            
 331/*      
 332          len += sprintf( buffer + len,
 333                "TCP fast path RX:  H2: %ul H1: %ul L: %ul\n",
 334                        tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss);
 335*/
 336        
 337        if (offset >= len)
 338        {
 339                *start = buffer;
 340                return 0;
 341        }
 342        *start = buffer + offset;
 343        len -= offset;
 344        if (len > length)
 345                len = length;
 346        if (len < 0)
 347                len = 0; 
 348        return len;
 349}
 350
 351/* 
 352 *      Output /proc/net/netstat
 353 */
 354 
 355int netstat_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 356{
 357        extern struct linux_mib net_statistics;
 358        int len;
 359
 360        len = sprintf(buffer,
 361                      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
 362                      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
 363                      " OutOfWindowIcmps LockDroppedIcmps\n"    
 364                      "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
 365                      net_statistics.SyncookiesSent,
 366                      net_statistics.SyncookiesRecv,
 367                      net_statistics.SyncookiesFailed,
 368                      net_statistics.EmbryonicRsts,
 369                      net_statistics.PruneCalled,
 370                      net_statistics.RcvPruned,
 371                      net_statistics.OfoPruned,
 372                      net_statistics.OutOfWindowIcmps,
 373                      net_statistics.LockDroppedIcmps);
 374
 375        if (offset >= len)
 376        {
 377                *start = buffer;
 378                return 0;
 379        }
 380        *start = buffer + offset;
 381        len -= offset;
 382        if (len > length)
 383                len = length;
 384        if (len < 0)
 385                len = 0; 
 386        return len;
 387}
 388
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.