~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to lib/learn.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (c) 2011, 2012 Nicira, Inc.
 
2
 * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
3
3
 *
4
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
5
 * you may not use this file except in compliance with the License.
303
303
    fm->cookie = htonll(0);
304
304
    fm->cookie_mask = htonll(0);
305
305
    fm->new_cookie = htonll(learn->cookie);
 
306
    fm->modify_cookie = fm->new_cookie != htonll(UINT64_MAX);
306
307
    fm->table_id = learn->table_id;
307
308
    fm->command = OFPFC_MODIFY_STRICT;
308
309
    fm->idle_timeout = learn->idle_timeout;
355
356
        case NX_LEARN_DST_OUTPUT:
356
357
            if (spec->n_bits <= 16
357
358
                || is_all_zeros(value.u8, sizeof value - 2)) {
358
 
                uint16_t port = ntohs(value.be16[7]);
 
359
                ofp_port_t port = u16_to_ofp(ntohs(value.be16[7]));
359
360
 
360
 
                if (port < OFPP_MAX
 
361
                if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX)
361
362
                    || port == OFPP_IN_PORT
362
363
                    || port == OFPP_FLOOD
363
364
                    || port == OFPP_LOCAL
374
375
    fm->ofpacts_len = ofpacts->size;
375
376
}
376
377
 
377
 
static void
 
378
/* Perform a bitwise-OR on 'wc''s fields that are relevant as sources in
 
379
 * the learn action 'learn'. */
 
380
void
 
381
learn_mask(const struct ofpact_learn *learn, struct flow_wildcards *wc)
 
382
{
 
383
    const struct ofpact_learn_spec *spec;
 
384
    union mf_subvalue value;
 
385
 
 
386
    memset(&value, 0xff, sizeof value);
 
387
    for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) {
 
388
        if (spec->src_type == NX_LEARN_SRC_FIELD) {
 
389
            mf_write_subfield_flow(&spec->src, &value, &wc->masks);
 
390
        }
 
391
    }
 
392
}
 
393
 
 
394
/* Returns NULL if successful, otherwise a malloc()'d string describing the
 
395
 * error.  The caller is responsible for freeing the returned string. */
 
396
static char * WARN_UNUSED_RESULT
378
397
learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
379
398
{
380
399
    const char *full_s = s;
381
400
    const char *arrow = strstr(s, "->");
382
401
    struct mf_subfield dst;
383
402
    union mf_subvalue imm;
 
403
    char *error;
384
404
 
385
405
    memset(&imm, 0, sizeof imm);
386
406
    if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && arrow) {
392
412
        for (i = 0; i < n; i++) {
393
413
            int hexit = hexit_value(in[-i]);
394
414
            if (hexit < 0) {
395
 
                ovs_fatal(0, "%s: bad hex digit in value", full_s);
 
415
                return xasprintf("%s: bad hex digit in value", full_s);
396
416
            }
397
417
            out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit;
398
418
        }
402
422
    }
403
423
 
404
424
    if (strncmp(s, "->", 2)) {
405
 
        ovs_fatal(0, "%s: missing `->' following value", full_s);
 
425
        return xasprintf("%s: missing `->' following value", full_s);
406
426
    }
407
427
    s += 2;
408
428
 
409
 
    s = mf_parse_subfield(&dst, s);
410
 
    if (*s != '\0') {
411
 
        ovs_fatal(0, "%s: trailing garbage following destination", full_s);
 
429
    error = mf_parse_subfield(&dst, s);
 
430
    if (error) {
 
431
        return error;
412
432
    }
413
433
 
414
434
    if (!bitwise_is_all_zeros(&imm, sizeof imm, dst.n_bits,
415
435
                              (8 * sizeof imm) - dst.n_bits)) {
416
 
        ovs_fatal(0, "%s: value does not fit into %u bits",
417
 
                  full_s, dst.n_bits);
 
436
        return xasprintf("%s: value does not fit into %u bits",
 
437
                         full_s, dst.n_bits);
418
438
    }
419
439
 
420
440
    spec->n_bits = dst.n_bits;
422
442
    spec->src_imm = imm;
423
443
    spec->dst_type = NX_LEARN_DST_LOAD;
424
444
    spec->dst = dst;
 
445
    return NULL;
425
446
}
426
447
 
427
 
static void
 
