ovn/controller/lflow.c
void
lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
          const struct simap *ct_zones,
          struct hmap *local_datapaths)
{
    struct hmap flows = HMAP_INITIALIZER(&flows);
    uint32_t conj_id_ofs = 1;

    ldp_run(ctx);

    const struct sbrec_logical_flow *lflow;
    SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) {
        /* Find the "struct logical_datapath" associated with this
         * Logical_Flow row.  If there's no such struct, that must be because
         * no logical ports are bound to that logical datapath, so there's no
         * point in maintaining any flows for it anyway, so skip it. */
        const struct logical_datapath *ldp;
        ldp = ldp_lookup(lflow->logical_datapath);
        if (!ldp) {
            continue;
        }

        bool ingress = !strcmp(lflow->pipeline, "ingress");

        if (ldp->type == LDP_TYPE_SWITCH && !ingress) {
            /* For a logical switch datapath, local_datapaths tells us if there
             * are any local ports for this datapath.  If not, processing
             * logical flows for the egress pipeline of this datapath is
             * unnecessary.
             *
             * We still need the ingress pipeline because even if there are no
             * local ports, we still may need to execute the ingress pipeline
             * after a packet leaves a logical router.  Further optimization
             * is possible, but not based on what we know with local_datapaths
             * right now.
             *
             * A better approach would be a kind of "flood fill" algorithm:
             *
             *   1. Initialize set S to the logical datapaths that have a port
             *      located on the hypervisor.
             *
             *   2. For each patch port P in a logical datapath in S, add the
             *      logical datapath of the remote end of P to S.  Iterate
             *      until S reaches a fixed point.
             */

            struct hmap_node *ld;
            ld = hmap_first_with_hash(local_datapaths, ldp->tunnel_key);
            if (!ld) {
                continue;
            }
        }

        /* Determine translation of logical table IDs to physical table IDs. */
        uint8_t first_ptable = (ingress
                                ? OFTABLE_LOG_INGRESS_PIPELINE
                                : OFTABLE_LOG_EGRESS_PIPELINE);
        uint8_t ptable = first_ptable + lflow->table_id;
        uint8_t output_ptable = (ingress
                                 ? OFTABLE_REMOTE_OUTPUT
                                 : OFTABLE_LOG_TO_PHY);

        /* Translate OVN actions into OpenFlow actions.
         *
         * XXX Deny changes to 'outport' in egress pipeline. */
        uint64_t ofpacts_stub[64 / 8];
        struct ofpbuf ofpacts;
        struct expr *prereqs;
        char *error;

        ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
        struct action_params ap = {
            .symtab = &symtab,
            .ports = &ldp->ports,
            .ct_zones = ct_zones,

            .n_tables = LOG_PIPELINE_LEN,
            .first_ptable = first_ptable,
            .cur_ltable = lflow->table_id,
            .output_ptable = output_ptable,
        };
        error = actions_parse_string(lflow->actions, &ap, &ofpacts, &prereqs);
        if (error) {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
            VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",
                         lflow->actions, error);
            free(error);
            continue;
        }

        /* Translate OVN match into table of OpenFlow matches. */
        struct hmap matches;
        struct expr *expr;

        expr = expr_parse_string(lflow->match, &symtab, &error);
        if (!error) {
            if (prereqs) {
                expr = expr_combine(EXPR_T_AND, expr, prereqs);
                prereqs = NULL;
            }
            expr = expr_annotate(expr, &symtab, &error);
        }
        if (error) {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
            VLOG_WARN_RL(&rl, "error parsing match \"%s\": %s",
                         lflow->match, error);
            expr_destroy(prereqs);
            ofpbuf_uninit(&ofpacts);
            free(error);
            continue;
        }

        expr = expr_simplify(expr);
        expr = expr_normalize(expr);
        uint32_t n_conjs = expr_to_matches(expr, &ldp->ports, &matches);
        expr_destroy(expr);

        /* Prepare the OpenFlow matches for adding to the flow table. */
        struct expr_match *m;
        HMAP_FOR_EACH (m, hmap_node, &matches) {
            match_set_metadata(&m->match, htonll(ldp->tunnel_key));
            if (m->match.wc.masks.conj_id) {
                m->match.flow.conj_id += conj_id_ofs;
            }
            if (!m->n) {
                ofctrl_add_flow(flow_table, ptable, lflow->priority,
                                &m->match, &ofpacts);
            } else {
                uint64_t conj_stubs[64 / 8];
                struct ofpbuf conj;

                ofpbuf_use_stub(&conj, conj_stubs, sizeof conj_stubs);
                for (int i = 0; i < m->n; i++) {
                    const struct cls_conjunction *src = &m->conjunctions[i];
                    struct ofpact_conjunction *dst;

                    dst = ofpact_put_CONJUNCTION(&conj);
                    dst->id = src->id + conj_id_ofs;
                    dst->clause = src->clause;
                    dst->n_clauses = src->n_clauses;
                }
                ofctrl_add_flow(flow_table, ptable, lflow->priority,
                                &m->match, &conj);
                ofpbuf_uninit(&conj);
            }
        }

        /* Clean up. */
        expr_matches_destroy(&matches);
        ofpbuf_uninit(&ofpacts);
        conj_id_ofs += n_conjs;
    }
}
/* Translates logical flows in the Logical_Flow table in the OVN_SB database
 * into OpenFlow flows.  See ovn-architecture(7) for more information. */
