netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / lib / route-table-bsd.c
1 /*
2  * Copyright (c) 2012 Ed Maste. All rights reserved.
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
19 #include "route-table.h"
20
21 #include <sys/socket.h>
22 #include <sys/types.h>
23
24 #include <net/if.h>
25 #include <net/route.h>
26 #include <net/if_dl.h>
27 #include <netinet/in.h>
28
29 #include <errno.h>
30 #include <poll.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include "ovs-router.h"
35 #include "packets.h"
36 #include "openvswitch/vlog.h"
37 #include "util.h"
38
39 VLOG_DEFINE_THIS_MODULE(route_table_bsd);
40
41 bool
42 route_table_fallback_lookup(ovs_be32 ip, char name[], ovs_be32 *gw)
43 {
44     struct {
45         struct rt_msghdr rtm;
46         char space[512];
47     } rtmsg;
48
49     struct rt_msghdr *rtm = &rtmsg.rtm;
50     struct sockaddr_dl *ifp = NULL;
51     struct sockaddr_in *sin;
52     struct sockaddr *sa;
53     static int seq;
54     int i, namelen, rtsock;
55     ssize_t len;
56     const pid_t pid = getpid();
57     bool got_ifp = false;
58     unsigned int retry_count = 5;  /* arbitrary */
59
60     VLOG_DBG("looking route up for " IP_FMT " pid %" PRIuMAX,
61         IP_ARGS(ip), (uintmax_t)pid);
62
63     rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
64     if (rtsock < 0)
65         return false;
66
67 retry:
68     memset(&rtmsg, 0, sizeof(rtmsg));
69     rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
70     rtm->rtm_version = RTM_VERSION;
71     rtm->rtm_type = RTM_GET;
72     rtm->rtm_addrs = RTA_DST | RTA_IFP;
73     rtm->rtm_seq = ++seq;
74
75     sin = (struct sockaddr_in *)(rtm + 1);
76     sin->sin_len = len = sizeof(struct sockaddr_in);
77     sin->sin_family = AF_INET;
78     sin->sin_addr.s_addr = ip;
79
80     len = write(rtsock, (char *)&rtmsg, rtm->rtm_msglen);
81     if (len == -1) {
82         if (errno == ENOBUFS && retry_count-- > 0) {
83             VLOG_INFO("Recoverable error writing to routing socket: %s",
84                       ovs_strerror(errno));
85             usleep(500 * 1000);  /* arbitrary */
86             goto retry;
87         }
88         VLOG_ERR("Error writing to routing socket: %s", ovs_strerror(errno));
89         close(rtsock);
90         return false;
91     }
92     if (len != rtm->rtm_msglen) {
93         VLOG_ERR("Short write to routing socket");
94         close(rtsock);
95         return false;
96     }
97
98     do {
99         struct pollfd pfd;
100         int ret;
101
102         memset(&pfd, 0, sizeof(pfd));
103         pfd.fd = rtsock;
104         pfd.events = POLLIN;
105         /*
106          * The timeout value below is somehow arbitrary.
107          * It's to detect the lost of routing messages due to
108          * buffer exhaustion etc.  The routing socket is not
109          * reliable.
110          */
111         ret = poll(&pfd, 1, 500);
112         if (ret == -1) {
113             VLOG_ERR("Error polling on routing socket: %s",
114                      ovs_strerror(errno));
115             close(rtsock);
116             return false;
117         }
118         if (ret == 0) {
119             if (retry_count-- > 0) {
120                 VLOG_INFO("Timeout; resending routing message");
121                 goto retry;
122             }
123             close(rtsock);
124             return false;
125         }
126         len = read(rtsock, (char *)&rtmsg, sizeof(rtmsg));
127         if (len > 0) {
128             VLOG_DBG("got rtmsg pid %" PRIuMAX " seq %d",
129                 (uintmax_t)rtmsg.rtm.rtm_pid,
130                 rtmsg.rtm.rtm_seq);
131         }
132     } while (len > 0 && (rtmsg.rtm.rtm_seq != seq ||
133         rtmsg.rtm.rtm_pid != pid));
134     close(rtsock);
135     if (len == -1) {
136         VLOG_ERR("Error reading from routing socket: %s", ovs_strerror(errno));
137         return false;
138     }
139
140     *gw = 0;
141     sa = (struct sockaddr *)(rtm + 1);
142     for (i = 1; i; i <<= 1) {
143         if (rtm->rtm_addrs & i) {
144             if (i == RTA_IFP && sa->sa_family == AF_LINK &&
145               ALIGNED_CAST(struct sockaddr_dl *, sa)->sdl_nlen) {
146                 ifp = ALIGNED_CAST(struct sockaddr_dl *, sa);
147                 namelen = ifp->sdl_nlen;
148                 if (namelen > IFNAMSIZ - 1)
149                     namelen = IFNAMSIZ - 1;
150                 memcpy(name, ifp->sdl_data, namelen);
151                 name[namelen] = '\0';
152                 VLOG_DBG("got ifp %s", name);
153                 got_ifp = true;
154             } else if (i == RTA_GATEWAY && sa->sa_family == AF_INET) {
155                 const struct sockaddr_in *sin_dst =
156                     ALIGNED_CAST(struct sockaddr_in *, sa);
157
158                 *gw = sin_dst->sin_addr.s_addr;
159                 VLOG_DBG("got gateway " IP_FMT, IP_ARGS(*gw));
160             }
161 #if defined(__FreeBSD__)
162             sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
163 #elif defined(__NetBSD__)
164             sa = (struct sockaddr *)((char *)sa + RT_ROUNDUP(sa->sa_len));
165 #else
166 #error unimplemented
167 #endif
168         }
169     }
170     return got_ifp;
171 }
172
173 uint64_t
174 route_table_get_change_seq(void)
175 {
176     return 0;
177 }
178
179 void
180 route_table_init(void)
181 {
182     ovs_router_init();
183 }
184
185 void
186 route_table_run(void)
187 {
188 }
189
190 void
191 route_table_wait(void)
192 {
193 }