448
/* Returns NULL if successful, otherwise a malloc()'d string describing the
 
449
 * error.  The caller is responsible for freeing the returned string. */
 
450
static char * WARN_UNUSED_RESULT
428
451
learn_parse_spec(const char *orig, char *name, char *value,
429
452
                 struct ofpact_learn_spec *spec)
430
453
{
435
458
 
436
459
        error = mf_parse_value(dst, value, &imm);
437
460
        if (error) {
438
 
            ovs_fatal(0, "%s", error);
 
461
            return error;
439
462
        }
440
463
 
441
464
        spec->n_bits = dst->n_bits;
449
472
        spec->dst.n_bits = dst->n_bits;
450
473
    } else if (strchr(name, '[')) {
451
474
        /* Parse destination and check prerequisites. */
452
 
        if (mf_parse_subfield(&spec->dst, name)[0] != '\0') {
453
 
            ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
454
 
                      orig, name);
 
475
        char *error;
 
476
 
 
477
        error = mf_parse_subfield(&spec->dst, name);
 
478
        if (error) {
 
479
            return error;
455
480
        }
456
481
 
457
482
        /* Parse source and check prerequisites. */
458
483
        if (value[0] != '\0') {
459
 
            if (mf_parse_subfield(&spec->src, value)[0] != '\0') {
460
 
                ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
461
 
                          orig, value);
 
484
            error = mf_parse_subfield(&spec->src, value);
 
485
            if (error) {
 
486
                return error;
462
487
            }
463
488
            if (spec->src.n_bits != spec->dst.n_bits) {
464
 
                ovs_fatal(0, "%s: bit widths of %s (%u) and %s (%u) differ",
465
 
                          orig, name, spec->src.n_bits, value,
466
 
                          spec->dst.n_bits);
 
489
                return xasprintf("%s: bit widths of %s (%u) and %s (%u) "
 
490
                                 "differ", orig, name, spec->src.n_bits, value,
 
491
                                 spec->dst.n_bits);
467
492
            }
468
493
        } else {
469
494
            spec->src = spec->dst;
474
499
        spec->dst_type = NX_LEARN_DST_MATCH;
475
500
    } else if (!strcmp(name, "load")) {
476
501
        if (value[strcspn(value, "[-")] == '-') {
477
 
            learn_parse_load_immediate(value, spec);
 
502
            char *error = learn_parse_load_immediate(value, spec);
 
503
            if (error) {
 
504
                return error;
 
505
            }
478
506
        } else {
479
507
            struct ofpact_reg_move move;
 
508
            char *error;
480
509
 
481
 
            nxm_parse_reg_move(&move, value);
 
510
            error = nxm_parse_reg_move(&move, value);
 
511
            if (error) {
 
512
                return error;
 
513
            }
482
514
 
483
515
            spec->n_bits = move.src.n_bits;
484
516
            spec->src_type = NX_LEARN_SRC_FIELD;
487
519
            spec->dst = move.dst;
488
520
        }
489
521
    } else if (!strcmp(name, "output")) {
490
 
        if (mf_parse_subfield(&spec->src, value)[0] != '\0') {
491
 
            ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
492
 
                      orig, name);
 
522
        char *error = mf_parse_subfield(&spec->src, value);
 
523
        if (error) {
 
524
            return error;
493
525
        }
494
526
 
495
527
        spec->n_bits = spec->src.n_bits;
496
528
        spec->src_type = NX_LEARN_SRC_FIELD;
497
529
        spec->dst_type = NX_LEARN_DST_OUTPUT;
498
530
    } else {
499
 
        ovs_fatal(0, "%s: unknown keyword %s", orig, name);
 
531
        return xasprintf("%s: unknown keyword %s", orig, name);
500
532
    }
 
533
 
 
534
    return NULL;
501
535
}
502
536
 
503
 
/* Parses 'arg' as a set of arguments to the "learn" action and appends a
504
 
 * matching OFPACT_LEARN action to 'ofpacts'.  ovs-ofctl(8) describes the
505
 
 * format parsed.
506
 
 *
507
 
 * Prints an error on stderr and aborts the program if 'arg' syntax is invalid.
508
 
 *
509
 
 * If 'flow' is nonnull, then it should be the flow from a struct match that is
510
 
 * the matching rule for the learning action.  This helps to better validate
511
 
 * the action's arguments.
512
 
 *
513
 
 * Modifies 'arg'. */
