IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau C Discussion :

code d'activation timestamp hardware


Sujet :

Réseau C

  1. #1
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut code d'activation timestamp hardware
    Bonjour,

    J'essaie de comprendre comment marche le code de la biblithèque pcap (j'utilise libpcap version 1.4.0) pour activer le timestamp hardware des paquets.
    Il s'agit du code pcap-linux.c, voici un bout de code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
     
    /*
     * Attempt to set up memory-mapped access.
     *
     * On success, returns 1, and sets *status to 0 if there are no warnings
     * or to a PCAP_WARNING_ code if there is a warning.
     *
     * On failure due to lack of support for memory-mapped capture, returns
     * 0.
     *
     * On error, returns -1, and sets *status to the appropriate error code;
     * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
     */
    static int
    create_ring(pcap_t *handle, int *status)
    {
    	unsigned i, j, frames_per_block;
    	struct tpacket_req req;
    	socklen_t len;
    	unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff;
    	unsigned int frame_size;
     
    	/*
    	 * Start out assuming no warnings or errors.
    	 */
    	*status = 0;
     
    	/* Note that with large snapshot length (say 64K, which is the default
    	 * for recent versions of tcpdump, the value that "-s 0" has given
    	 * for a long time with tcpdump, and the default in Wireshark/TShark),
    	 * if we use the snapshot length to calculate the frame length,
    	 * only a few frames will be available in the ring even with pretty
    	 * large ring size (and a lot of memory will be unused).
    	 *
    	 * Ideally, we should choose a frame length based on the
    	 * minimum of the specified snapshot length and the maximum
    	 * packet size.  That's not as easy as it sounds; consider, for
    	 * example, an 802.11 interface in monitor mode, where the
    	 * frame would include a radiotap header, where the maximum
    	 * radiotap header length is device-dependent.
    	 *
    	 * So, for now, we just do this for Ethernet devices, where
    	 * there's no metadata header, and the link-layer header is
    	 * fixed length.  We can get the maximum packet size by
    	 * adding 18, the Ethernet header length plus the CRC length
    	 * (just in case we happen to get the CRC in the packet), to
    	 * the MTU of the interface; we fetch the MTU in the hopes
    	 * that it reflects support for jumbo frames.  (Even if the
    	 * interface is just being used for passive snooping, the driver
    	 * might set the size of buffers in the receive ring based on
    	 * the MTU, so that the MTU limits the maximum size of packets
    	 * that we can receive.)
    	 *
    	 * We don't do that if segmentation/fragmentation or receive
    	 * offload are enabled, so we don't get rudely surprised by
    	 * "packets" bigger than the MTU. */
    	frame_size = handle->snapshot;
    	if (handle->linktype == DLT_EN10MB) {
    		int mtu;
    		int offload;
     
    		offload = iface_get_offload(handle);
    		if (offload == -1) {
    			*status = PCAP_ERROR;
    			return -1;
    		}
    		if (!offload) {
    			mtu = iface_get_mtu(handle->fd, handle->opt.source,
    			    handle->errbuf);
    			if (mtu == -1) {
    				*status = PCAP_ERROR;
    				return -1;
    			}
    			if (frame_size > mtu + 18)
    				frame_size = mtu + 18;
    		}
    	}
     
    	/* NOTE: calculus matching those in tpacket_rcv()
    	 * in linux-2.6/net/packet/af_packet.c
    	 */
    	len = sizeof(sk_type);
    	if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type, &len) < 0) {
    		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno));
    		*status = PCAP_ERROR;
    		return -1;
    	}
    #ifdef PACKET_RESERVE
    	len = sizeof(tp_reserve);
    	if (getsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, &tp_reserve, &len) < 0) {
    		if (errno != ENOPROTOOPT) {
    			/*
    			 * ENOPROTOOPT means "kernel doesn't support
    			 * PACKET_RESERVE", in which case we fall back
    			 * as best we can.
    			 */
    			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "getsockopt: %s", pcap_strerror(errno));
    			*status = PCAP_ERROR;
    			return -1;
    		}
    		tp_reserve = 0;	/* older kernel, reserve not supported */
    	}
    #else
    	tp_reserve = 0;	/* older kernel, reserve not supported */
    #endif
    	maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE;
    		/* XXX: in the kernel maclen is calculated from
    		 * LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len
    		 * in:  packet_snd()           in linux-2.6/net/packet/af_packet.c
    		 * then packet_alloc_skb()     in linux-2.6/net/packet/af_packet.c
    		 * then sock_alloc_send_pskb() in linux-2.6/net/core/sock.c
    		 * but I see no way to get those sizes in userspace,
    		 * like for instance with an ifreq ioctl();
    		 * the best thing I've found so far is MAX_HEADER in the kernel
    		 * part of linux-2.6/include/linux/netdevice.h
    		 * which goes up to 128+48=176; since pcap-linux.c defines
    		 * a MAX_LINKHEADER_SIZE of 256 which is greater than that,
    		 * let's use it.. maybe is it even large enough to directly
    		 * replace macoff..
    		 */
    	tp_hdrlen = TPACKET_ALIGN(handle->md.tp_hdrlen) + sizeof(struct sockaddr_ll) ;
    	netoff = TPACKET_ALIGN(tp_hdrlen + (maclen < 16 ? 16 : maclen)) + tp_reserve;
    		/* NOTE: AFAICS tp_reserve may break the TPACKET_ALIGN of
    		 * netoff, which contradicts
    		 * linux-2.6/Documentation/networking/packet_mmap.txt
    		 * documenting that:
    		 * "- Gap, chosen so that packet data (Start+tp_net)
    		 * aligns to TPACKET_ALIGNMENT=16"
    		 */
    		/* NOTE: in linux-2.6/include/linux/skbuff.h:
    		 * "CPUs often take a performance hit
    		 *  when accessing unaligned memory locations"
    		 */
    	macoff = netoff - maclen;
    	req.tp_frame_size = TPACKET_ALIGN(macoff + frame_size);
    	req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size;
     
    	/* compute the minumum block size that will handle this frame. 
    	 * The block has to be page size aligned. 
    	 * The max block size allowed by the kernel is arch-dependent and 
    	 * it's not explicitly checked here. */
    	req.tp_block_size = getpagesize();
    	while (req.tp_block_size < req.tp_frame_size) 
    		req.tp_block_size <<= 1;
     
    	frames_per_block = req.tp_block_size/req.tp_frame_size;
     
    	/*
    	 * PACKET_TIMESTAMP was added after linux/net_tstamp.h was,
    	 * so we check for PACKET_TIMESTAMP.  We check for
    	 * linux/net_tstamp.h just in case a system somehow has
    	 * PACKET_TIMESTAMP but not linux/net_tstamp.h; that might
    	 * be unnecessary.
    	 *
    	 * SIOCSHWTSTAMP was introduced in the patch that introduced
    	 * linux/net_tstamp.h, so we don't bother checking whether
    	 * SIOCSHWTSTAMP is defined (if your Linux system has
    	 * linux/net_tstamp.h but doesn't define SIOCSHWTSTAMP, your
    	 * Linux system is badly broken).
    	 */
    #if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
    	/*
    	 * If we were told to do so, ask the kernel and the driver
    	 * to use hardware timestamps.
    	 *
    	 * Hardware timestamps are only supported with mmapped
    	 * captures.
    	 */
    	if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER ||
    	    handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER_UNSYNCED) {
    		struct hwtstamp_config hwconfig;
    		struct ifreq ifr;
    		int timesource;
     
    		/*
    		 * Ask for hardware time stamps on all packets,
    		 * including transmitted packets.
    		 */
    		memset(&hwconfig, 0, sizeof(hwconfig));
    		hwconfig.tx_type = HWTSTAMP_TX_ON;
    		hwconfig.rx_filter = HWTSTAMP_FILTER_ALL;
     
    		memset(&ifr, 0, sizeof(ifr));
    		strcpy(ifr.ifr_name, handle->opt.source);
    		ifr.ifr_data = (void *)&hwconfig;
     
    		if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) {
    			switch (errno) {
     
    			case EPERM:
    				/*
    				 * Treat this as an error, as the
    				 * user should try to run this
    				 * with the appropriate privileges -
    				 * and, if they can't, shouldn't
    				 * try requesting hardware time stamps.
    				 */
    				*status = PCAP_ERROR_PERM_DENIED;
    				return -1;
     
    			case EOPNOTSUPP:
    				/*
    				 * Treat this as a warning, as the
    				 * only way to fix the warning is to
    				 * get an adapter that supports hardware
    				 * time stamps.  We'll just fall back
    				 * on the standard host time stamps.
    				 */
    				*status = PCAP_WARNING_TSTAMP_TYPE_NOTSUP;
    				break;
     
    			default:
    				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
    					"SIOCSHWTSTAMP failed: %s",
    					pcap_strerror(errno));
    				*status = PCAP_ERROR;
    				return -1;
    			}
    		} else {
    			/*
    			 * Well, that worked.  Now specify the type of
    			 * hardware time stamp we want for this
    			 * socket.
    			 */
    			if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER) {
    				/*
    				 * Hardware timestamp, synchronized
    				 * with the system clock.
    				 */
    				timesource = SOF_TIMESTAMPING_SYS_HARDWARE;
    			} else {
    				/*
    				 * PCAP_TSTAMP_ADAPTER_UNSYNCED - hardware
    				 * timestamp, not synchronized with the
    				 * system clock.
    				 */
    				timesource = SOF_TIMESTAMPING_RAW_HARDWARE;
    			}
    			if (setsockopt(handle->fd, SOL_PACKET, PACKET_TIMESTAMP,
    				(void *)&timesource, sizeof(timesource))) {
    				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 
    					"can't set PACKET_TIMESTAMP: %s", 
    					pcap_strerror(errno));
    				*status = PCAP_ERROR;
    				return -1;
    			}
    		}
    	}
    #endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */
     
    	/* ask the kernel to create the ring */
    retry:
    	req.tp_block_nr = req.tp_frame_nr / frames_per_block;
     
    	/* req.tp_frame_nr is requested to match frames_per_block*req.tp_block_nr */
    	req.tp_frame_nr = req.tp_block_nr * frames_per_block;
     
    	if (setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
    					(void *) &req, sizeof(req))) {
    		if ((errno == ENOMEM) && (req.tp_block_nr > 1)) {
    			/*
    			 * Memory failure; try to reduce the requested ring
    			 * size.
    			 *
    			 * We used to reduce this by half -- do 5% instead.
    			 * That may result in more iterations and a longer
    			 * startup, but the user will be much happier with
    			 * the resulting buffer size.
    			 */
    			if (req.tp_frame_nr < 20)
    				req.tp_frame_nr -= 1;
    			else
    				req.tp_frame_nr -= req.tp_frame_nr/20;
    			goto retry;
    		}
    		if (errno == ENOPROTOOPT) {
    			/*
    			 * We don't have ring buffer support in this kernel.
    			 */
    			return 0;
    		}
    		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
    		    "can't create rx ring on packet socket: %s",
    		    pcap_strerror(errno));
    		*status = PCAP_ERROR;
    		return -1;
    	}
     
    	/* memory map the rx ring */
    	handle->md.mmapbuflen = req.tp_block_nr * req.tp_block_size;
    	handle->md.mmapbuf = mmap(0, handle->md.mmapbuflen,
    	    PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0);
    	if (handle->md.mmapbuf == MAP_FAILED) {
    		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
    		    "can't mmap rx ring: %s", pcap_strerror(errno));
     
    		/* clear the allocated ring on error*/
    		destroy_ring(handle);
    		*status = PCAP_ERROR;
    		return -1;
    	}
     
    	/* allocate a ring for each frame header pointer*/
    	handle->cc = req.tp_frame_nr;
    	handle->buffer = malloc(handle->cc * sizeof(union thdr *));
    	if (!handle->buffer) {
    		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
    		    "can't allocate ring of frame headers: %s",
    		    pcap_strerror(errno));
     
    		destroy_ring(handle);
    		*status = PCAP_ERROR;
    		return -1;
    	}
     
    	/* fill the header ring with proper frame ptr*/
    	handle->offset = 0;
    	for (i=0; i<req.tp_block_nr; ++i) {
    		void *base = &handle->md.mmapbuf[i*req.tp_block_size];
    		for (j=0; j<frames_per_block; ++j, ++handle->offset) {
    			RING_GET_FRAME(handle) = base;
    			base += req.tp_frame_size;
    		}
    	}
     
    	handle->bufsize = req.tp_frame_size;
    	handle->offset = 0;
    	return 1;
    }
    à la ligne 187, on s'adresse au driver de la carte avec ioctl et on lui dit d'activer le timestamp hardware... (corrigez moi si ce n'est pas le cas)

    Ma question est:
    Pourquoi on doit dire à la socket, en utilisant sockopt avec l'option SOL_SOCKET à la ligne 239, qu'on veut un timestamp hardware ? pourquoi la ligne 187 ne suffit-elle pas ?

    Merci d'avance pour votre aide

  2. #2
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    Citation Envoyé par ikuzar
    Ma question est:
    Pourquoi on doit dire à la socket, en utilisant sockopt avec l'option SOL_SOCKET à la ligne 239, qu'on veut un timestamp hardware ? pourquoi la ligne 187 ne suffit-elle pas ?
    Salut, la ligne 187 comme tu l'as bien compris sert à activer le timestamp hardware via SIOCSHWTSTAMP, la ligne 239 n'est pas redondante elle définie la source du timestamp (l'horloge) via PACKET_TIMESTAMP, les deux options possible:
    Code /source/Documentation/networking/timestamping/timestamping.c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    "  SOF_TIMESTAMPING_SYS_HARDWARE - request reporting of transformed HW time stamps\n"
    "  SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
    To start press any key. (reading screen) Where's the "any" key? I see Esc, Catarl, and Pig Up. There doesn't seem to be any "any" key. Wo! All this computer hacking is making me thirsty. I think I'll order a Tab. (presses TAB key). -- HOMER --

  3. #3
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut
    D'accord,
    Dans ce cas, pourquoi s'adresse - t - on à la socket et non pas au driver pour dire qu'on veut une source de timestamp système ? la socket se trouve à un niveau trop haut pour faire ca non ?

  4. #4
    Membre actif
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    630
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 630
    Points : 234
    Points
    234
    Par défaut
    Si j'ai bien compris ce qui est dit ici: http://seclists.org/tcpdump/2010/q2/99, en fait, le driver fournit deux timestamps issus des deux sources (NIC clock et system clock).
    C'est à l'utilisateur de choisir quelle source il veut utiliser, c'est pour cela qu'on s'adresse à la socket..

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. activer le timestamp hardware sur un NIC d'intel
    Par ikuzar dans le forum Équipements
    Réponses: 2
    Dernier message: 20/08/2013, 15h23
  2. Problème de code d'activation
    Par cmoi_doudi dans le forum Sécurité
    Réponses: 4
    Dernier message: 16/06/2008, 21h36
  3. Réponses: 8
    Dernier message: 20/12/2007, 19h44
  4. Réponses: 4
    Dernier message: 29/10/2007, 10h35
  5. code pour activer javascript
    Par richton95 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 24/03/2006, 15h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo