#include <net/if_dl.h>
#include <netinet/in.h>
+#include <errno.h>
+#include <poll.h>
#include <string.h>
#include <unistd.h>
+#include "ovs-router.h"
+#include "packets.h"
+#include "openvswitch/vlog.h"
#include "util.h"
-#include "vlog.h"
-VLOG_DEFINE_THIS_MODULE(route_table);
-
-static int pid;
-static unsigned int register_count = 0;
+VLOG_DEFINE_THIS_MODULE(route_table_bsd);
bool
-route_table_get_name(ovs_be32 ip, char name[IFNAMSIZ])
+route_table_fallback_lookup(ovs_be32 ip, char name[], ovs_be32 *gw)
{
struct {
struct rt_msghdr rtm;
struct sockaddr_in *sin;
struct sockaddr *sa;
static int seq;
- int i, len, namelen, rtsock;
+ int i, namelen, rtsock;
+ ssize_t len;
+ const pid_t pid = getpid();
+ bool got_ifp = false;
+ unsigned int retry_count = 5; /* arbitrary */
+
+ VLOG_DBG("looking route up for " IP_FMT " pid %" PRIuMAX,
+ IP_ARGS(ip), (uintmax_t)pid);
rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
if (rtsock < 0)
return false;
+retry:
memset(&rtmsg, 0, sizeof(rtmsg));
-
rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
rtm->rtm_version = RTM_VERSION;
rtm->rtm_type = RTM_GET;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = ip;
- if ((write(rtsock, (char *)&rtmsg, rtm->rtm_msglen)) < 0) {
+ len = write(rtsock, (char *)&rtmsg, rtm->rtm_msglen);
+ if (len == -1) {
+ if (errno == ENOBUFS && retry_count-- > 0) {
+ VLOG_INFO("Recoverable error writing to routing socket: %s",
+ ovs_strerror(errno));
+ usleep(500 * 1000); /* arbitrary */
+ goto retry;
+ }
+ VLOG_ERR("Error writing to routing socket: %s", ovs_strerror(errno));
+ close(rtsock);
+ return false;
+ }
+ if (len != rtm->rtm_msglen) {
+ VLOG_ERR("Short write to routing socket");
close(rtsock);
return false;
}
do {
+ struct pollfd pfd;
+ int ret;
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = rtsock;
+ pfd.events = POLLIN;
+ /*
+ * The timeout value below is somehow arbitrary.
+ * It's to detect the lost of routing messages due to
+ * buffer exhaustion etc. The routing socket is not
+ * reliable.
+ */
+ ret = poll(&pfd, 1, 500);
+ if (ret == -1) {
+ VLOG_ERR("Error polling on routing socket: %s",
+ ovs_strerror(errno));
+ close(rtsock);
+ return false;
+ }
+ if (ret == 0) {
+ if (retry_count-- > 0) {
+ VLOG_INFO("Timeout; resending routing message");
+ goto retry;
+ }
+ close(rtsock);
+ return false;
+ }
len = read(rtsock, (char *)&rtmsg, sizeof(rtmsg));
+ if (len > 0) {
+ VLOG_DBG("got rtmsg pid %" PRIuMAX " seq %d",
+ (uintmax_t)rtmsg.rtm.rtm_pid,
+ rtmsg.rtm.rtm_seq);
+ }
} while (len > 0 && (rtmsg.rtm.rtm_seq != seq ||
rtmsg.rtm.rtm_pid != pid));
-
close(rtsock);
-
- if (len < 0) {
+ if (len == -1) {
+ VLOG_ERR("Error reading from routing socket: %s", ovs_strerror(errno));
return false;
}
+ *gw = 0;
sa = (struct sockaddr *)(rtm + 1);
for (i = 1; i; i <<= 1) {
if (rtm->rtm_addrs & i) {
namelen = IFNAMSIZ - 1;
memcpy(name, ifp->sdl_data, namelen);
name[namelen] = '\0';
- return true;
+ VLOG_DBG("got ifp %s", name);
+ got_ifp = true;
+ } else if (i == RTA_GATEWAY && sa->sa_family == AF_INET) {
+ const struct sockaddr_in *sin_dst =
+ ALIGNED_CAST(struct sockaddr_in *, sa);
+
+ *gw = sin_dst->sin_addr.s_addr;
+ VLOG_DBG("got gateway " IP_FMT, IP_ARGS(*gw));
}
#if defined(__FreeBSD__)
sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
#endif
}
}
- return false;
+ return got_ifp;
}
uint64_t
}
void
-route_table_register(void)
-{
- if (!register_count)
- {
- pid = getpid();
- }
-
- register_count++;
-}
-
-void
-route_table_unregister(void)
+route_table_init(void)
{
- register_count--;
+ ovs_router_init();
}
void