LCOV - code coverage report
Current view: top level - ofproto - ofproto-dpif-rid.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 47 48 97.9 %
Date: 2016-09-14 01:02:56 Functions: 8 8 100.0 %
Branches: 15 18 83.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #ifndef OFPROTO_DPIF_RID_H
      18                 :            : #define OFPROTO_DPIF_RID_H
      19                 :            : 
      20                 :            : #include <stddef.h>
      21                 :            : #include <stdint.h>
      22                 :            : 
      23                 :            : #include "cmap.h"
      24                 :            : #include "ofproto-dpif-mirror.h"
      25                 :            : #include "openvswitch/list.h"
      26                 :            : #include "openvswitch/ofp-actions.h"
      27                 :            : #include "ovs-thread.h"
      28                 :            : #include "uuid.h"
      29                 :            : 
      30                 :            : struct ofproto_dpif;
      31                 :            : struct rule;
      32                 :            : 
      33                 :            : /*
      34                 :            :  * Freezing and recirculation
      35                 :            :  * ==========================
      36                 :            :  *
      37                 :            :  * Freezing is a technique for halting and checkpointing packet translation in
      38                 :            :  * a way that it can be restarted again later.  This file has a couple of data
      39                 :            :  * structures related to freezing in general; their names begin with "frozen".
      40                 :            :  *
      41                 :            :  * Recirculation is the use of freezing to allow a frame to re-enter the
      42                 :            :  * datapath packet processing path to achieve more flexible packet processing,
      43                 :            :  * such as modifying header fields after MPLS POP action and selecting a slave
      44                 :            :  * port for bond ports.
      45                 :            :  *
      46                 :            :  *
      47                 :            :  * Data path and user space interface
      48                 :            :  * -----------------------------------
      49                 :            :  *
      50                 :            :  * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a RECIRC
      51                 :            :  * action.  recirc_id is used to select the next packet processing steps among
      52                 :            :  * multiple instances of recirculation.  When a packet initially enters the
      53                 :            :  * datapath it is assigned with recirc_id 0, which indicates no recirculation.
      54                 :            :  * Recirc_ids are managed by the user space, opaque to the datapath.
      55                 :            :  *
      56                 :            :  * On the other hand, dp_hash can only be computed by the datapath, opaque to
      57                 :            :  * the user space, as the datapath is free to choose the hashing algorithm
      58                 :            :  * without informing user space about it.  The dp_hash value should be
      59                 :            :  * wildcarded for newly received packets.  HASH action specifies whether the
      60                 :            :  * hash is computed, and if computed, how many fields are to be included in the
      61                 :            :  * hash computation.  The computed hash value is stored into the dp_hash field
      62                 :            :  * prior to recirculation.
      63                 :            :  *
      64                 :            :  * The RECIRC action sets the recirc_id field and then reprocesses the packet
      65                 :            :  * as if it was received again on the same input port.  RECIRC action works
      66                 :            :  * like a function call; actions listed after the RECIRC action will be
      67                 :            :  * executed after recirculation.  RECIRC action can be nested, but datapath
      68                 :            :  * implementation limits the number of nested recirculations to prevent
      69                 :            :  * unreasonable nesting depth or infinite loop.
      70                 :            :  *
      71                 :            :  * User space recirculation context
      72                 :            :  * ---------------------------------
      73                 :            :  *
      74                 :            :  * Recirculation is usually hidden from the OpenFlow controllers.  Action
      75                 :            :  * translation code deduces when recirculation is necessary and issues a
      76                 :            :  * datapath recirculation action.  All OpenFlow actions to be performed after
      77                 :            :  * recirculation are derived from the OpenFlow pipeline and are stored with the
      78                 :            :  * recirculation ID.  When the OpenFlow tables are changed in a way affecting
      79                 :            :  * the recirculation flows, new recirculation ID with new metadata and actions
      80                 :            :  * is allocated and the old one is timed out.
      81                 :            :  *
      82                 :            :  * Recirculation ID pool
      83                 :            :  * ----------------------
      84                 :            :  *
      85                 :            :  * Recirculation ID needs to be unique for all datapaths.  Recirculation ID
      86                 :            :  * pool keeps track of recirculation ids and stores OpenFlow pipeline
      87                 :            :  * translation context so that flow processing may continue after
      88                 :            :  * recirculation.
      89                 :            :  *
      90                 :            :  * A Recirculation ID can be any uint32_t value, except for that the value 0 is
      91                 :            :  * reserved for 'no recirculation' case.
      92                 :            :  *
      93                 :            :  * Thread-safety
      94                 :            :  * --------------
      95                 :            :  *
      96                 :            :  * All APIs are thread safe.
      97                 :            :  */
      98                 :            : 
      99                 :            : /* Metadata for restoring pipeline context after recirculation.  Helpers
     100                 :            :  * are inlined below to keep them together with the definition for easier
     101                 :            :  * updates. */
     102                 :            : BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
     103                 :            : 
     104                 :            : struct frozen_metadata {
     105                 :            :     /* Metadata in struct flow. */
     106                 :            :     const struct flow_tnl *tunnel; /* Encapsulating tunnel parameters. */
     107                 :            :     ovs_be64 metadata;            /* OpenFlow Metadata. */
     108                 :            :     uint64_t regs[FLOW_N_XREGS];  /* Registers. */
     109                 :            :     ofp_port_t in_port;           /* Incoming port. */
     110                 :            : };
     111                 :            : 
     112                 :            : static inline void
     113                 :       1419 : frozen_metadata_from_flow(struct frozen_metadata *md,
     114                 :            :                           const struct flow *flow)
     115                 :            : {
     116                 :       1419 :     memset(md, 0, sizeof *md);
     117                 :       1419 :     md->tunnel = &flow->tunnel;
     118                 :       1419 :     md->metadata = flow->metadata;
     119                 :       1419 :     memcpy(md->regs, flow->regs, sizeof md->regs);
     120                 :       1419 :     md->in_port = flow->in_port.ofp_port;
     121                 :       1419 : }
     122                 :            : 
     123                 :            : static inline void
     124                 :       1503 : frozen_metadata_to_flow(const struct frozen_metadata *md,
     125                 :            :                         struct flow *flow)
     126                 :            : {
     127 [ +  - ][ -  + ]:       1503 :     if (md->tunnel && flow_tnl_dst_is_set(md->tunnel)) {
     128                 :          0 :         flow->tunnel = *md->tunnel;
     129                 :            :     } else {
     130                 :       1503 :         memset(&flow->tunnel, 0, sizeof flow->tunnel);
     131                 :            :     }
     132                 :       1503 :     flow->metadata = md->metadata;
     133                 :       1503 :     memcpy(flow->regs, md->regs, sizeof flow->regs);
     134                 :       1503 :     flow->in_port.ofp_port = md->in_port;
     135                 :       1503 : }
     136                 :            : 
     137                 :            : /* State that flow translation can save, to restore when translation
     138                 :            :  * resumes.  */
     139                 :            : struct frozen_state {
     140                 :            :     /* Initial table for processing when thawing. */
     141                 :            :     uint8_t table_id;
     142                 :            : 
     143                 :            :     /* Pipeline context for processing when thawing. */
     144                 :            :     struct uuid ofproto_uuid;     /* Bridge to resume from. */
     145                 :            :     struct frozen_metadata metadata; /* Flow metadata. */
     146                 :            :     union mf_subvalue *stack;     /* Stack if any. */
     147                 :            :     size_t n_stack;
     148                 :            :     mirror_mask_t mirrors;        /* Mirrors already output. */
     149                 :            :     bool conntracked;             /* Conntrack occurred prior to freeze. */
     150                 :            : 
     151                 :            :     /* Actions to be translated when thawing. */
     152                 :            :     struct ofpact *ofpacts;
     153                 :            :     size_t ofpacts_len;           /* Size of 'ofpacts', in bytes. */
     154                 :            :     struct ofpact *action_set;
     155                 :            :     size_t action_set_len;        /* Size of 'action_set', in bytes. */
     156                 :            : };
     157                 :            : 
     158                 :            : /* This maps a recirculation ID to saved state that flow translation can
     159                 :            :  * restore when recirculation occurs. */
     160                 :            : struct recirc_id_node {
     161                 :            :     /* Index data. */
     162                 :            :     struct ovs_list exp_node OVS_GUARDED;
     163                 :            :     struct cmap_node id_node;
     164                 :            :     struct cmap_node metadata_node;
     165                 :            :     uint32_t id;
     166                 :            :     uint32_t hash;
     167                 :            :     struct ovs_refcount refcount;
     168                 :            : 
     169                 :            :     /* Saved state.
     170                 :            :      *
     171                 :            :      * This state should not be modified after inserting a node in the pool,
     172                 :            :      * hence the 'const' to emphasize that. */
     173                 :            :     const struct frozen_state state;
     174                 :            : 
     175                 :            :     /* Storage for tunnel metadata. */
     176                 :            :     struct flow_tnl state_metadata_tunnel;
     177                 :            : };
     178                 :            : 
     179                 :            : /* This is only used for bonds and will go away when bonds implementation is
     180                 :            :  * updated to use this mechanism instead of internal rules. */
     181                 :            : uint32_t recirc_alloc_id(struct ofproto_dpif *);
     182                 :            : 
     183                 :            : uint32_t recirc_alloc_id_ctx(const struct frozen_state *);
     184                 :            : uint32_t recirc_find_id(const struct frozen_state *);
     185                 :            : void recirc_free_id(uint32_t recirc_id);
     186                 :            : void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name);
     187                 :            : 
     188                 :            : const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id);
     189                 :            : 
     190                 :            : static inline struct recirc_id_node *
     191                 :        771 : recirc_id_node_from_state(const struct frozen_state *state)
     192                 :            : {
     193                 :        771 :     return CONTAINER_OF(state, struct recirc_id_node, state);
     194                 :            : }
     195                 :            : 
     196                 :        771 : static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_)
     197                 :            : {
     198                 :        771 :     struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_);
     199                 :            : 
     200 [ +  - ][ +  + ]:        771 :     return node ? ovs_refcount_try_ref_rcu(&node->refcount) : false;
     201                 :            : }
     202                 :            : 
     203                 :            : void recirc_id_node_unref(const struct recirc_id_node *);
     204                 :            : 
     205                 :            : void recirc_run(void);
     206                 :            : 
     207                 :            : /* Recirculation IDs on which references are held. */
     208                 :            : struct recirc_refs {
     209                 :            :     unsigned n_recircs;
     210                 :            :     union {
     211                 :            :         uint32_t recirc[2];   /* When n_recircs == 1 or 2 */
     212                 :            :         uint32_t *recircs;    /* When 'n_recircs' > 2 */
     213                 :            :     };
     214                 :            : };
     215                 :            : 
     216                 :            : #define RECIRC_REFS_EMPTY_INITIALIZER ((struct recirc_refs) \
     217                 :            :                                        { 0, { { 0, 0 } } })
     218                 :            : /* Helpers to abstract the recirculation union away. */
     219                 :            : static inline void
     220                 :       6744 : recirc_refs_init(struct recirc_refs *rr)
     221                 :            : {
     222                 :       6744 :     *rr = RECIRC_REFS_EMPTY_INITIALIZER;
     223                 :       6744 : }
     224                 :            : 
     225                 :            : static inline void
     226                 :        947 : recirc_refs_add(struct recirc_refs *rr, uint32_t id)
     227                 :            : {
     228         [ +  + ]:        947 :     if (OVS_LIKELY(rr->n_recircs < ARRAY_SIZE(rr->recirc))) {
     229                 :        907 :         rr->recirc[rr->n_recircs++] = id;
     230                 :            :     } else {
     231         [ +  + ]:         40 :         if (rr->n_recircs == ARRAY_SIZE(rr->recirc)) {
     232                 :         20 :             uint32_t *recircs = xmalloc(sizeof rr->recirc + sizeof id);
     233                 :            : 
     234                 :         20 :             memcpy(recircs, rr->recirc, sizeof rr->recirc);
     235                 :         20 :             rr->recircs = recircs;
     236                 :            :         } else {
     237                 :         20 :             rr->recircs = xrealloc(rr->recircs,
     238                 :         20 :                                    (rr->n_recircs + 1) * sizeof id);
     239                 :            :         }
     240                 :         40 :         rr->recircs[rr->n_recircs++] = id;
     241                 :            :     }
     242                 :        947 : }
     243                 :            : 
     244                 :            : static inline void
     245                 :       7539 : recirc_refs_swap(struct recirc_refs *a, struct recirc_refs *b)
     246                 :            : {
     247                 :            :     struct recirc_refs tmp;
     248                 :            : 
     249                 :       7539 :     tmp = *a;
     250                 :       7539 :     *a = *b;
     251                 :       7539 :     *b = tmp;
     252                 :       7539 : }
     253                 :            : 
     254                 :            : static inline void
     255                 :      91781 : recirc_refs_unref(struct recirc_refs *rr)
     256                 :            : {
     257         [ +  + ]:      91781 :     if (OVS_LIKELY(rr->n_recircs <= ARRAY_SIZE(rr->recirc))) {
     258         [ +  + ]:      92626 :         for (int i = 0; i < rr->n_recircs; i++) {
     259                 :        865 :             recirc_free_id(rr->recirc[i]);
     260                 :            :         }
     261                 :            :     } else {
     262         [ +  + ]:        100 :         for (int i = 0; i < rr->n_recircs; i++) {
     263                 :         80 :             recirc_free_id(rr->recircs[i]);
     264                 :            :         }
     265                 :         20 :         free(rr->recircs);
     266                 :            :     }
     267                 :      91781 :     rr->n_recircs = 0;
     268                 :      91781 : }
     269                 :            : 
     270                 :            : #endif

Generated by: LCOV version 1.12