514
 
void
515
 
learn_parse(char *arg, const struct flow *flow, struct ofpbuf *ofpacts)
 
537
/* Returns NULL if successful, otherwise a malloc()'d string describing the
 
538
 * error.  The caller is responsible for freeing the returned string. */
 
539
static char * WARN_UNUSED_RESULT
 
540
learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts)
516
541
{
517
 
    char *orig = xstrdup(arg);
 
542
    struct ofpact_learn *learn;
 
543
    struct match match;
518
544
    char *name, *value;
519
545
 
520
 
    struct ofpact_learn *learn;
521
 
    struct match match;
522
 
    enum ofperr error;
523
 
 
524
546
    learn = ofpact_put_LEARN(ofpacts);
525
547
    learn->idle_timeout = OFP_FLOW_PERMANENT;
526
548
    learn->hard_timeout = OFP_FLOW_PERMANENT;
532
554
        if (!strcmp(name, "table")) {
533
555
            learn->table_id = atoi(value);
534
556
            if (learn->table_id == 255) {
535
 
                ovs_fatal(0, "%s: table id 255 not valid for `learn' action",
536
 
                          orig);
 
557
                return xasprintf("%s: table id 255 not valid for `learn' "
 
558
                                 "action", orig);
537
559
            }
538
560
        } else if (!strcmp(name, "priority")) {
539
561
            learn->priority = atoi(value);
549
571
            learn->cookie = strtoull(value, NULL, 0);
550
572
        } else {
551
573
            struct ofpact_learn_spec *spec;
 
574
            char *error;
552
575
 
553
576
            spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
554
577
            learn = ofpacts->l2;
555
578
            learn->n_specs++;
556
579
 
557
 
            learn_parse_spec(orig, name, value, spec);
558
 
 
559
 
            /* Check prerequisites. */
560
 
            if (spec->src_type == NX_LEARN_SRC_FIELD
561
 
                && flow && !mf_are_prereqs_ok(spec->src.field, flow)) {
562
 
                ovs_fatal(0, "%s: cannot specify source field %s because "
563
 
                          "prerequisites are not satisfied",
564
 
                          orig, spec->src.field->name);
565
 
            }
566
 
            if ((spec->dst_type == NX_LEARN_DST_MATCH
567
 
                 || spec->dst_type == NX_LEARN_DST_LOAD)
568
 
                && !mf_are_prereqs_ok(spec->dst.field, &match.flow)) {
569
 
                ovs_fatal(0, "%s: cannot specify destination field %s because "
570
 
                          "prerequisites are not satisfied",
571
 
                          orig, spec->dst.field->name);
 
580
            error = learn_parse_spec(orig, name, value, spec);
 
581
            if (error) {
 
582
                return error;
572
583
            }
573
584
 
574
585
            /* Update 'match' to allow for satisfying destination
581
592
    }
582
593
    ofpact_update_len(ofpacts, &learn->ofpact);
583
594
 
584
 
    /* In theory the above should have caught any errors, but... */
585
 
    if (flow) {
586
 
        error = learn_check(learn, flow);
587
 
        if (error) {
588
 
            ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error));
589
 
        }
590
 
    }
 
595
    return NULL;
 
596
}
 
597
 
 
598
/* Parses 'arg' as a set of arguments to the "learn" action and appends a
 
599
 * matching OFPACT_LEARN action to 'ofpacts'.  ovs-ofctl(8) describes the
 
600
 * format parsed.
 
601
 *
 
602
 * Returns NULL if successful, otherwise a malloc()'d string describing the
 
603
 * error.  The caller is responsible for freeing the returned string.
 
604
 *
 
605
 * If 'flow' is nonnull, then it should be the flow from a struct match that is
 
606
 * the matching rule for the learning action.  This helps to better validate
 
607
 * the action's arguments.
 
608
 *
 
609
 * Modifies 'arg'. */
 
610
char * WARN_UNUSED_RESULT
 
611
learn_parse(char *arg, struct ofpbuf *ofpacts)
 
612
{
 
613
    char *orig = xstrdup(arg);
 
614
    char *error = learn_parse__(orig, arg, ofpacts);
591
615
    free(orig);
 
616
    return error;
592
617
}
593
618
 
594
619
/* Appends a description of 'learn' to 's', in the format that ovs-ofctl(8)