~ubuntu-branches/ubuntu/oneiric/libvirt/oneiric-proposed

« back to all changes in this revision

Viewing changes to .pc/lxc-move-virrun-etc-to-util-command.patch/src/util/ebtables.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2011-10-03 14:39:05 UTC
  • mfrom: (128.1.2 libvirt)
  • Revision ID: package-import@ubuntu.com-20111003143905-cj1ottjem8j8nhk2
Tags: 0.9.2-4ubuntu15
Pull patches from upstream which prevent a race between lxc driver and
controller while a container is started, easily exposed by nova.
(LP: #842845)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007-2010 Red Hat, Inc.
 
3
 * Copyright (C) 2009 IBM Corp.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 
18
 *
 
19
 * based on iptables.c
 
20
 * Authors:
 
21
 *     Gerhard Stenzel <gerhard.stenzel@de.ibm.com>
 
22
 */
 
23
 
 
24
#include <config.h>
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <stdarg.h>
 
29
#include <string.h>
 
30
#include <errno.h>
 
31
#include <limits.h>
 
32
#include <unistd.h>
 
33
#include <fcntl.h>
 
34
#include <sys/types.h>
 
35
#include <sys/stat.h>
 
36
#include <sys/wait.h>
 
37
 
 
38
#ifdef HAVE_PATHS_H
 
39
# include <paths.h>
 
40
#endif
 
41
 
 
42
#include "internal.h"
 
43
#include "ebtables.h"
 
44
#include "util.h"
 
45
#include "memory.h"
 
46
#include "virterror_internal.h"
 
47
#include "logging.h"
 
48
 
 
49
struct _ebtablesContext
 
50
{
 
51
    ebtRules *input_filter;
 
52
    ebtRules *forward_filter;
 
53
    ebtRules *nat_postrouting;
 
54
};
 
55
 
 
56
enum {
 
57
    ADD = 0,
 
58
    REMOVE,
 
59
    CREATE,
 
60
    POLICY,
 
61
    INSERT
 
62
};
 
63
 
 
64
static void
 
65
ebtRuleFree(ebtRule *rule)
 
66
{
 
67
    VIR_FREE(rule->rule);
 
68
 
 
69
    if (rule->argv) {
 
70
        int i = 0;
 
71
        while (rule->argv[i])
 
72
            VIR_FREE(rule->argv[i++]);
 
73
        VIR_FREE(rule->argv);
 
74
    }
 
75
}
 
76
 
 
77
static int
 
78
ebtRulesAppend(ebtRules *rules,
 
79
               char *rule,
 
80
               const char **argv,
 
81
               int command_idx)
 
82
{
 
83
    if (VIR_REALLOC_N(rules->rules, rules->nrules+1) < 0) {
 
84
        int i = 0;
 
85
        while (argv[i])
 
86
            VIR_FREE(argv[i++]);
 
87
        VIR_FREE(argv);
 
88
        return ENOMEM;
 
89
    }
 
90
 
 
91
    rules->rules[rules->nrules].rule        = rule;
 
92
    rules->rules[rules->nrules].argv        = argv;
 
93
    rules->rules[rules->nrules].command_idx = command_idx;
 
94
 
 
95
    rules->nrules++;
 
96
 
 
97
    return 0;
 
98
}
 
99
 
 
100
static int
 
101
ebtRulesRemove(ebtRules *rules,
 
102
               char *rule)
 
103
{
 
104
    int i;
 
105
 
 
106
    for (i = 0; i < rules->nrules; i++)
 
107
        if (STREQ(rules->rules[i].rule, rule))
 
108
            break;
 
109
 
 
110
    if (i >= rules->nrules)
 
111
        return EINVAL;
 
112
 
 
113
    ebtRuleFree(&rules->rules[i]);
 
114
 
 
115
    memmove(&rules->rules[i],
 
116
            &rules->rules[i+1],
 
117
            (rules->nrules - i - 1) * sizeof (ebtRule));
 
118
 
 
119
    rules->nrules--;
 
120
 
 
121
    return 0;
 
122
}
 
123
 
 
124
static void
 
125
ebtRulesFree(ebtRules *rules)
 
126
{
 
127
    int i;
 
128
 
 
129
    VIR_FREE(rules->table);
 
130
    VIR_FREE(rules->chain);
 
131
 
 
132
    if (rules->rules) {
 
133
        for (i = 0; i < rules->nrules; i++)
 
134
            ebtRuleFree(&rules->rules[i]);
 
135
 
 
136
        VIR_FREE(rules->rules);
 
137
 
 
138
        rules->nrules = 0;
 
139
    }
 
140
 
 
141
    VIR_FREE(rules);
 
142
}
 
143
 
 
144
static ebtRules *
 
145
ebtRulesNew(const char *table,
 
146
            const char *chain)
 
147
{
 
148
    ebtRules *rules;
 
149
 
 
150
    if (VIR_ALLOC(rules) < 0)
 
151
        return NULL;
 
152
 
 
153
    if (!(rules->table = strdup(table)))
 
154
        goto error;
 
155
 
 
156
    if (!(rules->chain = strdup(chain)))
 
157
        goto error;
 
158
 
 
159
    rules->rules = NULL;
 
160
    rules->nrules = 0;
 
161
 
 
162
    return rules;
 
163
 
 
164
 error:
 
165
    ebtRulesFree(rules);
 
166
    return NULL;
 
167
}
 
168
 
 
169
static int ATTRIBUTE_SENTINEL
 
170
ebtablesAddRemoveRule(ebtRules *rules, int action, const char *arg, ...)
 
171
{
 
172
    va_list args;
 
173
    int retval = ENOMEM;
 
174
    const char **argv;
 
175
    char *rule = NULL;
 
176
    const char *s;
 
177
    int n, command_idx;
 
178
 
 
179
    n = 1 + /* /sbin/ebtables  */
 
180
        2 + /*   --table foo   */
 
181
        2 + /*   --insert bar  */
 
182
        1;  /*   arg           */
 
183
 
 
184
    va_start(args, arg);
 
185
    while (va_arg(args, const char *))
 
186
        n++;
 
187
 
 
188
    va_end(args);
 
189
 
 
190
    if (VIR_ALLOC_N(argv, n + 1) < 0)
 
191
        goto error;
 
192
 
 
193
    n = 0;
 
194
 
 
195
    if (!(argv[n++] = strdup(EBTABLES_PATH)))
 
196
        goto error;
 
197
 
 
198
    command_idx = n;
 
199
 
 
200
    if(action == ADD || action == REMOVE) {
 
201
        if (!(argv[n++] = strdup("--insert")))
 
202
            goto error;
 
203
 
 
204
        if (!(argv[n++] = strdup(rules->chain)))
 
205
            goto error;
 
206
    }
 
207
 
 
208
    if (!(argv[n++] = strdup(arg)))
 
209
        goto error;
 
210
 
 
211
    va_start(args, arg);
 
212
 
 
213
    while ((s = va_arg(args, const char *))) {
 
214
        if (!(argv[n++] = strdup(s))) {
 
215
            va_end(args);
 
216
            goto error;
 
217
        }
 
218
    }
 
219
 
 
220
    va_end(args);
 
221
 
 
222
    if (!(rule = virArgvToString(&argv[command_idx])))
 
223
        goto error;
 
224
 
 
225
    if (action == REMOVE) {
 
226
        VIR_FREE(argv[command_idx]);
 
227
        if (!(argv[command_idx] = strdup("--delete")))
 
228
            goto error;
 
229
    }
 
230
 
 
231
    if (virRun(argv, NULL) < 0) {
 
232
        retval = errno;
 
233
        goto error;
 
234
    }
 
235
 
 
236
    if (action == ADD || action == CREATE || action == POLICY ||
 
237
        action == INSERT) {
 
238
        retval = ebtRulesAppend(rules, rule, argv, command_idx);
 
239
        rule = NULL;
 
240
        argv = NULL;
 
241
    } else {
 
242
        retval = ebtRulesRemove(rules, rule);
 
243
    }
 
244
 
 
245
 error:
 
246
    VIR_FREE(rule);
 
247
 
 
248
    if (argv) {
 
249
        n = 0;
 
250
        while (argv[n])
 
251
            VIR_FREE(argv[n++]);
 
252
        VIR_FREE(argv);
 
253
    }
 
254
 
 
255
    return retval;
 
256
}
 
257
 
 
258
 
 
259
/**
 
260
 * ebtablesContextNew:
 
261
 *
 
262
 * Create a new ebtable context
 
263
 *
 
264
 * Returns a pointer to the new structure or NULL in case of error
 
265
 */
 
266
ebtablesContext *
 
267
ebtablesContextNew(const char *driver)
 
268
{
 
269
    bool success = false;
 
270
    ebtablesContext *ctx = NULL;
 
271
    char *input_chain = NULL;
 
272
    char *forward_chain = NULL;
 
273
    char *nat_chain = NULL;
 
274
 
 
275
    if (VIR_ALLOC(ctx) < 0)
 
276
        return NULL;
 
277
 
 
278
    if (virAsprintf(&input_chain, "libvirt_%s_INPUT", driver) < 0 ||
 
279
        virAsprintf(&forward_chain, "libvirt_%s_FORWARD", driver) < 0 ||
 
280
        virAsprintf(&nat_chain, "libvirt_%s_POSTROUTING", driver) < 0) {
 
281
        goto cleanup;
 
282
    }
 
283
 
 
284
    if (!(ctx->input_filter = ebtRulesNew("filter", input_chain)))
 
285
        goto cleanup;
 
286
 
 
287
    if (!(ctx->forward_filter = ebtRulesNew("filter", forward_chain)))
 
288
        goto cleanup;
 
289
 
 
290
    if (!(ctx->nat_postrouting = ebtRulesNew("nat", nat_chain)))
 
291
        goto cleanup;
 
292
 
 
293
    success = true;
 
294
 
 
295
cleanup:
 
296
    VIR_FREE(input_chain);
 
297
    VIR_FREE(forward_chain);
 
298
    VIR_FREE(nat_chain);
 
299
 
 
300
    if (!success) {
 
301
        ebtablesContextFree(ctx);
 
302
        ctx = NULL;
 
303
    }
 
304
 
 
305
    return ctx;
 
306
}
 
307
 
 
308
/**
 
309
 * ebtablesContextFree:
 
310
 * @ctx: pointer to the EB table context
 
311
 *
 
312
 * Free the resources associated with an EB table context
 
313
 */
 
314
void
 
315
ebtablesContextFree(ebtablesContext *ctx)
 
316
{
 
317
    if (!ctx)
 
318
        return;
 
319
    if (ctx->input_filter)
 
320
        ebtRulesFree(ctx->input_filter);
 
321
    if (ctx->forward_filter)
 
322
        ebtRulesFree(ctx->forward_filter);
 
323
    if (ctx->nat_postrouting)
 
324
        ebtRulesFree(ctx->nat_postrouting);
 
325
    VIR_FREE(ctx);
 
326
}
 
327
 
 
328
int
 
329
ebtablesAddForwardPolicyReject(ebtablesContext *ctx)
 
330
{
 
331
    return ebtablesForwardPolicyReject(ctx, ADD);
 
332
}
 
333
 
 
334
 
 
335
int
 
336
ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx)
 
