LCOV - code coverage report
Current view: top level - lib - vconn-stream.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 138 148 93.2 %
Date: 2016-09-14 01:02:56 Functions: 18 18 100.0 %
Branches: 54 74 73.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 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                 :            : #include <config.h>
      18                 :            : #include <errno.h>
      19                 :            : #include <poll.h>
      20                 :            : #include <stdlib.h>
      21                 :            : #include <string.h>
      22                 :            : #include <sys/types.h>
      23                 :            : #include <unistd.h>
      24                 :            : #include "fatal-signal.h"
      25                 :            : #include "openvswitch/ofpbuf.h"
      26                 :            : #include "openflow/openflow.h"
      27                 :            : #include "poll-loop.h"
      28                 :            : #include "socket-util.h"
      29                 :            : #include "stream.h"
      30                 :            : #include "util.h"
      31                 :            : #include "vconn-provider.h"
      32                 :            : #include "openvswitch/vconn.h"
      33                 :            : #include "openvswitch/vlog.h"
      34                 :            : 
      35                 :      19636 : VLOG_DEFINE_THIS_MODULE(vconn_stream);
      36                 :            : 
      37                 :            : /* Active stream socket vconn. */
      38                 :            : 
      39                 :            : struct vconn_stream
      40                 :            : {
      41                 :            :     struct vconn vconn;
      42                 :            :     struct stream *stream;
      43                 :            :     struct ofpbuf *rxbuf;
      44                 :            :     struct ofpbuf *txbuf;
      45                 :            :     int n_packets;
      46                 :            : };
      47                 :            : 
      48                 :            : static const struct vconn_class stream_vconn_class;
      49                 :            : 
      50                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 25);
      51                 :            : 
      52                 :            : static void vconn_stream_clear_txbuf(struct vconn_stream *);
      53                 :            : 
      54                 :            : static struct vconn *
      55                 :       6921 : vconn_stream_new(struct stream *stream, int connect_status,
      56                 :            :                  uint32_t allowed_versions)
      57                 :            : {
      58                 :            :     struct vconn_stream *s;
      59                 :            : 
      60                 :       6921 :     s = xmalloc(sizeof *s);
      61                 :       6921 :     vconn_init(&s->vconn, &stream_vconn_class, connect_status,
      62                 :            :                stream_get_name(stream), allowed_versions);
      63                 :       6921 :     s->stream = stream;
      64                 :       6921 :     s->txbuf = NULL;
      65                 :       6921 :     s->rxbuf = NULL;
      66                 :       6921 :     s->n_packets = 0;
      67                 :       6921 :     return &s->vconn;
      68                 :            : }
      69                 :            : 
      70                 :            : /* Creates a new vconn that will send and receive data on a stream named 'name'
      71                 :            :  * and stores a pointer to the vconn in '*vconnp'.
      72                 :            :  *
      73                 :            :  * Returns 0 if successful, otherwise a positive errno value. */
      74                 :            : static int
      75                 :       6894 : vconn_stream_open(const char *name, uint32_t allowed_versions,
      76                 :            :                   char *suffix OVS_UNUSED, struct vconn **vconnp, uint8_t dscp)
      77                 :            : {
      78                 :            :     struct stream *stream;
      79                 :            :     int error;
      80                 :            : 
      81                 :       6894 :     error = stream_open_with_default_port(name, OFP_PORT, &stream, dscp);
      82         [ +  + ]:       6894 :     if (!error) {
      83                 :       3502 :         error = stream_connect(stream);
      84 [ +  + ][ +  - ]:       3502 :         if (!error || error == EAGAIN) {
      85                 :       3502 :             *vconnp = vconn_stream_new(stream, error, allowed_versions);
      86                 :       3502 :             return 0;
      87                 :            :         }
      88                 :            :     }
      89                 :            : 
      90                 :       3392 :     stream_close(stream);
      91                 :       6894 :     return error;
      92                 :            : }
      93                 :            : 
      94                 :            : static struct vconn_stream *
      95                 :     704825 : vconn_stream_cast(struct vconn *vconn)
      96                 :            : {
      97                 :     704825 :     return CONTAINER_OF(vconn, struct vconn_stream, vconn);
      98                 :            : }
      99                 :            : 
     100                 :            : static void
     101                 :       6870 : vconn_stream_close(struct vconn *vconn)
     102                 :            : {
     103                 :       6870 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     104                 :            : 
     105 [ +  + ][ +  + ]:       6870 :     if ((vconn->error == EPROTO || s->n_packets < 1) && s->rxbuf) {
                 [ +  + ]
     106                 :          8 :         stream_report_content(s->rxbuf->data, s->rxbuf->size, STREAM_OPENFLOW,
     107                 :            :                               &this_module, vconn_get_name(vconn));
     108                 :            :     }
     109                 :            : 
     110                 :       6870 :     stream_close(s->stream);
     111                 :       6870 :     vconn_stream_clear_txbuf(s);
     112                 :       6870 :     ofpbuf_delete(s->rxbuf);
     113                 :       6870 :     free(s);
     114                 :       6870 : }
     115                 :            : 
     116                 :            : static int
     117                 :         75 : vconn_stream_connect(struct vconn *vconn)
     118                 :            : {
     119                 :         75 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     120                 :         75 :     return stream_connect(s->stream);
     121                 :            : }
     122                 :            : 
     123                 :            : static int
     124                 :     254636 : vconn_stream_recv__(struct vconn_stream *s, int rx_len)
     125                 :            : {
     126                 :     254636 :     struct ofpbuf *rx = s->rxbuf;
     127                 :            :     int want_bytes, retval;
     128                 :            : 
     129                 :     254636 :     want_bytes = rx_len - rx->size;
     130                 :     254636 :     ofpbuf_prealloc_tailroom(rx, want_bytes);
     131                 :     254636 :     retval = stream_recv(s->stream, ofpbuf_tail(rx), want_bytes);
     132         [ +  + ]:     254636 :     if (retval > 0) {
     133                 :     125174 :         rx->size += retval;
     134         [ +  - ]:     125174 :         return retval == want_bytes ? 0 : EAGAIN;
     135         [ +  + ]:     129462 :     } else if (retval == 0) {
     136         [ -  + ]:       3420 :         if (rx->size) {
     137         [ #  # ]:          0 :             VLOG_ERR_RL(&rl, "connection dropped mid-packet");
     138                 :          0 :             return EPROTO;
     139                 :            :         }
     140                 :       3420 :         return EOF;
     141                 :            :     } else {
     142                 :     126042 :         return -retval;
     143                 :            :     }
     144                 :            : }
     145                 :            : 
     146                 :            : static int
     147                 :     210236 : vconn_stream_recv(struct vconn *vconn, struct ofpbuf **bufferp)
     148                 :            : {
     149                 :     210236 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     150                 :            :     const struct ofp_header *oh;
     151                 :            :     int rx_len;
     152                 :            : 
     153                 :            :     /* Allocate new receive buffer if we don't have one. */
     154         [ +  + ]:     210236 :     if (s->rxbuf == NULL) {
     155                 :      84462 :         s->rxbuf = ofpbuf_new(1564);
     156                 :            :     }
     157                 :            : 
     158                 :            :     /* Read ofp_header. */
     159         [ +  - ]:     210236 :     if (s->rxbuf->size < sizeof(struct ofp_header)) {
     160                 :     210236 :         int retval = vconn_stream_recv__(s, sizeof(struct ofp_header));
     161         [ +  + ]:     210236 :         if (retval) {
     162                 :     129462 :             return retval;
     163                 :            :         }
     164                 :            :     }
     165                 :            : 
     166                 :            :     /* Read payload. */
     167                 :      80774 :     oh = s->rxbuf->data;
     168                 :      80774 :     rx_len = ntohs(oh->length);
     169         [ +  + ]:      80774 :     if (rx_len < sizeof(struct ofp_header)) {
     170         [ +  - ]:          3 :         VLOG_ERR_RL(&rl, "received too-short ofp_header (%d bytes)", rx_len);
     171                 :          3 :         return EPROTO;
     172         [ +  + ]:      80771 :     } else if (s->rxbuf->size < rx_len) {
     173                 :      44400 :         int retval = vconn_stream_recv__(s, rx_len);
     174         [ -  + ]:      44400 :         if (retval) {
     175                 :          0 :             return retval;
     176                 :            :         }
     177                 :            :     }
     178                 :            : 
     179                 :      80771 :     s->n_packets++;
     180                 :      80771 :     *bufferp = s->rxbuf;
     181                 :      80771 :     s->rxbuf = NULL;
     182                 :      80771 :     return 0;
     183                 :            : }
     184                 :            : 
     185                 :            : static void
     186                 :       6955 : vconn_stream_clear_txbuf(struct vconn_stream *s)
     187                 :            : {
     188                 :       6955 :     ofpbuf_delete(s->txbuf);
     189                 :       6955 :     s->txbuf = NULL;
     190                 :       6955 : }
     191                 :            : 
     192                 :            : static int
     193                 :      93528 : vconn_stream_send(struct vconn *vconn, struct ofpbuf *buffer)
     194                 :            : {
     195                 :      93528 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     196                 :            :     ssize_t retval;
     197                 :            : 
     198         [ +  + ]:      93528 :     if (s->txbuf) {
     199                 :      12654 :         return EAGAIN;
     200                 :            :     }
     201                 :            : 
     202                 :      80874 :     retval = stream_send(s->stream, buffer->data, buffer->size);
     203         [ +  + ]:      80874 :     if (retval == buffer->size) {
     204                 :      80784 :         ofpbuf_delete(buffer);
     205                 :      80784 :         return 0;
     206 [ +  - ][ +  + ]:         90 :     } else if (retval >= 0 || retval == -EAGAIN) {
     207                 :         85 :         s->txbuf = buffer;
     208         [ -  + ]:         85 :         if (retval > 0) {
     209                 :          0 :             ofpbuf_pull(buffer, retval);
     210                 :            :         }
     211                 :         85 :         return 0;
     212                 :            :     } else {
     213                 :          5 :         return -retval;
     214                 :            :     }
     215                 :            : }
     216                 :            : 
     217                 :            : static void
     218                 :     125346 : vconn_stream_run(struct vconn *vconn)
     219                 :            : {
     220                 :     125346 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     221                 :            :     ssize_t retval;
     222                 :            : 
     223                 :     125346 :     stream_run(s->stream);
     224         [ +  + ]:     125346 :     if (!s->txbuf) {
     225                 :     112688 :         return;
     226                 :            :     }
     227                 :            : 
     228                 :      12658 :     retval = stream_send(s->stream, s->txbuf->data, s->txbuf->size);
     229         [ +  + ]:      12658 :     if (retval < 0) {
     230         [ -  + ]:      12573 :         if (retval != -EAGAIN) {
     231         [ #  # ]:          0 :             VLOG_ERR_RL(&rl, "send: %s", ovs_strerror(-retval));
     232                 :          0 :             vconn_stream_clear_txbuf(s);
     233                 :          0 :             return;
     234                 :            :         }
     235         [ +  - ]:         85 :     } else if (retval > 0) {
     236                 :         85 :         ofpbuf_pull(s->txbuf, retval);
     237         [ +  - ]:         85 :         if (!s->txbuf->size) {
     238                 :         85 :             vconn_stream_clear_txbuf(s);
     239                 :         85 :             return;
     240                 :            :         }
     241                 :            :     }
     242                 :            : }
     243                 :            : 
     244                 :            : static void
     245                 :     124578 : vconn_stream_run_wait(struct vconn *vconn)
     246                 :            : {
     247                 :     124578 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     248                 :            : 
     249                 :     124578 :     stream_run_wait(s->stream);
     250         [ +  + ]:     124578 :     if (s->txbuf) {
     251                 :      12658 :         stream_send_wait(s->stream);
     252                 :            :     }
     253                 :     124578 : }
     254                 :            : 
     255                 :            : static void
     256                 :     144192 : vconn_stream_wait(struct vconn *vconn, enum vconn_wait_type wait)
     257                 :            : {
     258                 :     144192 :     struct vconn_stream *s = vconn_stream_cast(vconn);
     259   [ +  +  +  - ]:     144192 :     switch (wait) {
     260                 :            :     case WAIT_CONNECT:
     261                 :         64 :         stream_connect_wait(s->stream);
     262                 :         64 :         break;
     263                 :            : 
     264                 :            :     case WAIT_SEND:
     265         [ +  + ]:      19492 :         if (!s->txbuf) {
     266                 :       6838 :             stream_send_wait(s->stream);
     267                 :            :         } else {
     268                 :            :             /* Nothing to do: need to drain txbuf first.
     269                 :            :              * vconn_stream_run_wait() will arrange to wake up when there room
     270                 :            :              * to send data, so there's no point in calling poll_fd_wait()
     271                 :            :              * redundantly here. */
     272                 :            :         }
     273                 :      19492 :         break;
     274                 :            : 
     275                 :            :     case WAIT_RECV:
     276                 :     124636 :         stream_recv_wait(s->stream);
     277                 :     124636 :         break;
     278                 :            : 
     279                 :            :     default:
     280                 :          0 :         OVS_NOT_REACHED();
     281                 :            :     }
     282                 :     144192 : }
     283                 :            : 
     284                 :            : /* Passive stream socket vconn. */
     285                 :            : 
     286                 :            : struct pvconn_pstream
     287                 :            : {
     288                 :            :     struct pvconn pvconn;
     289                 :            :     struct pstream *pstream;
     290                 :            : };
     291                 :            : 
     292                 :            : static const struct pvconn_class pstream_pvconn_class;
     293                 :            : 
     294                 :            : static struct pvconn_pstream *
     295                 :     624004 : pvconn_pstream_cast(struct pvconn *pvconn)
     296                 :            : {
     297                 :     624004 :     return CONTAINER_OF(pvconn, struct pvconn_pstream, pvconn);
     298                 :            : }
     299                 :            : 
     300                 :            : /* Creates a new pvconn named 'name' that will accept new connections using
     301                 :            :  * pstream_accept() and stores a pointer to the pvconn in '*pvconnp'.
     302                 :            :  *
     303                 :            :  * Returns 0 if successful, otherwise a positive errno value.  (The current
     304                 :            :  * implementation never fails.) */
     305                 :            : static int
     306                 :       1499 : pvconn_pstream_listen(const char *name, uint32_t allowed_versions,
     307                 :            :                       char *suffix OVS_UNUSED, struct pvconn **pvconnp,
     308                 :            :                       uint8_t dscp)
     309                 :            : {
     310                 :            :     struct pvconn_pstream *ps;
     311                 :            :     struct pstream *pstream;
     312                 :            :     int error;
     313                 :            : 
     314                 :       1499 :     error = pstream_open_with_default_port(name, OFP_PORT, &pstream, dscp);
     315         [ -  + ]:       1499 :     if (error) {
     316                 :          0 :         return error;
     317                 :            :     }
     318                 :            : 
     319                 :       1499 :     ps = xmalloc(sizeof *ps);
     320                 :       1499 :     pvconn_init(&ps->pvconn, &pstream_pvconn_class, name, allowed_versions);
     321                 :       1499 :     ps->pstream = pstream;
     322                 :       1499 :     *pvconnp = &ps->pvconn;
     323                 :       1499 :     return 0;
     324                 :            : }
     325                 :            : 
     326                 :            : static void
     327                 :       1499 : pvconn_pstream_close(struct pvconn *pvconn)
     328                 :            : {
     329                 :       1499 :     struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
     330                 :       1499 :     pstream_close(ps->pstream);
     331                 :       1499 :     free(ps);
     332                 :       1499 : }
     333                 :            : 
     334                 :            : static int
     335                 :     315213 : pvconn_pstream_accept(struct pvconn *pvconn, struct vconn **new_vconnp)
     336                 :            : {
     337                 :     315213 :     struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
     338                 :            :     struct stream *stream;
     339                 :            :     int error;
     340                 :            : 
     341                 :     315213 :     error = pstream_accept(ps->pstream, &stream);
     342         [ +  + ]:     315213 :     if (error) {
     343         [ -  + ]:     311794 :         if (error != EAGAIN) {
     344         [ #  # ]:          0 :             VLOG_DBG_RL(&rl, "%s: accept: %s",
     345                 :            :                         pstream_get_name(ps->pstream), ovs_strerror(error));
     346                 :            :         }
     347                 :     311794 :         return error;
     348                 :            :     }
     349                 :            : 
     350                 :       3419 :     *new_vconnp = vconn_stream_new(stream, 0, pvconn->allowed_versions);
     351                 :     315213 :     return 0;
     352                 :            : }
     353                 :            : 
     354                 :            : static void
     355                 :     307292 : pvconn_pstream_wait(struct pvconn *pvconn)
     356                 :            : {
     357                 :     307292 :     struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
     358                 :     307292 :     pstream_wait(ps->pstream);
     359                 :     307292 : }
     360                 :            : 
     361                 :            : /* Stream-based vconns and pvconns. */
     362                 :            : 
     363                 :            : #define STREAM_INIT(NAME)                           \
     364                 :            :     {                                               \
     365                 :            :             NAME,                                   \
     366                 :            :             vconn_stream_open,                      \
     367                 :            :             vconn_stream_close,                     \
     368                 :            :             vconn_stream_connect,                   \
     369                 :            :             vconn_stream_recv,                      \
     370                 :            :             vconn_stream_send,                      \
     371                 :            :             vconn_stream_run,                       \
     372                 :            :             vconn_stream_run_wait,                  \
     373                 :            :             vconn_stream_wait,                      \
     374                 :            :     }
     375                 :            : 
     376                 :            : #define PSTREAM_INIT(NAME)                          \
     377                 :            :     {                                               \
     378                 :            :             NAME,                                   \
     379                 :            :             pvconn_pstream_listen,                  \
     380                 :            :             pvconn_pstream_close,                   \
     381                 :            :             pvconn_pstream_accept,                  \
     382                 :            :             pvconn_pstream_wait                     \
     383                 :            :     }
     384                 :            : 
     385                 :            : static const struct vconn_class stream_vconn_class = STREAM_INIT("stream");
     386                 :            : static const struct pvconn_class pstream_pvconn_class = PSTREAM_INIT("pstream");
     387                 :            : 
     388                 :            : const struct vconn_class tcp_vconn_class = STREAM_INIT("tcp");
     389                 :            : const struct pvconn_class ptcp_pvconn_class = PSTREAM_INIT("ptcp");
     390                 :            : 
     391                 :            : const struct vconn_class unix_vconn_class = STREAM_INIT("unix");
     392                 :            : const struct pvconn_class punix_pvconn_class = PSTREAM_INIT("punix");
     393                 :            : 
     394                 :            : #ifdef HAVE_OPENSSL
     395                 :            : const struct vconn_class ssl_vconn_class = STREAM_INIT("ssl");
     396                 :            : const struct pvconn_class pssl_pvconn_class = PSTREAM_INIT("pssl");
     397                 :            : #endif

Generated by: LCOV version 1.12