Translates logical flows in the Logical_Flow table in the OVN_SB database
into OpenFlow flows.  See ovn-architecture(7) for more information.
Translates logical flows in the Logical_Flow table in the OVN_SB database into OpenFlow flows . See ovn - architecture ( 7 ) for more information .
void
lflow_run(struct controller_ctx *ctx, struct hmap *flow_table,
          const struct simap *ct_zones,
          struct hmap *local_datapaths)
{
    struct hmap flows = HMAP_INITIALIZER(&flows);
    uint32_t conj_id_ofs = 1;
    ldp_run(ctx);
    const struct sbrec_logical_flow *lflow;
    SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) {
        const struct logical_datapath *ldp;
        ldp = ldp_lookup(lflow->logical_datapath);
        if (!ldp) {
            continue;
        }
        bool ingress = !strcmp(lflow->pipeline, "ingress");
        if (ldp->type == LDP_TYPE_SWITCH && !ingress) {
            struct hmap_node *ld;
            ld = hmap_first_with_hash(local_datapaths, ldp->tunnel_key);
            if (!ld) {
                continue;
            }
        }
        uint8_t first_ptable = (ingress
                                ? OFTABLE_LOG_INGRESS_PIPELINE
                                : OFTABLE_LOG_EGRESS_PIPELINE);
        uint8_t ptable = first_ptable + lflow->table_id;
        uint8_t output_ptable = (ingress
                                 ? OFTABLE_REMOTE_OUTPUT
                                 : OFTABLE_LOG_TO_PHY);
        uint64_t ofpacts_stub[64 / 8];
        struct ofpbuf ofpacts;
        struct expr *prereqs;
        char *error;
        ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
        struct action_params ap = {
            .symtab = &symtab,
            .ports = &ldp->ports,
            .ct_zones = ct_zones,
            .n_tables = LOG_PIPELINE_LEN,
            .first_ptable = first_ptable,
            .cur_ltable = lflow->table_id,
            .output_ptable = output_ptable,
        };
        error = actions_parse_string(lflow->actions, &ap, &ofpacts, &prereqs);
        if (error) {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
            VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",
                         lflow->actions, error);
            free(error);
            continue;
        }
        struct hmap matches;
        struct expr *expr;
        expr = expr_parse_string(lflow->match, &symtab, &error);
        if (!error) {
            if (prereqs) {
                expr = expr_combine(EXPR_T_AND, expr, prereqs);
                prereqs = NULL;
            }
            expr = expr_annotate(expr, &symtab, &error);
        }
        if (error) {
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
            VLOG_WARN_RL(&rl, "error parsing match \"%s\": %s",
                         lflow->match, error);
            expr_destroy(prereqs);
            ofpbuf_uninit(&ofpacts);
            free(error);
            continue;
        }
        expr = expr_simplify(expr);
        expr = expr_normalize(expr);
        uint32_t n_conjs = expr_to_matches(expr, &ldp->ports, &matches);
        expr_destroy(expr);
        struct expr_match *m;
        HMAP_FOR_EACH (m, hmap_node, &matches) {
            match_set_metadata(&m->match, htonll(ldp->tunnel_key));
            if (m->match.wc.masks.conj_id) {
                m->match.flow.conj_id += conj_id_ofs;
            }
            if (!m->n) {
                ofctrl_add_flow(flow_table, ptable, lflow->priority,
                                &m->match, &ofpacts);
            } else {
                uint64_t conj_stubs[64 / 8];
                struct ofpbuf conj;
                ofpbuf_use_stub(&conj, conj_stubs, sizeof conj_stubs);
                for (int i = 0; i < m->n; i++) {
                    const struct cls_conjunction *src = &m->conjunctions[i];
                    struct ofpact_conjunction *dst;
                    dst = ofpact_put_CONJUNCTION(&conj);
                    dst->id = src->id + conj_id_ofs;
                    dst->clause = src->clause;
                    dst->n_clauses = src->n_clauses;
                }
                ofctrl_add_flow(flow_table, ptable, lflow->priority,
                                &m->match, &conj);
                ofpbuf_uninit(&conj);
            }
        }
        expr_matches_destroy(&matches);
        ofpbuf_uninit(&ofpacts);
        conj_id_ofs += n_conjs;
    }
}
void lflow_run ( struct controller_ctx * ctx , struct hmap * flow_table , const struct simap * ct_zones , struct hmap * local_datapaths ) { struct hmap flows = HMAP_INITIALIZER ( & flows ) ; uint32_t conj_id_ofs = 1 ; ldp_run ( ctx ) ; const struct sbrec_logical_flow * lflow ; SBREC_LOGICAL_FLOW_FOR_EACH ( lflow , ctx -> ovnsb_idl ) { const struct logical_datapath * ldp ; ldp = ldp_lookup ( lflow -> logical_datapath ) ; if ( ! ldp ) { continue ; } bool ingress = ! strcmp ( lflow -> pipeline , " " ) ; if ( ldp -> type == LDP_TYPE_SWITCH && ! ingress ) { struct hmap_node * ld ; ld = hmap_first_with_hash ( local_datapaths , ldp -> tunnel_key ) ; if ( ! ld ) { continue ; } } uint8_t first_ptable = ( ingress ? OFTABLE_LOG_INGRESS_PIPELINE : OFTABLE_LOG_EGRESS_PIPELINE ) ; uint8_t ptable = first_ptable + lflow -> table_id ; uint8_t output_ptable = ( ingress ? OFTABLE_REMOTE_OUTPUT : OFTABLE_LOG_TO_PHY ) ; uint64_t ofpacts_stub [ 64 / 8 ] ; struct ofpbuf ofpacts ; struct expr * prereqs ; char * error ; ofpbuf_use_stub ( & ofpacts , ofpacts_stub , sizeof ofpacts_stub ) ; struct action_params ap = { . symtab = & symtab , . ports = & ldp -> ports , . ct_zones = ct_zones , . n_tables = LOG_PIPELINE_LEN , . first_ptable = first_ptable , . cur_ltable = lflow -> table_id , . output_ptable = output_ptable , } ; error = actions_parse_string ( lflow -> actions , & ap , & ofpacts , & prereqs ) ; if ( error ) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT ( 1 , 1 ) ; VLOG_WARN_RL ( & rl , " \" \" " , lflow -> actions , error ) ; free ( error ) ; continue ; } struct hmap matches ; struct expr * expr ; expr = expr_parse_string ( lflow -> match , & symtab , & error ) ; if ( ! error ) { if ( prereqs ) { expr = expr_combine ( EXPR_T_AND , expr , prereqs ) ; prereqs = NULL ; } expr = expr_annotate ( expr , & symtab , & error ) ; } if ( error ) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT ( 1 , 1 ) ; VLOG_WARN_RL ( & rl , " \" \" " , lflow -> match , error ) ; expr_destroy ( prereqs ) ; ofpbuf_uninit ( & ofpacts ) ; free ( error ) ; continue ; } expr = expr_simplify ( expr ) ; expr = expr_normalize ( expr ) ; uint32_t n_conjs = expr_to_matches ( expr , & ldp -> ports , & matches ) ; expr_destroy ( expr ) ; struct expr_match * m ; HMAP_FOR_EACH ( m , hmap_node , & matches ) { match_set_metadata ( & m -> match , htonll ( ldp -> tunnel_key ) ) ; if ( m -> match . wc . masks . conj_id ) { m -> match . flow . conj_id += conj_id_ofs ; } if ( ! m -> n ) { ofctrl_add_flow ( flow_table , ptable , lflow -> priority , & m -> match , & ofpacts ) ; } else { uint64_t conj_stubs [ 64 / 8 ] ; struct ofpbuf conj ; ofpbuf_use_stub ( & conj , conj_stubs , sizeof conj_stubs ) ; for ( int i = 0 ; i < m -> n ; i ++ ) { const struct cls_conjunction * src = & m -> conjunctions [ i ] ; struct ofpact_conjunction * dst ; dst = ofpact_put_CONJUNCTION ( & conj ) ; dst -> id = src -> id + conj_id_ofs ; dst -> clause = src -> clause ; dst -> n_clauses = src -> n_clauses ; } ofctrl_add_flow ( flow_table , ptable , lflow -> priority , & m -> match , & conj ) ; ofpbuf_uninit ( & conj ) ; } } expr_matches_destroy ( & matches ) ; ofpbuf_uninit ( & ofpacts ) ; conj_id_ofs += n_conjs ; } }
Translates logical flows in the Logical_Flow table in the OVN_SB database
 into OpenFlow flows.