337
{
 
338
    return ebtablesForwardPolicyReject(ctx, REMOVE);
 
339
}
 
340
 
 
341
int
 
342
ebtablesForwardPolicyReject(ebtablesContext *ctx,
 
343
                            int action)
 
344
{
 
345
    /* create it, if it does not exist */
 
346
    if (action == ADD) {
 
347
        ebtablesAddRemoveRule(ctx->forward_filter,
 
348
                              CREATE,
 
349
                              "--new-chain", ctx->forward_filter->chain, NULL,
 
350
                              NULL);
 
351
        ebtablesAddRemoveRule(ctx->forward_filter,
 
352
                              INSERT,
 
353
                              "--insert", "FORWARD", "--jump",
 
354
                              ctx->forward_filter->chain, NULL);
 
355
    }
 
356
 
 
357
    return ebtablesAddRemoveRule(ctx->forward_filter,
 
358
                                 POLICY,
 
359
                                 "-P", ctx->forward_filter->chain, "DROP",
 
360
                                 NULL);
 
361
}
 
362
 
 
363
/*
 
364
 * Allow all traffic destined to the bridge, with a valid network address
 
365
 */
 
366
static int
 
367
ebtablesForwardAllowIn(ebtablesContext *ctx,
 
368
                       const char *iface,
 
369
                       const char *macaddr,
 
370
                       int action)
 
