]>
git.proxmox.com Git - ovs.git/blob - ofproto/netflow.c
2 * Copyright (c) 2008, 2009 Nicira Networks.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <arpa/inet.h>
29 #include "socket-util.h"
35 #define THIS_MODULE VLM_netflow
38 #define NETFLOW_V5_VERSION 5
40 /* Every NetFlow v5 message contains the header that follows. This is
41 * followed by up to thirty records that describe a terminating flow.
42 * We only send a single record per NetFlow message.
44 struct netflow_v5_header
{
45 uint16_t version
; /* NetFlow version is 5. */
46 uint16_t count
; /* Number of records in this message. */
47 uint32_t sysuptime
; /* System uptime in milliseconds. */
48 uint32_t unix_secs
; /* Number of seconds since Unix epoch. */
49 uint32_t unix_nsecs
; /* Number of residual nanoseconds
50 after epoch seconds. */
51 uint32_t flow_seq
; /* Number of flows since sending
53 uint8_t engine_type
; /* Engine type. */
54 uint8_t engine_id
; /* Engine id. */
55 uint16_t sampling_interval
; /* Set to zero. */
57 BUILD_ASSERT_DECL(sizeof(struct netflow_v5_header
) == 24);
59 /* A NetFlow v5 description of a terminating flow. It is preceded by a
62 struct netflow_v5_record
{
63 uint32_t src_addr
; /* Source IP address. */
64 uint32_t dst_addr
; /* Destination IP address. */
65 uint32_t nexthop
; /* IP address of next hop. Set to 0. */
66 uint16_t input
; /* Input interface index. */
67 uint16_t output
; /* Output interface index. */
68 uint32_t packet_count
; /* Number of packets. */
69 uint32_t byte_count
; /* Number of bytes. */
70 uint32_t init_time
; /* Value of sysuptime on first packet. */
71 uint32_t used_time
; /* Value of sysuptime on last packet. */
73 /* The 'src_port' and 'dst_port' identify the source and destination
74 * port, respectively, for TCP and UDP. For ICMP, the high-order
75 * byte identifies the type and low-order byte identifies the code
76 * in the 'dst_port' field. */
81 uint8_t tcp_flags
; /* Union of seen TCP flags. */
82 uint8_t ip_proto
; /* IP protocol. */
83 uint8_t ip_tos
; /* IP TOS value. */
84 uint16_t src_as
; /* Source AS ID. Set to 0. */
85 uint16_t dst_as
; /* Destination AS ID. Set to 0. */
86 uint8_t src_mask
; /* Source mask bits. Set to 0. */
87 uint8_t dst_mask
; /* Destination mask bits. Set to 0. */
90 BUILD_ASSERT_DECL(sizeof(struct netflow_v5_record
) == 48);
93 uint8_t engine_type
; /* Value of engine_type to use. */
94 uint8_t engine_id
; /* Value of engine_id to use. */
95 long long int boot_time
; /* Time when netflow_create() was called. */
96 int *fds
; /* Sockets for NetFlow collectors. */
97 size_t n_fds
; /* Number of Netflow collectors. */
98 bool add_id_to_iface
; /* Put the 7 least signficiant bits of
99 * 'engine_id' into the most signficant
100 * bits of the interface fields. */
101 uint32_t netflow_cnt
; /* Flow sequence number for NetFlow. */
102 struct ofpbuf packet
; /* NetFlow packet being accumulated. */
105 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
108 open_collector(char *dst
)
110 char *save_ptr
= NULL
;
111 const char *host_name
;
112 const char *port_string
;
113 struct sockaddr_in sin
;
117 /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that
118 * can cause segfaults here:
119 * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614.
120 * Using "::" instead of the obvious ":" works around it. */
121 host_name
= strtok_r(dst
, ":", &save_ptr
);
122 port_string
= strtok_r(NULL
, ":", &save_ptr
);
124 ovs_error(0, "%s: bad peer name format", dst
);
125 return -EAFNOSUPPORT
;
128 ovs_error(0, "%s: bad port format", dst
);
129 return -EAFNOSUPPORT
;
132 memset(&sin
, 0, sizeof sin
);
133 sin
.sin_family
= AF_INET
;
134 if (lookup_ip(host_name
, &sin
.sin_addr
)) {
137 sin
.sin_port
= htons(atoi(port_string
));
139 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
141 VLOG_ERR("%s: socket: %s", dst
, strerror(errno
));
145 retval
= set_nonblocking(fd
);
151 retval
= connect(fd
, (struct sockaddr
*) &sin
, sizeof sin
);
154 VLOG_ERR("%s: connect: %s", dst
, strerror(error
));
163 netflow_expire(struct netflow
*nf
, const struct ofexpired
*expired
)
165 struct netflow_v5_header
*nf_hdr
;
166 struct netflow_v5_record
*nf_rec
;
169 /* NetFlow only reports on IP packets. */
170 if (expired
->flow
.dl_type
!= htons(ETH_TYPE_IP
)) {
176 if (!nf
->packet
.size
) {
177 nf_hdr
= ofpbuf_put_zeros(&nf
->packet
, sizeof *nf_hdr
);
178 nf_hdr
->version
= htons(NETFLOW_V5_VERSION
);
179 nf_hdr
->count
= htons(0);
180 nf_hdr
->sysuptime
= htonl(time_msec() - nf
->boot_time
);
181 nf_hdr
->unix_secs
= htonl(now
.tv_sec
);
182 nf_hdr
->unix_nsecs
= htonl(now
.tv_usec
* 1000);
183 nf_hdr
->flow_seq
= htonl(nf
->netflow_cnt
++);
184 nf_hdr
->engine_type
= nf
->engine_type
;
185 nf_hdr
->engine_id
= nf
->engine_id
;
186 nf_hdr
->sampling_interval
= htons(0);
189 nf_hdr
= nf
->packet
.data
;
190 nf_hdr
->count
= htons(ntohs(nf_hdr
->count
) + 1);
192 nf_rec
= ofpbuf_put_zeros(&nf
->packet
, sizeof *nf_rec
);
193 nf_rec
->src_addr
= expired
->flow
.nw_src
;
194 nf_rec
->dst_addr
= expired
->flow
.nw_dst
;
195 nf_rec
->nexthop
= htons(0);
196 if (nf
->add_id_to_iface
) {
197 uint16_t iface
= (nf
->engine_id
& 0x7f) << 9;
198 nf_rec
->input
= htons(iface
| (expired
->flow
.in_port
& 0x1ff));
199 nf_rec
->output
= htons(iface
);
200 printf("input: %x\n", ntohs(nf_rec
->input
));
202 nf_rec
->input
= htons(expired
->flow
.in_port
);
203 nf_rec
->output
= htons(0);
205 nf_rec
->packet_count
= htonl(MIN(expired
->packet_count
, UINT32_MAX
));
206 nf_rec
->byte_count
= htonl(MIN(expired
->byte_count
, UINT32_MAX
));
207 nf_rec
->init_time
= htonl(expired
->created
- nf
->boot_time
);
208 nf_rec
->used_time
= htonl(MAX(expired
->created
, expired
->used
)
210 if (expired
->flow
.nw_proto
== IP_TYPE_ICMP
) {
211 /* In NetFlow, the ICMP type and code are concatenated and
212 * placed in the 'dst_port' field. */
213 uint8_t type
= ntohs(expired
->flow
.tp_src
);
214 uint8_t code
= ntohs(expired
->flow
.tp_dst
);
215 nf_rec
->src_port
= htons(0);
216 nf_rec
->dst_port
= htons((type
<< 8) | code
);
218 nf_rec
->src_port
= expired
->flow
.tp_src
;
219 nf_rec
->dst_port
= expired
->flow
.tp_dst
;
221 nf_rec
->tcp_flags
= expired
->tcp_flags
;
222 nf_rec
->ip_proto
= expired
->flow
.nw_proto
;
223 nf_rec
->ip_tos
= expired
->ip_tos
;
225 /* NetFlow messages are limited to 30 records. A length of 1400
226 * bytes guarantees that the limit is not exceeded. */
227 if (nf
->packet
.size
>= 1400) {
233 netflow_run(struct netflow
*nf
)
237 if (!nf
->packet
.size
) {
241 for (i
= 0; i
< nf
->n_fds
; i
++) {
242 if (send(nf
->fds
[i
], nf
->packet
.data
, nf
->packet
.size
, 0) == -1) {
243 VLOG_WARN_RL(&rl
, "netflow message send failed: %s",
251 clear_collectors(struct netflow
*nf
)
255 for (i
= 0; i
< nf
->n_fds
; i
++) {
264 netflow_set_collectors(struct netflow
*nf
, const struct svec
*collectors_
)
266 struct svec collectors
;
270 clear_collectors(nf
);
272 svec_clone(&collectors
, collectors_
);
273 svec_sort_unique(&collectors
);
275 nf
->fds
= xmalloc(sizeof *nf
->fds
* collectors
.n
);
276 for (i
= 0; i
< collectors
.n
; i
++) {
277 const char *name
= collectors
.names
[i
];
278 char *tmpname
= xstrdup(name
);
279 int fd
= open_collector(tmpname
);
282 nf
->fds
[nf
->n_fds
++] = fd
;
284 VLOG_WARN("couldn't open connection to collector (%s), "
285 "ignoring %s\n", strerror(-fd
), name
);
292 svec_destroy(&collectors
);
297 netflow_set_engine(struct netflow
*nf
, uint8_t engine_type
,
298 uint8_t engine_id
, bool add_id_to_iface
)
300 nf
->engine_type
= engine_type
;
301 nf
->engine_id
= engine_id
;
302 nf
->add_id_to_iface
= add_id_to_iface
;
308 struct netflow
*nf
= xmalloc(sizeof *nf
);
311 nf
->boot_time
= time_msec();
314 nf
->add_id_to_iface
= false;
316 ofpbuf_init(&nf
->packet
, 1500);
321 netflow_destroy(struct netflow
*nf
)
324 ofpbuf_uninit(&nf
->packet
);
325 clear_collectors(nf
);