Translates logical flows in the Logical_Flow table in the OVN_SB database into OpenFlow flows .
/* Find the "struct logical_datapath" associated with this
         * Logical_Flow row.  If there's no such struct, that must be because
         * no logical ports are bound to that logical datapath, so there's no
         * point in maintaining any flows for it anyway, so skip it. */ /* For a logical switch datapath, local_datapaths tells us if there
             * are any local ports for this datapath.  If not, processing
             * logical flows for the egress pipeline of this datapath is
             * unnecessary.
             *
             * We still need the ingress pipeline because even if there are no
             * local ports, we still may need to execute the ingress pipeline
             * after a packet leaves a logical router.  Further optimization
             * is possible, but not based on what we know with local_datapaths
             * right now.
             *
             * A better approach would be a kind of "flood fill" algorithm:
             *
             *   1. Initialize set S to the logical datapaths that have a port
             *      located on the hypervisor.
             *
             *   2. For each patch port P in a logical datapath in S, add the
             *      logical datapath of the remote end of P to S.  Iterate
             *      until S reaches a fixed point.
             */ /* Determine translation of logical table IDs to physical table IDs. */ /* Translate OVN actions into OpenFlow actions.
         *
         * XXX Deny changes to 'outport' in egress pipeline. */ /* Translate OVN match into table of OpenFlow matches. */ /* Prepare the OpenFlow matches for adding to the flow table. */ /* Clean up. */