For SNAT, don't store the pre-fragment L2 header before actions are applied.
[sliver-openvswitch.git] / lib / timeval.c
1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
2  * Junior University
3  *
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  *
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 #include <config.h>
35 #include "timeval.h"
36 #include <assert.h>
37 #include <errno.h>
38 #include <poll.h>
39 #include <signal.h>
40 #include <string.h>
41 #include <sys/time.h>
42 #include "fatal-signal.h"
43 #include "util.h"
44
45 /* Initialized? */
46 static bool inited;
47
48 /* Has a timer tick occurred? */
49 static volatile sig_atomic_t tick;
50
51 /* The current time, as of the last refresh. */
52 static struct timeval now;
53
54 /* Time at which to die with SIGALRM (if not TIME_MIN). */
55 static time_t deadline = TIME_MIN;
56
57 static void sigalrm_handler(int);
58 static void refresh_if_ticked(void);
59 static time_t time_add(time_t, time_t);
60 static void block_sigalrm(sigset_t *);
61 static void unblock_sigalrm(const sigset_t *);
62
63 /* Initializes the timetracking module. */
64 void
65 time_init(void)
66 {
67     struct sigaction sa;
68     struct itimerval itimer;
69
70     if (inited) {
71         return;
72     }
73
74     inited = true;
75     gettimeofday(&now, NULL);
76     tick = false;
77
78     /* Set up signal handler. */
79     memset(&sa, 0, sizeof sa);
80     sa.sa_handler = sigalrm_handler;
81     sigemptyset(&sa.sa_mask);
82     sa.sa_flags = SA_RESTART;
83     if (sigaction(SIGALRM, &sa, NULL)) {
84         ofp_fatal(errno, "sigaction(SIGALRM) failed");
85     }
86
87     /* Set up periodic timer. */
88     itimer.it_interval.tv_sec = 0;
89     itimer.it_interval.tv_usec = TIME_UPDATE_INTERVAL * 1000;
90     itimer.it_value = itimer.it_interval;
91     if (setitimer(ITIMER_REAL, &itimer, NULL)) {
92         ofp_fatal(errno, "setitimer failed");
93     }
94 }
95
96 /* Forces a refresh of the current time from the kernel.  It is not usually
97  * necessary to call this function, since the time will be refreshed
98  * automatically at least every TIME_UPDATE_INTERVAL milliseconds. */
99 void
100 time_refresh(void)
101 {
102     gettimeofday(&now, NULL);
103     tick = false;
104 }
105
106 /* Returns the current time, in seconds. */
107 time_t
108 time_now(void)
109 {
110     refresh_if_ticked();
111     return now.tv_sec;
112 }
113
114 /* Returns the current time, in ms (within TIME_UPDATE_INTERVAL ms). */
115 long long int
116 time_msec(void)
117 {
118     refresh_if_ticked();
119     return (long long int) now.tv_sec * 1000 + now.tv_usec / 1000;
120 }
121
122 /* Configures the program to die with SIGALRM 'secs' seconds from now, if
123  * 'secs' is nonzero, or disables the feature if 'secs' is zero. */
124 void
125 time_alarm(unsigned int secs)
126 {
127     sigset_t oldsigs;
128
129     time_init();
130     block_sigalrm(&oldsigs);
131     deadline = secs ? time_add(time_now(), secs) : TIME_MIN;
132     unblock_sigalrm(&oldsigs);
133 }
134
135 /* Like poll(), except:
136  *
137  *      - On error, returns a negative error code (instead of setting errno).
138  *
139  *      - If interrupted by a signal, retries automatically until the original
140  *        'timeout' expires.  (Because of this property, this function will
141  *        never return -EINTR.)
142  *
143  *      - As a side effect, refreshes the current time (like time_refresh()).
144  */
145 int
146 time_poll(struct pollfd *pollfds, int n_pollfds, int timeout)
147 {
148     long long int start;
149     sigset_t oldsigs;
150     bool blocked;
151     int retval;
152
153     time_refresh();
154     start = time_msec();
155     blocked = false;
156     for (;;) {
157         int time_left;
158         if (timeout > 0) {
159             long long int elapsed = time_msec() - start;
160             time_left = timeout >= elapsed ? timeout - elapsed : 0;
161         } else {
162             time_left = timeout;
163         }
164
165         retval = poll(pollfds, n_pollfds, time_left);
166         if (retval < 0) {
167             retval = -errno;
168         }
169         if (retval != -EINTR) {
170             break;
171         }
172
173         if (!blocked && deadline == TIME_MIN) {
174             block_sigalrm(&oldsigs);
175             blocked = true;
176         }
177         time_refresh();
178     }
179     if (blocked) {
180         unblock_sigalrm(&oldsigs);
181     }
182     return retval;
183 }
184
185 /* Returns the sum of 'a' and 'b', with saturation on overflow or underflow. */
186 static time_t
187 time_add(time_t a, time_t b)
188 {
189     return (a >= 0
190             ? (b > TIME_MAX - a ? TIME_MAX : a + b)
191             : (b < TIME_MIN - a ? TIME_MIN : a + b));
192 }
193
194 static void
195 sigalrm_handler(int sig_nr)
196 {
197     tick = true;
198     if (deadline != TIME_MIN && time(0) > deadline) {
199         fatal_signal_handler(sig_nr);
200     }
201 }
202
203 static void
204 refresh_if_ticked(void)
205 {
206     assert(inited);
207     if (tick) {
208         time_refresh();
209     }
210 }
211
212 static void
213 block_sigalrm(sigset_t *oldsigs)
214 {
215     sigset_t sigalrm;
216     sigemptyset(&sigalrm);
217     sigaddset(&sigalrm, SIGALRM);
218     if (sigprocmask(SIG_BLOCK, &sigalrm, oldsigs)) {
219         ofp_fatal(errno, "sigprocmask");
220     }
221 }
222
223 static void
224 unblock_sigalrm(const sigset_t *oldsigs)
225 {
226     if (sigprocmask(SIG_SETMASK, oldsigs, NULL)) {
227         ofp_fatal(errno, "sigprocmask");
228     }
229 }