2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-25 15:07:05 +00:00
Files
openvswitch/lib/vconn-tcp.c
Ben Pfaff 56192221b7 vconn-unix: Unlink Unix sockets for vconns at close and free memory.
The make_unix_socket() function that Unix vconns use to create their
bindings calls fatal_signal_add_file_to_unlink() to make sure that the
binding socket gets unlinked from the file system if the process is killed
by a fatal signal.  However, this doesn't happen until the process is
actually killed, even if the vconn that owns the socket is actually closed.

This wasn't a problem when the vconn-unix code was written, because all
of the unix vconns were created at process start time and never destroyed
during the normal process runtime.  However, these days the vswitch can
create and destroy unix vconns at runtime depending on the contents of its
configuration file, so it's better to clean up the file system and free
the memory required to keep track of these sockets.

This commit makes unix vconns and pvconns delete their files and free
the memory used to track them when the (p)vconns are closed.

This is only a very minor leak most of the time.

Bug #1817.
2009-09-21 16:44:58 -07:00

141 lines
3.8 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2008, 2009 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <config.h>
#include "vconn.h"
#include <errno.h>
#include <inttypes.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "packets.h"
#include "socket-util.h"
#include "util.h"
#include "openflow/openflow.h"
#include "vconn-provider.h"
#include "vconn-stream.h"
#include "vlog.h"
#define THIS_MODULE VLM_vconn_tcp
/* Active TCP. */
static int
new_tcp_vconn(const char *name, int fd, int connect_status,
const struct sockaddr_in *remote, struct vconn **vconnp)
{
struct sockaddr_in local;
socklen_t local_len = sizeof local;
int on = 1;
int retval;
/* Get the local IP and port information */
retval = getsockname(fd, (struct sockaddr *)&local, &local_len);
if (retval) {
memset(&local, 0, sizeof local);
}
retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
if (retval) {
VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, strerror(errno));
close(fd);
return errno;
}
retval = new_stream_vconn(name, fd, connect_status, NULL, vconnp);
if (!retval) {
struct vconn *vconn = *vconnp;
vconn_set_remote_ip(vconn, remote->sin_addr.s_addr);
vconn_set_remote_port(vconn, remote->sin_port);
vconn_set_local_ip(vconn, local.sin_addr.s_addr);
vconn_set_local_port(vconn, local.sin_port);
}
return retval;
}
static int
tcp_open(const char *name, char *suffix, struct vconn **vconnp)
{
struct sockaddr_in sin;
int fd, error;
error = tcp_open_active(suffix, OFP_TCP_PORT, &sin, &fd);
if (fd >= 0) {
return new_tcp_vconn(name, fd, error, &sin, vconnp);
} else {
VLOG_ERR("%s: connect: %s", name, strerror(error));
return error;
}
}
struct vconn_class tcp_vconn_class = {
"tcp", /* name */
tcp_open, /* open */
NULL, /* close */
NULL, /* connect */
NULL, /* recv */
NULL, /* send */
NULL, /* wait */
};
/* Passive TCP. */
static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
struct vconn **vconnp);
static int
ptcp_open(const char *name UNUSED, char *suffix, struct pvconn **pvconnp)
{
int fd;
fd = tcp_open_passive(suffix, OFP_TCP_PORT);
if (fd < 0) {
return -fd;
} else {
return new_pstream_pvconn("ptcp", fd, ptcp_accept, NULL, pvconnp);
}
}
static int
ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
struct vconn **vconnp)
{
const struct sockaddr_in *sin = (const struct sockaddr_in *) sa;
char name[128];
if (sa_len == sizeof(struct sockaddr_in) && sin->sin_family == AF_INET) {
sprintf(name, "tcp:"IP_FMT, IP_ARGS(&sin->sin_addr));
if (sin->sin_port != htons(OFP_TCP_PORT)) {
sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port));
}
} else {
strcpy(name, "tcp");
}
return new_tcp_vconn(name, fd, 0, sin, vconnp);
}
struct pvconn_class ptcp_pvconn_class = {
"ptcp",
ptcp_open,
NULL,
NULL,
NULL
};