summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Eitzenberger <heitzenberger@astaro.com>2009-11-11 10:10:34 +0100
committerHarald Welte <laforge@gnumonks.org>2010-10-21 19:15:39 +0200
commitb9c73a89fe179a81d66d420f24a1f50a0f3a8014 (patch)
tree693600695b0b1ca9b7e2cc5b91012c4d334a8ed1
parentd174fd10bf5d5b7e7d304295f82a824c39ade26d (diff)
IPFIX: use UDP (required for Vineyard)
Signed-off-by: Holger Eitzenberger <holger@eitzenberger.org>
-rw-r--r--include/ulogd/ulogd.h1
-rw-r--r--output/ipfix/ipfix.h31
-rw-r--r--output/ipfix/ulogd_output_IPFIX.c143
3 files changed, 156 insertions, 19 deletions
diff --git a/include/ulogd/ulogd.h b/include/ulogd/ulogd.h
index ad66c81..8de185e 100644
--- a/include/ulogd/ulogd.h
+++ b/include/ulogd/ulogd.h
@@ -26,6 +26,7 @@
#define __fmt_printf(idx, first) \
__attribute__((format (printf,(idx),(first))))
+#define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn))
#define __cold __attribute__((cold))
diff --git a/output/ipfix/ipfix.h b/output/ipfix/ipfix.h
index 2bf2ce2..bdca3b4 100644
--- a/output/ipfix/ipfix.h
+++ b/output/ipfix/ipfix.h
@@ -36,4 +36,35 @@ struct ipfix_set_hdr {
uint8_t data[];
};
+/* Vineyard IPFIX-like protocol */
+struct vy_ipfix_hdr {
+#define VY_IPFIX_VERSION 'A'
+ uint16_t version;
+ uint8_t cnt; /* RecordCount */
+ uint32_t dev_id;
+ uint32_t uptime; /* milliseconds */
+ uint32_t unix_secs;
+ uint32_t unix_nsecs;
+ uint8_t data[];
+} __packed;
+
+struct vy_ipfix_data {
+ struct sockaddr_in saddr;
+ struct sockaddr_in daddr;
+ uint16_t ifi_in;
+ uint16_t ifi_out;
+ uint32_t packets;
+ uint32_t bytes;
+ uint32_t start; /* milliseconds */
+ uint32_t end; /* milliseconds */
+ uint16_t sport;
+ uint16_t dport;
+ uint8_t l4_proto;
+ uint8_t dscp;
+ uint32_t appsig;
+ uint32_t retrans_rate;
+ uint32_t rtt;
+ uint8_t policy; /* discard, shape, ... */
+} __packed;
+
#endif /* IPFIX_H */
diff --git a/output/ipfix/ulogd_output_IPFIX.c b/output/ipfix/ulogd_output_IPFIX.c
index 1f01c60..99ec11f 100644
--- a/output/ipfix/ulogd_output_IPFIX.c
+++ b/output/ipfix/ulogd_output_IPFIX.c
@@ -39,7 +39,7 @@ enum {
};
static const struct config_keyset ipfix_kset = {
- .num_ces = 3,
+ .num_ces = 4,
.ces = {
[OID_CE] = CONFIG_KEY_INT("oid", 0),
[HOST_CE] = CONFIG_KEY_STR("host", ""),
@@ -58,10 +58,20 @@ struct ipfix_templ {
struct ipfix_templ *next;
};
+struct ipfix_flow {
+ struct llist_head link;
+ struct ulogd_value value[];
+};
+
struct ipfix_priv {
struct ulogd_fd ufd;
uint32_t seqno;
+ struct vy_ipfix_hdr *hdr;
+ char *end;
+ int num_flows;
struct ipfix_templ *templates;
+ int proto;
+ struct ulogd_timer timer;
struct sockaddr_in sa;
};
@@ -102,7 +112,7 @@ static struct ulogd_key ipfix_in_keys[] = {
};
static int
-tcp_ufd_cb(int fd, unsigned what, void *arg)
+ipfix_ufd_cb(int fd, unsigned what, void *arg)
{
struct ulogd_pluginstance *pi = arg;
struct ipfix_priv *priv = upi_priv(pi);
@@ -111,19 +121,26 @@ tcp_ufd_cb(int fd, unsigned what, void *arg)
if (what & ULOGD_FD_READ) {
nread = read(priv->ufd.fd, buf, sizeof(buf));
- if (!nread) {
+ if (nread < 0) {
+ upi_log(pi, ULOGD_ERROR, "read: %m\n");
+
+ /* FIXME plugin is not restarted */
+ ulogd_upi_set_state(pi, PsConfigured);
+ } else if (!nread) {
upi_log(pi, ULOGD_INFO, "connection reset by peer\n");
ulogd_unregister_fd(&priv->ufd);
} else
upi_log(pi, ULOGD_INFO, "unexpected data (%d bytes)\n", nread);
}
- /* FIXME plugin is not restarted */
- ulogd_upi_set_state(pi, PsConfigured);
-
return 0;
}
+static void
+ipfix_timer_cb(struct ulogd_timer *t)
+{
+}
+
static int
ipfix_configure(struct ulogd_pluginstance *pi)
{
@@ -138,6 +155,10 @@ ipfix_configure(struct ulogd_pluginstance *pi)
upi_log(pi, ULOGD_FATAL, "no destination host specified\n");
return ULOGD_IRET_ERR;
}
+ if (!strcmp(proto_ce(pi), "udp"))
+ priv->proto = IPPROTO_UDP;
+ else if (!strcmp(proto_ce(pi), "tcp"))
+ priv->proto = IPPROTO_TCP;
memset(&priv->sa, 0, sizeof(priv->sa));
priv->sa.sin_family = AF_INET;
@@ -151,7 +172,9 @@ ipfix_configure(struct ulogd_pluginstance *pi)
return ULOGD_IRET_ERR;
}
- ulogd_init_fd(&priv->ufd, -1, ULOGD_FD_READ, tcp_ufd_cb, pi);
+ ulogd_init_fd(&priv->ufd, -1, ULOGD_FD_READ, ipfix_ufd_cb, pi);
+ ulogd_init_timer(&priv->timer, 1 SEC, ipfix_timer_cb, pi,
+ TIMER_F_PERIODIC);
return ULOGD_IRET_OK;
}
@@ -160,7 +183,7 @@ static int
tcp_connect(struct ulogd_pluginstance *pi)
{
struct ipfix_priv *priv = upi_priv(pi);
- char addr[16];
+ int ret = ULOGD_IRET_ERR;
if ((priv->ufd.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
upi_log(pi, ULOGD_FATAL, "socket: %m\n");
@@ -169,31 +192,76 @@ tcp_connect(struct ulogd_pluginstance *pi)
if (connect(priv->ufd.fd, &priv->sa, sizeof(priv->sa)) < 0) {
upi_log(pi, ULOGD_ERROR, "connect: %m\n");
- return ULOGD_IRET_AGAIN;
- }
-
- if (ulogd_register_fd(&priv->ufd) < 0)
+ ret = ULOGD_IRET_AGAIN;
goto err_close;
-
- upi_log(pi, ULOGD_INFO, "connected to %s:%d\n",
- inet_ntop(AF_INET, &priv->sa.sin_addr, addr, sizeof(addr)),
- port_ce(pi));
+ }
return ULOGD_IRET_OK;
err_close:
close(priv->ufd.fd);
- return ULOGD_IRET_ERR;
+ return ret;
+}
+
+static int
+udp_connect(struct ulogd_pluginstance *pi)
+{
+ struct ipfix_priv *priv = upi_priv(pi);
+
+ if ((priv->ufd.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ upi_log(pi, ULOGD_FATAL, "socket: %m\n");
+ return ULOGD_IRET_ERR;
+ }
+
+ if (connect(priv->ufd.fd, &priv->sa, sizeof(priv->sa)) < 0) {
+ upi_log(pi, ULOGD_ERROR, "connect: %m\n");
+ return ULOGD_IRET_AGAIN;
+ }
+
+ return 0;
}
static int
ipfix_start(struct ulogd_pluginstance *pi)
{
struct ipfix_priv *priv = upi_priv(pi);
+ struct vy_ipfix_hdr *hdr = priv->hdr;
+ char addr[16];
int ret;
- if ((ret = tcp_connect(pi)) < 0)
- return ret;
+ switch (priv->proto) {
+ case IPPROTO_UDP:
+ if ((ret = udp_connect(pi)) < 0)
+ return ret;
+ break;
+ case IPPROTO_TCP:
+ if ((ret = tcp_connect(pi)) < 0)
+ return ret;
+ break;
+
+ default:
+ break;
+ }
+
+ upi_log(pi, ULOGD_INFO, "connected to %s:%d\n",
+ inet_ntop(AF_INET, &priv->sa.sin_addr, addr, sizeof(addr)),
+ port_ce(pi));
+
+ if (ulogd_register_fd(&priv->ufd) < 0)
+ return ULOGD_IRET_ERR;
+
+ ulogd_register_timer(&priv->timer);
+
+ hdr = priv->hdr = malloc(sizeof(struct vy_ipfix_hdr)
+ + 2 * sizeof(struct vy_ipfix_data));
+ if (!priv->hdr) {
+ upi_log(pi, ULOGD_ERROR, "out of memory\n");
+ return -1;
+ }
+
+ hdr->version = VY_IPFIX_VERSION;
+ hdr->cnt = 2;
+ hdr->dev_id = 42;
return ULOGD_IRET_OK;
}
@@ -203,6 +271,11 @@ ipfix_stop(struct ulogd_pluginstance *pi)
{
struct ipfix_priv *priv = upi_priv(pi);
+ close(priv->ufd.fd);
+ priv->ufd.fd = -1;
+
+ free(priv->hdr);
+
return 0;
}
@@ -210,8 +283,40 @@ static int
ipfix_interp(struct ulogd_pluginstance *pi, unsigned *flags)
{
struct ipfix_priv *priv = upi_priv(pi);
+ struct ulogd_key *in = pi->input.keys;
+ struct vy_ipfix_hdr *hdr = priv->hdr;
+ struct vy_ipfix_data *data;
+ int ret;
+ BUG_ON(priv->num_flows < 0 || priv->num_flows >= 2);
+ data = ((struct vy_ipfix_data *)hdr->data) + priv->num_flows;
+
+ if (!key_src_valid(&in[InIpSaddr]))
+ return ULOGD_IRET_OK;
+
+ key_src_in(&in[InIpSaddr], &data->saddr.sin_addr);
+ key_src_in(&in[InIpDaddr], &data->daddr.sin_addr);
+ data->ifi_in = data->ifi_out = 0U;
+ data->packets = (uint32_t)(key_src_u64(&in[InRawInPktCount])
+ + key_src_u64(&in[InRawOutPktCount]));
+ data->bytes = (uint32_t)(key_src_u64(&in[InRawInPktLen])
+ + key_src_u64(&in[InRawOutPktLen]));
+ data->start = key_src_u32(&in[InFlowStartSec])
+ + key_src_u32(&in[InFlowStartUsec]) / 1000;
+ data->end = key_src_u32(&in[InFlowEndSec])
+ + key_src_u32(&in[InFlowEndUsec]) / 1000;
+ if (key_src_valid(&in[InL4SPort])) {
+ data->sport = key_src_u16(&in[InL4SPort]);
+ data->dport = key_src_u16(&in[InL4DPort]);
+ }
+ data->l4_proto = key_src_u8(&in[InIpProto]);
+ data->dscp = 0;
+ if (++priv->num_flows >= 2) {
+ ret = send(priv->ufd.fd, priv->hdr, sizeof(struct vy_ipfix_hdr)
+ + 2 * sizeof(struct vy_ipfix_data), 0);
+ priv->num_flows = 0;
+ }
return 0;
}