From patchwork Sat Oct 10 04:15:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 528521 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (li376-54.members.linode.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id A5DD9140E3D for ; Sat, 10 Oct 2015 15:15:57 +1100 (AEDT) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id E766E10AD6; Fri, 9 Oct 2015 21:15:53 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v1.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 3A30110AD1 for ; Fri, 9 Oct 2015 21:15:52 -0700 (PDT) Received: from bar3.cudamail.com (bar1 [192.168.15.1]) by mx3v1.cudamail.com (Postfix) with ESMTP id B8C9F6195F1 for ; Fri, 9 Oct 2015 22:15:51 -0600 (MDT) X-ASG-Debug-ID: 1444450551-03dd7b7d3d115650001-byXFYA Received: from mx3-pf1.cudamail.com ([192.168.14.2]) by bar3.cudamail.com with ESMTP id 6pGFHQrlQ79zS4uu (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 09 Oct 2015 22:15:51 -0600 (MDT) X-Barracuda-Envelope-From: blp@nicira.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.2 Received: from unknown (HELO mail-pa0-f52.google.com) (209.85.220.52) by mx3-pf1.cudamail.com with ESMTPS (RC4-SHA encrypted); 10 Oct 2015 04:15:50 -0000 Received-SPF: unknown (mx3-pf1.cudamail.com: Multiple SPF records returned) X-Barracuda-RBL-Trusted-Forwarder: 209.85.220.52 Received: by pablk4 with SMTP id lk4so103943653pab.3 for ; Fri, 09 Oct 2015 21:15:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Omk0o35np2DEdTJtBacHpTR5fhRpkUXdo1FYfmr0UE8=; b=IrWp9l6R/YQSZXKXphHYHJPvB7dcL56UHEDvRFhaqFJm4883MHEkW8+/W1Nxr1RjDo hdGNTjjFDK/wzpnF1Mnsdil405ZWkIUl6UVtAlbeCBZacjZz77nwYWJMrSsvO/22C+uk t1OT75G4PPTAd7IoOLmoWC8Y3Q3gHmOZ53KcaywMWiSFije/FpP+xGbbIk3UyQttal3X Qpvo1v9ryn8z6Nfobq2EDOeFXnGu8hvxz1Od5SbmlRTL0T1f2FdjIRw88WXkZSvY3Dy/ QOq+5DEffpPU+5WZSVDz9+uxFc6ga4f/rIsUE4O30jLaq5KEJdOi67CG2Q47hbXWfnW2 nxpA== X-Gm-Message-State: ALoCoQm74eU/sY4+Ceetlop8gNX+DevLnZ4qu1ZoXb6P9V0Xvo+vxSGU2GUQRy6yHpWCKqg6dhXH X-Received: by 10.68.249.66 with SMTP id ys2mr19917563pbc.82.1444450550201; Fri, 09 Oct 2015 21:15:50 -0700 (PDT) Received: from sigabrt.gateway.sonic.net (173-228-112-112.dsl.dynamic.fusionbroadband.com. [173.228.112.112]) by smtp.gmail.com with ESMTPSA id bk8sm5386937pad.18.2015.10.09.21.15.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Oct 2015 21:15:48 -0700 (PDT) X-CudaMail-Envelope-Sender: blp@nicira.com X-Barracuda-Apparent-Source-IP: 173.228.112.112 From: Ben Pfaff To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V1-1008077594 X-CudaMail-DTE: 100915 X-CudaMail-Originating-IP: 209.85.220.52 Date: Fri, 9 Oct 2015 21:15:22 -0700 X-ASG-Orig-Subj: [##CM-V1-1008077594##][PATCH 01/23] ovn: Extend logical "next" action to jump to arbitrary flow tables. Message-Id: <1444450544-11845-2-git-send-email-blp@nicira.com> X-Mailer: git-send-email 2.1.3 In-Reply-To: <1444450544-11845-1-git-send-email-blp@nicira.com> References: <1444450544-11845-1-git-send-email-blp@nicira.com> X-Barracuda-Connect: UNKNOWN[192.168.14.2] X-Barracuda-Start-Time: 1444450551 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH 01/23] ovn: Extend logical "next" action to jump to arbitrary flow tables. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" This makes it easier to route a "destination unreachable" message generated because of an IP routing failure, because the destination unreachable message must itself be routed the same way. Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- ovn/controller/lflow.c | 15 +++++---- ovn/lib/actions.c | 88 +++++++++++++++++++++++++++++++++++++++----------- ovn/lib/actions.h | 10 +++--- ovn/lib/expr.c | 11 ++----- ovn/lib/lex.c | 21 ++++++++++++ ovn/lib/lex.h | 2 ++ ovn/ovn-sb.xml | 5 ++- tests/ovn.at | 10 ++++-- tests/test-ovn.c | 4 +-- 9 files changed, 123 insertions(+), 43 deletions(-) diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c index 9246e61..2b1984a 100644 --- a/ovn/controller/lflow.c +++ b/ovn/controller/lflow.c @@ -264,16 +264,16 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table) continue; } - /* Translate logical table ID to physical table ID. */ + /* Determine translation of logical table IDs to physical table IDs. */ bool ingress = !strcmp(lflow->pipeline, "ingress"); - uint8_t phys_table = lflow->table_id + (ingress - ? OFTABLE_LOG_INGRESS_PIPELINE - : OFTABLE_LOG_EGRESS_PIPELINE); - uint8_t next_phys_table - = lflow->table_id + 1 < LOG_PIPELINE_LEN ? phys_table + 1 : 0; + uint8_t first_table = (ingress + ? OFTABLE_LOG_INGRESS_PIPELINE + : OFTABLE_LOG_EGRESS_PIPELINE); + uint8_t phys_table = first_table + lflow->table_id; uint8_t output_phys_table = (ingress ? OFTABLE_REMOTE_OUTPUT : OFTABLE_LOG_TO_PHY); + /* Translate OVN actions into OpenFlow actions. * * XXX Deny changes to 'outport' in egress pipeline. */ @@ -284,7 +284,8 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table) ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); error = actions_parse_string(lflow->actions, &symtab, &ldp->ports, - next_phys_table, output_phys_table, + first_table, LOG_PIPELINE_LEN, + lflow->table_id, output_phys_table, &ofpacts, &prereqs); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 4170fc5..2bc495c 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -30,8 +30,10 @@ struct action_context { /* Input. */ struct lexer *lexer; /* Lexer for pulling more tokens. */ const struct shash *symtab; /* Symbol table. */ - uint8_t next_table_id; /* OpenFlow table for 'next' to resubmit. */ - uint8_t output_table_id; /* OpenFlow table for 'output' to resubmit. */ + uint8_t first_table; /* First OpenFlow table. */ + uint8_t n_tables; /* Number of OpenFlow tables. */ + uint8_t cur_table; /* 0 <= cur_table < n_tables. */ + uint8_t output_table; /* OpenFlow table for 'output' to resubmit. */ const struct simap *ports; /* Map from port name to number. */ /* State. */ @@ -131,6 +133,48 @@ emit_resubmit(struct action_context *ctx, uint8_t table_id) resubmit->table_id = table_id; } +static bool +action_get_int(struct action_context *ctx, int *value) +{ + bool ok = lexer_get_int(ctx->lexer, value); + if (!ok) { + action_syntax_error(ctx, "expecting small integer"); + } + return ok; +} + +static void +parse_next_action(struct action_context *ctx) +{ + if (!ctx->n_tables) { + action_error(ctx, "\"next\" action not allowed here."); + } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { + int table; + + if (!action_get_int(ctx, &table)) { + return; + } + if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { + action_syntax_error(ctx, "expecting `)'"); + return; + } + + if (table >= ctx->n_tables) { + action_error(ctx, "\"next\" argument must be in range 0 to %d.", + ctx->n_tables - 1); + return; + } + + emit_resubmit(ctx, ctx->first_table + table); + } else { + if (ctx->cur_table < ctx->n_tables) { + emit_resubmit(ctx, ctx->first_table + ctx->cur_table + 1); + } else { + action_error(ctx, "\"next\" action not allowed in last table."); + } + } +} + static void parse_actions(struct action_context *ctx) { @@ -158,13 +202,9 @@ parse_actions(struct action_context *ctx) || lookahead == LEX_T_LSQUARE) { parse_set_action(ctx); } else if (lexer_match_id(ctx->lexer, "next")) { - if (ctx->next_table_id) { - emit_resubmit(ctx, ctx->next_table_id); - } else { - action_error(ctx, "\"next\" action not allowed here."); - } + parse_next_action(ctx); } else if (lexer_match_id(ctx->lexer, "output")) { - emit_resubmit(ctx, ctx->output_table_id); + emit_resubmit(ctx, ctx->output_table); } else { action_syntax_error(ctx, "expecting action"); } @@ -188,10 +228,16 @@ parse_actions(struct action_context *ctx) * (as one would provide to expr_to_matches()). Strings used in the actions * that are not in 'ports' are translated to zero. * - * 'next_table_id' should be the OpenFlow table to which the "next" action will - * resubmit, or 0 to disable "next". + * 'first_table' and 'n_tables' define the range of OpenFlow tables that the + * logical "next" action should be able to jump to. Logical table 0 maps to + * OpenFlow table 'first_table', logical table 1 to 'first_table + 1', and so + * on. If 'n_tables' is 0 then "next" is disallowed entirely. + * + * 'cur_table' is an offset from 'first_table' (e.g. 0 <= cur_table < n_tables) + * of the logical flow that contains the actions. If cur_table + 1 < n_tables, + * then this defines the default table that "next" will jump to. * - * 'output_table_id' should be the OpenFlow table to which the "output" action + * 'output_table' should be the OpenFlow table to which the "output" action * will resubmit * * Some actions add extra requirements (prerequisites) to the flow's match. If @@ -206,8 +252,9 @@ parse_actions(struct action_context *ctx) */ char * OVS_WARN_UNUSED_RESULT actions_parse(struct lexer *lexer, const struct shash *symtab, - const struct simap *ports, uint8_t next_table_id, - uint8_t output_table_id, struct ofpbuf *ofpacts, + const struct simap *ports, + uint8_t first_table, uint8_t n_tables, uint8_t cur_table, + uint8_t output_table, struct ofpbuf *ofpacts, struct expr **prereqsp) { size_t ofpacts_start = ofpacts->size; @@ -216,8 +263,10 @@ actions_parse(struct lexer *lexer, const struct shash *symtab, ctx.lexer = lexer; ctx.symtab = symtab; ctx.ports = ports; - ctx.next_table_id = next_table_id; - ctx.output_table_id = output_table_id; + ctx.first_table = first_table; + ctx.n_tables = n_tables; + ctx.cur_table = cur_table; + ctx.output_table = output_table; ctx.error = NULL; ctx.ofpacts = ofpacts; ctx.prereqs = NULL; @@ -238,8 +287,9 @@ actions_parse(struct lexer *lexer, const struct shash *symtab, /* Like actions_parse(), but the actions are taken from 's'. */ char * OVS_WARN_UNUSED_RESULT actions_parse_string(const char *s, const struct shash *symtab, - const struct simap *ports, uint8_t next_table_id, - uint8_t output_table_id, struct ofpbuf *ofpacts, + const struct simap *ports, uint8_t first_table, + uint8_t n_tables, uint8_t cur_table, + uint8_t output_table, struct ofpbuf *ofpacts, struct expr **prereqsp) { struct lexer lexer; @@ -247,8 +297,8 @@ actions_parse_string(const char *s, const struct shash *symtab, lexer_init(&lexer, s); lexer_get(&lexer); - error = actions_parse(&lexer, symtab, ports, next_table_id, - output_table_id, ofpacts, prereqsp); + error = actions_parse(&lexer, symtab, ports, first_table, n_tables, + cur_table, output_table, ofpacts, prereqsp); lexer_destroy(&lexer); return error; diff --git a/ovn/lib/actions.h b/ovn/lib/actions.h index 74cd185..ae897d6 100644 --- a/ovn/lib/actions.h +++ b/ovn/lib/actions.h @@ -27,13 +27,15 @@ struct shash; struct simap; char *actions_parse(struct lexer *, const struct shash *symtab, - const struct simap *ports, uint8_t next_table_id, - uint8_t output_table_id, struct ofpbuf *ofpacts, + const struct simap *ports, uint8_t first_table, + uint8_t n_tables, uint8_t cur_table, + uint8_t output_table, struct ofpbuf *ofpacts, struct expr **prereqsp) OVS_WARN_UNUSED_RESULT; char *actions_parse_string(const char *s, const struct shash *symtab, - const struct simap *ports, uint8_t next_table_id, - uint8_t output_table_id, struct ofpbuf *ofpacts, + const struct simap *ports, uint8_t first_table, + uint8_t n_tables, uint8_t cur_table, + uint8_t output_table, struct ofpbuf *ofpacts, struct expr **prereqsp) OVS_WARN_UNUSED_RESULT; diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c index 8270b82..6fbe3e2 100644 --- a/ovn/lib/expr.c +++ b/ovn/lib/expr.c @@ -668,16 +668,11 @@ exit: static bool expr_get_int(struct expr_context *ctx, int *value) { - if (ctx->lexer->token.type == LEX_T_INTEGER - && ctx->lexer->token.format == LEX_F_DECIMAL - && ntohll(ctx->lexer->token.value.integer) <= INT_MAX) { - *value = ntohll(ctx->lexer->token.value.integer); - lexer_get(ctx->lexer); - return true; - } else { + bool ok = lexer_get_int(ctx->lexer, value); + if (!ok) { expr_syntax_error(ctx, "expecting small integer."); - return false; } + return ok; } static bool diff --git a/ovn/lib/lex.c b/ovn/lib/lex.c index 2ffcfb9..308d216 100644 --- a/ovn/lib/lex.c +++ b/ovn/lib/lex.c @@ -750,3 +750,24 @@ lexer_match_id(struct lexer *lexer, const char *id) return false; } } + +bool +lexer_is_int(const struct lexer *lexer) +{ + return (lexer->token.type == LEX_T_INTEGER + && lexer->token.format == LEX_F_DECIMAL + && ntohll(lexer->token.value.integer) <= INT_MAX); +} + +bool +lexer_get_int(struct lexer *lexer, int *value) +{ + if (lexer_is_int(lexer)) { + *value = ntohll(lexer->token.value.integer); + lexer_get(lexer); + return true; + } else { + *value = 0; + return false; + } +} diff --git a/ovn/lib/lex.h b/ovn/lib/lex.h index b5828a2..7ad6f55 100644 --- a/ovn/lib/lex.h +++ b/ovn/lib/lex.h @@ -109,5 +109,7 @@ enum lex_type lexer_get(struct lexer *); enum lex_type lexer_lookahead(const struct lexer *); bool lexer_match(struct lexer *, enum lex_type); bool lexer_match_id(struct lexer *, const char *id); +bool lexer_is_int(const struct lexer *); +bool lexer_get_int(struct lexer *, int *value); #endif /* ovn/lex.h */ diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index 4609c2d..8c457d4 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -767,8 +767,11 @@
next;
+
next(table);
- Executes the next logical datapath table as a subroutine. + Executes another logical datapath table as a subroutine. By default, + the table after the current one is executed. Specify + table to jump to a specific table in the same pipeline.
field = constant;
diff --git a/tests/ovn.at b/tests/ovn.at index 1eb6d0b..330f723 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -438,9 +438,11 @@ dnl Text before => is input, text after => is expected output. AT_DATA([test-cases.txt], [[ # Positive tests. drop; => actions=drop, prereqs=1 -next; => actions=resubmit(,11), prereqs=1 +next; => actions=resubmit(,27), prereqs=1 +next(0); => actions=resubmit(,16), prereqs=1 +next(15); => actions=resubmit(,31), prereqs=1 output; => actions=resubmit(,64), prereqs=1 -outport="eth0"; next; outport="LOCAL"; next; => actions=set_field:0x5->reg7,resubmit(,11),set_field:0xfffe->reg7,resubmit(,11), prereqs=1 +outport="eth0"; next; outport="LOCAL"; next; => actions=set_field:0x5->reg7,resubmit(,27),set_field:0xfffe->reg7,resubmit(,27), prereqs=1 tcp.dst=80; => actions=set_field:80->tcp_dst, prereqs=ip.proto == 0x6 && (eth.type == 0x800 || eth.type == 0x86dd) eth.dst[40] = 1; => actions=set_field:01:00:00:00:00:00/01:00:00:00:00:00->eth_dst, prereqs=1 vlan.pcp = 2; => actions=set_field:0x4000/0xe000->vlan_tci, prereqs=vlan.tci[12] @@ -471,6 +473,10 @@ next; drop; => Syntax error at `drop' expecting action. # Missing ";": next => Syntax error at end of input expecting ';'. +next(); => Syntax error at `)' expecting small integer. +next(10; => Syntax error at `;' expecting `)'. +next(16); => "next" argument must be in range 0 to 15. + inport[1] = 1; => Cannot select subfield of string field inport. ip.proto[1] = 1; => Cannot select subfield of nominal field ip.proto. eth.dst[40] == 1; => Syntax error at `==' expecting `='. diff --git a/tests/test-ovn.c b/tests/test-ovn.c index 774ebdf..0e9d2d2 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1225,8 +1225,8 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) char *error; ofpbuf_init(&ofpacts, 0); - error = actions_parse_string(ds_cstr(&input), &symtab, &ports, 11, 64, - &ofpacts, &prereqs); + error = actions_parse_string(ds_cstr(&input), &symtab, &ports, + 16, 16, 10, 64, &ofpacts, &prereqs); if (!error) { struct ds output;