Add "settimestamp" and "gettimestamp" messages, providing the the ability
to embed a timestamp (struct timeval) in outgoing packets. The message specifies the offset at which the timestamp should be inserted. NG_SOURCE(4) gives an example usage that queues an ICMP packet. Using that example, the following command will insert a timestamp in the ICMP's data payload: ngctl msg src0: settimestamp '{ offset=0x2a flags=1 }' Sponsored by: Sandvine Incorporated
This commit is contained in:
parent
b6f6e672f7
commit
5f87dd698c
@ -77,6 +77,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
#define NG_SOURCE_INTR_TICKS 1
|
#define NG_SOURCE_INTR_TICKS 1
|
||||||
#define NG_SOURCE_DRIVER_IFQ_MAXLEN (4*1024)
|
#define NG_SOURCE_DRIVER_IFQ_MAXLEN (4*1024)
|
||||||
|
|
||||||
|
#define mtod_off(m,off,t) ((t)(mtod((m),caddr_t)+(off)))
|
||||||
|
|
||||||
/* Per node info */
|
/* Per node info */
|
||||||
struct privdata {
|
struct privdata {
|
||||||
node_p node;
|
node_p node;
|
||||||
@ -88,6 +90,7 @@ struct privdata {
|
|||||||
struct callout intr_ch;
|
struct callout intr_ch;
|
||||||
uint64_t packets; /* packets to send */
|
uint64_t packets; /* packets to send */
|
||||||
uint32_t queueOctets;
|
uint32_t queueOctets;
|
||||||
|
struct ng_source_embed_info embed_timestamp;
|
||||||
};
|
};
|
||||||
typedef struct privdata *sc_p;
|
typedef struct privdata *sc_p;
|
||||||
|
|
||||||
@ -110,6 +113,10 @@ static int ng_source_start (sc_p, uint64_t);
|
|||||||
static void ng_source_stop (sc_p);
|
static void ng_source_stop (sc_p);
|
||||||
static int ng_source_send (sc_p, int, int *);
|
static int ng_source_send (sc_p, int, int *);
|
||||||
static int ng_source_store_output_ifp(sc_p, char *);
|
static int ng_source_store_output_ifp(sc_p, char *);
|
||||||
|
static void ng_source_packet_mod(sc_p, struct mbuf *,
|
||||||
|
int, int, caddr_t, int);
|
||||||
|
static int ng_source_dup_mod(sc_p, struct mbuf *,
|
||||||
|
struct mbuf **);
|
||||||
|
|
||||||
/* Parse type for timeval */
|
/* Parse type for timeval */
|
||||||
static const struct ng_parse_struct_field ng_source_timeval_type_fields[] = {
|
static const struct ng_parse_struct_field ng_source_timeval_type_fields[] = {
|
||||||
@ -130,6 +137,14 @@ static const struct ng_parse_type ng_source_stats_type = {
|
|||||||
&ng_source_stats_type_fields
|
&ng_source_stats_type_fields
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Parse type for struct ng_source_embed_info */
|
||||||
|
static const struct ng_parse_struct_field ng_source_embed_type_fields[] =
|
||||||
|
NG_SOURCE_EMBED_TYPE_INFO;
|
||||||
|
static const struct ng_parse_type ng_source_embed_type = {
|
||||||
|
&ng_parse_struct_type,
|
||||||
|
&ng_source_embed_type_fields
|
||||||
|
};
|
||||||
|
|
||||||
/* List of commands and how to convert arguments to/from ASCII */
|
/* List of commands and how to convert arguments to/from ASCII */
|
||||||
static const struct ng_cmdlist ng_source_cmds[] = {
|
static const struct ng_cmdlist ng_source_cmds[] = {
|
||||||
{
|
{
|
||||||
@ -188,6 +203,20 @@ static const struct ng_cmdlist ng_source_cmds[] = {
|
|||||||
&ng_parse_uint32_type,
|
&ng_parse_uint32_type,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
NGM_SOURCE_COOKIE,
|
||||||
|
NGM_SOURCE_SET_TIMESTAMP,
|
||||||
|
"settimestamp",
|
||||||
|
&ng_source_embed_type,
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NGM_SOURCE_COOKIE,
|
||||||
|
NGM_SOURCE_GET_TIMESTAMP,
|
||||||
|
"gettimestamp",
|
||||||
|
NULL,
|
||||||
|
&ng_source_embed_type
|
||||||
|
},
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -372,6 +401,29 @@ ng_source_rcvmsg(node_p node, item_p item, hook_p lasthook)
|
|||||||
|
|
||||||
sc->stats.maxPps = pps;
|
sc->stats.maxPps = pps;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NGM_SOURCE_SET_TIMESTAMP:
|
||||||
|
{
|
||||||
|
struct ng_source_embed_info *embed;
|
||||||
|
|
||||||
|
embed = (struct ng_source_embed_info *)msg->data;
|
||||||
|
bcopy(embed, &sc->embed_timestamp, sizeof(*embed));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NGM_SOURCE_GET_TIMESTAMP:
|
||||||
|
{
|
||||||
|
struct ng_source_embed_info *embed;
|
||||||
|
|
||||||
|
NG_MKRESPONSE(resp, msg, sizeof(*embed), M_DONTWAIT);
|
||||||
|
if (resp == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
embed = (struct ng_source_embed_info *)resp->data;
|
||||||
|
bcopy(&sc->embed_timestamp, embed, sizeof(*embed));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -662,11 +714,13 @@ ng_source_send(sc_p sc, int tosend, int *sent_p)
|
|||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Duplicate the packet. */
|
/* Duplicate and modify the packet. */
|
||||||
m2 = m_copypacket(m, M_DONTWAIT);
|
error = ng_source_dup_mod(sc, m, &m2);
|
||||||
if (m2 == NULL) {
|
if (error) {
|
||||||
_IF_PREPEND(&sc->snd_queue, m);
|
if (error == ENOBUFS)
|
||||||
error = ENOBUFS;
|
_IF_PREPEND(&sc->snd_queue, m);
|
||||||
|
else
|
||||||
|
_IF_ENQUEUE(&sc->snd_queue, m);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,3 +739,66 @@ ng_source_send(sc_p sc, int tosend, int *sent_p)
|
|||||||
*sent_p = sent;
|
*sent_p = sent;
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modify packet in 'm' by changing 'len' bytes starting at 'offset'
|
||||||
|
* to data in 'cp'.
|
||||||
|
*
|
||||||
|
* The packet data in 'm' must be in a contiguous buffer in a single mbuf.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ng_source_packet_mod(sc_p sc, struct mbuf *m, int offset, int len, caddr_t cp,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Can't modify beyond end of packet. */
|
||||||
|
/* TODO: Pad packet for this case. */
|
||||||
|
if (offset + len > m->m_len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bcopy(cp, mtod_off(m, offset, caddr_t), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ng_source_dup_mod(sc_p sc, struct mbuf *m0, struct mbuf **m_ptr)
|
||||||
|
{
|
||||||
|
struct mbuf *m;
|
||||||
|
struct ng_source_embed_info *ts;
|
||||||
|
int modify;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Are we going to modify packets? */
|
||||||
|
modify = sc->embed_timestamp.flags & NGM_SOURCE_EMBED_ENABLE;
|
||||||
|
|
||||||
|
/* Duplicate the packet. */
|
||||||
|
if (modify)
|
||||||
|
m = m_dup(m0, M_DONTWAIT);
|
||||||
|
else
|
||||||
|
m = m_copypacket(m0, M_DONTWAIT);
|
||||||
|
if (m == NULL) {
|
||||||
|
error = ENOBUFS;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
*m_ptr = m;
|
||||||
|
|
||||||
|
if (!modify)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Modify the copied packet for sending. */
|
||||||
|
KASSERT(M_WRITABLE(m), ("%s: packet not writable", __func__));
|
||||||
|
|
||||||
|
ts = &sc->embed_timestamp;
|
||||||
|
if (ts->flags & NGM_SOURCE_EMBED_ENABLE) {
|
||||||
|
struct timeval now;
|
||||||
|
getmicrotime(&now);
|
||||||
|
now.tv_sec = htonl(now.tv_sec);
|
||||||
|
now.tv_usec = htonl(now.tv_usec);
|
||||||
|
ng_source_packet_mod(sc, m, ts->offset, sizeof (now),
|
||||||
|
(caddr_t)&now, ts->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
@ -78,6 +78,21 @@ extern const struct ng_parse_type ng_source_timeval_type;
|
|||||||
{ NULL } \
|
{ NULL } \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Packet embedding info for NGM_SOURCE_GET/SET_TIMESTAMP */
|
||||||
|
struct ng_source_embed_info {
|
||||||
|
uint16_t offset; /* offset from ethernet header */
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t spare;
|
||||||
|
};
|
||||||
|
#define NGM_SOURCE_EMBED_ENABLE 0x01 /* enable embedding */
|
||||||
|
|
||||||
|
/* Keep this in sync with the above structure definition. */
|
||||||
|
#define NG_SOURCE_EMBED_TYPE_INFO { \
|
||||||
|
{ "offset", &ng_parse_hint16_type }, \
|
||||||
|
{ "flags", &ng_parse_hint8_type }, \
|
||||||
|
{ NULL } \
|
||||||
|
}
|
||||||
|
|
||||||
/* Netgraph commands */
|
/* Netgraph commands */
|
||||||
enum {
|
enum {
|
||||||
NGM_SOURCE_GET_STATS = 1, /* get stats */
|
NGM_SOURCE_GET_STATS = 1, /* get stats */
|
||||||
@ -88,6 +103,8 @@ enum {
|
|||||||
NGM_SOURCE_CLR_DATA, /* clear the queued data */
|
NGM_SOURCE_CLR_DATA, /* clear the queued data */
|
||||||
NGM_SOURCE_SETIFACE, /* configure downstream iface */
|
NGM_SOURCE_SETIFACE, /* configure downstream iface */
|
||||||
NGM_SOURCE_SETPPS, /* rate-limiting packets per second */
|
NGM_SOURCE_SETPPS, /* rate-limiting packets per second */
|
||||||
|
NGM_SOURCE_SET_TIMESTAMP, /* embed xmit timestamp */
|
||||||
|
NGM_SOURCE_GET_TIMESTAMP,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _NETGRAPH_NG_SOURCE_H_ */
|
#endif /* _NETGRAPH_NG_SOURCE_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user