]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc. | |
3 | * | |
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: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
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. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | ||
19 | #include "collectors.h" | |
20 | ||
21 | #include <errno.h> | |
22 | #include <stdlib.h> | |
23 | #include <sys/socket.h> | |
24 | #include <unistd.h> | |
25 | ||
26 | #include "socket-util.h" | |
27 | #include "sset.h" | |
28 | #include "util.h" | |
29 | #include "openvswitch/vlog.h" | |
30 | ||
31 | VLOG_DEFINE_THIS_MODULE(collectors); | |
32 | ||
33 | struct collectors { | |
34 | int *fds; /* Sockets. */ | |
35 | size_t n_fds; /* Number of sockets. */ | |
36 | }; | |
37 | ||
38 | /* Opens the targets specified in 'targets' for sending UDP packets. This is | |
39 | * useful for e.g. sending NetFlow or sFlow packets. Returns 0 if successful, | |
40 | * otherwise a positive errno value if opening at least one collector failed. | |
41 | * | |
42 | * Each target in 'targets' should be a string in the format "<host>[:<port>]". | |
43 | * <port> may be omitted if 'default_port' is nonzero, in which case it | |
44 | * defaults to 'default_port'. | |
45 | * | |
46 | * '*collectorsp' is set to a null pointer if no targets were successfully | |
47 | * added, otherwise to a new collectors object if at least one was successfully | |
48 | * added. Thus, even on a failure return, it is possible that '*collectorsp' | |
49 | * is nonnull, and even on a successful return, it is possible that | |
50 | * '*collectorsp' is null, if 'target's is an empty sset. */ | |
51 | int | |
52 | collectors_create(const struct sset *targets, uint16_t default_port, | |
53 | struct collectors **collectorsp) | |
54 | { | |
55 | struct collectors *c; | |
56 | const char *name; | |
57 | int retval = 0; | |
58 | ||
59 | c = xmalloc(sizeof *c); | |
60 | c->fds = xmalloc(sizeof *c->fds * sset_count(targets)); | |
61 | c->n_fds = 0; | |
62 | SSET_FOR_EACH (name, targets) { | |
63 | int error; | |
64 | int fd; | |
65 | ||
66 | error = inet_open_active(SOCK_DGRAM, name, default_port, NULL, &fd, 0); | |
67 | if (fd >= 0) { | |
68 | c->fds[c->n_fds++] = fd; | |
69 | } else { | |
70 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
71 | ||
72 | VLOG_WARN_RL(&rl, "couldn't open connection to collector %s (%s)", | |
73 | name, ovs_strerror(error)); | |
74 | if (!retval) { | |
75 | retval = error; | |
76 | } | |
77 | } | |
78 | } | |
79 | ||
80 | if (c->n_fds) { | |
81 | *collectorsp = c; | |
82 | } else { | |
83 | collectors_destroy(c); | |
84 | *collectorsp = NULL; | |
85 | } | |
86 | ||
87 | return retval; | |
88 | } | |
89 | ||
90 | /* Destroys 'c'. */ | |
91 | void | |
92 | collectors_destroy(struct collectors *c) | |
93 | { | |
94 | if (c) { | |
95 | size_t i; | |
96 | ||
97 | for (i = 0; i < c->n_fds; i++) { | |
98 | closesocket(c->fds[i]); | |
99 | } | |
100 | free(c->fds); | |
101 | free(c); | |
102 | } | |
103 | } | |
104 | ||
105 | /* Sends the 'n'-byte 'payload' to each of the collectors in 'c'. | |
106 | * Return the number of IPFIX packets which were sent unsuccessfully*/ | |
107 | size_t | |
108 | collectors_send(const struct collectors *c, const void *payload, size_t n) | |
109 | { | |
110 | size_t errors = 0; | |
111 | ||
112 | if (c) { | |
113 | size_t i; | |
114 | ||
115 | for (i = 0; i < c->n_fds; i++) { | |
116 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
117 | if (send(c->fds[i], payload, n, 0) == -1) { | |
118 | char *s = describe_fd(c->fds[i]); | |
119 | VLOG_WARN_RL(&rl, "%s: sending to collector failed (%s)", | |
120 | s, ovs_strerror(errno)); | |
121 | free(s); | |
122 | errors++; | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | return errors; | |
128 | } | |
129 | ||
130 | int | |
131 | collectors_count(const struct collectors *c) | |
132 | { | |
133 | return c ? c->n_fds : 0; | |
134 | } |