371
{
 
372
    return ebtablesAddRemoveRule(ctx->forward_filter,
 
373
                                     action,
 
374
                                     "--in-interface", iface,
 
375
                                     "--source", macaddr,
 
376
                                     "--jump", "ACCEPT",
 
377
                                     NULL);
 
378
}
 
379
 
 
380
/**
 
381
 * ebtablesAddForwardAllowIn:
 
382
 * @ctx: pointer to the EB table context
 
383
 * @iface: the output interface name
 
384
 * @physdev: the physical input device or NULL
 
385
 *
 
386
 * Add rules to the EB table context to allow the traffic on
 
387
 * @physdev device to be forwarded to interface @iface. This allows
 
388
 * the inbound traffic on a bridge.
 
389
 *
 
390
 * Returns 0 in case of success or an error code otherwise
 
391
 */
 
392
int
 
393
ebtablesAddForwardAllowIn(ebtablesContext *ctx,
 
394
                          const char *iface,
 
395
                          const unsigned char *mac)
 
396
{
 
397
    char *macaddr;
 
398
 
 
399
    if (virAsprintf(&macaddr,
 
400
                    "%02x:%02x:%02x:%02x:%02x:%02x",
 
401
                    mac[0], mac[1],
 
402
                    mac[2], mac[3],
 
403
                    mac[4], mac[5]) < 0) {
 
404
        return -1;
 
405
    }
 
406
    return ebtablesForwardAllowIn(ctx, iface, macaddr, ADD);
 
407
}
 
408
 
 
409
/**
 
410
 * ebtablesRemoveForwardAllowIn:
 
411
 * @ctx: pointer to the EB table context
 
412
 * @iface: the output interface name
 
413
 * @physdev: the physical input device or NULL
 
414
 *
 
415
 * Remove rules from the EB table context hence forbidding the traffic
 
416
 * on the @physdev device to be forwarded to interface @iface. This
 
417
 * stops the inbound traffic on a bridge.
 
418
 *
 
419
 * Returns 0 in case of success or an error code otherwise
 
420
 */
 
421
int
 
422
ebtablesRemoveForwardAllowIn(ebtablesContext *ctx,
 
423
                             const char *iface,
 
424
                             const unsigned char *mac)
 
425
{
 
426
    char *macaddr;
 
427
 
 
428
    if (virAsprintf(&macaddr,
 
429
                    "%02x:%02x:%02x:%02x:%02x:%02x",
 
430
                    mac[0], mac[1],
 
431
                    mac[2], mac[3],
 
432
                    mac[4], mac[5]) < 0) {
 
433
       return -1;
 
434
    }
 
435
    return ebtablesForwardAllowIn(ctx, iface, macaddr, REMOVE);
 
436
}