]>
Commit | Line | Data |
---|---|---|
9360d9b7 EM |
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 | ||
9da6989c YT |
29 | #include <errno.h> |
30 | #include <poll.h> | |
9360d9b7 EM |
31 | #include <string.h> |
32 | #include <unistd.h> | |
33 | ||
2d2b28d5 | 34 | #include "ovs-router.h" |
36673528 | 35 | #include "packets.h" |
43e2a621 | 36 | #include "openvswitch/vlog.h" |
e29915b2 | 37 | #include "util.h" |
9360d9b7 | 38 | |
36673528 YT |
39 | VLOG_DEFINE_THIS_MODULE(route_table_bsd); |
40 | ||
97d0619c LR |
41 | /* OS X does not define RT_ROUNDUP() or equivalent macro. */ |
42 | #if defined(__MACH__) | |
43 | #define RT_ROUNDUP(l) ((l) > 0 ? ROUND_UP((l), sizeof(long)) : sizeof(long)) | |
44 | #endif | |
45 | ||
9360d9b7 | 46 | bool |
ec6c5379 PS |
47 | route_table_fallback_lookup(const struct in6_addr *ip6_dst, char name[], |
48 | struct in6_addr *gw6) | |
9360d9b7 | 49 | { |
ec6c5379 | 50 | ovs_be32 ip; |
9360d9b7 EM |
51 | struct { |
52 | struct rt_msghdr rtm; | |
53 | char space[512]; | |
54 | } rtmsg; | |
55 | ||
56 | struct rt_msghdr *rtm = &rtmsg.rtm; | |
57 | struct sockaddr_dl *ifp = NULL; | |
58 | struct sockaddr_in *sin; | |
59 | struct sockaddr *sa; | |
60 | static int seq; | |
9da6989c YT |
61 | int i, namelen, rtsock; |
62 | ssize_t len; | |
6595fb00 | 63 | const pid_t pid = getpid(); |
a7701e29 | 64 | bool got_ifp = false; |
9da6989c YT |
65 | unsigned int retry_count = 5; /* arbitrary */ |
66 | ||
ec6c5379 PS |
67 | if (!IN6_IS_ADDR_V4MAPPED(ip6_dst)) { |
68 | return false; | |
69 | } | |
70 | ip = in6_addr_get_mapped_ipv4(ip6_dst); | |
71 | ||
9da6989c YT |
72 | VLOG_DBG("looking route up for " IP_FMT " pid %" PRIuMAX, |
73 | IP_ARGS(ip), (uintmax_t)pid); | |
9360d9b7 EM |
74 | |
75 | rtsock = socket(PF_ROUTE, SOCK_RAW, 0); | |
76 | if (rtsock < 0) | |
77 | return false; | |
78 | ||
9da6989c | 79 | retry: |
9360d9b7 | 80 | memset(&rtmsg, 0, sizeof(rtmsg)); |
9360d9b7 EM |
81 | rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in); |
82 | rtm->rtm_version = RTM_VERSION; | |
83 | rtm->rtm_type = RTM_GET; | |
84 | rtm->rtm_addrs = RTA_DST | RTA_IFP; | |
85 | rtm->rtm_seq = ++seq; | |
86 | ||
87 | sin = (struct sockaddr_in *)(rtm + 1); | |
88 | sin->sin_len = len = sizeof(struct sockaddr_in); | |
89 | sin->sin_family = AF_INET; | |
90 | sin->sin_addr.s_addr = ip; | |
91 | ||
9da6989c YT |
92 | len = write(rtsock, (char *)&rtmsg, rtm->rtm_msglen); |
93 | if (len == -1) { | |
94 | if (errno == ENOBUFS && retry_count-- > 0) { | |
95 | VLOG_INFO("Recoverable error writing to routing socket: %s", | |
96 | ovs_strerror(errno)); | |
97 | usleep(500 * 1000); /* arbitrary */ | |
98 | goto retry; | |
99 | } | |
100 | VLOG_ERR("Error writing to routing socket: %s", ovs_strerror(errno)); | |
101 | close(rtsock); | |
102 | return false; | |
103 | } | |
104 | if (len != rtm->rtm_msglen) { | |
105 | VLOG_ERR("Short write to routing socket"); | |
9360d9b7 EM |
106 | close(rtsock); |
107 | return false; | |
108 | } | |
109 | ||
110 | do { | |
9da6989c YT |
111 | struct pollfd pfd; |
112 | int ret; | |
113 | ||
114 | memset(&pfd, 0, sizeof(pfd)); | |
115 | pfd.fd = rtsock; | |
116 | pfd.events = POLLIN; | |
117 | /* | |
118 | * The timeout value below is somehow arbitrary. | |
119 | * It's to detect the lost of routing messages due to | |
120 | * buffer exhaustion etc. The routing socket is not | |
121 | * reliable. | |
122 | */ | |
123 | ret = poll(&pfd, 1, 500); | |
124 | if (ret == -1) { | |
125 | VLOG_ERR("Error polling on routing socket: %s", | |
126 | ovs_strerror(errno)); | |
127 | close(rtsock); | |
128 | return false; | |
129 | } | |
130 | if (ret == 0) { | |
131 | if (retry_count-- > 0) { | |
132 | VLOG_INFO("Timeout; resending routing message"); | |
133 | goto retry; | |
134 | } | |
135 | close(rtsock); | |
136 | return false; | |
137 | } | |
9360d9b7 | 138 | len = read(rtsock, (char *)&rtmsg, sizeof(rtmsg)); |
36673528 YT |
139 | if (len > 0) { |
140 | VLOG_DBG("got rtmsg pid %" PRIuMAX " seq %d", | |
141 | (uintmax_t)rtmsg.rtm.rtm_pid, | |
142 | rtmsg.rtm.rtm_seq); | |
143 | } | |
9360d9b7 EM |
144 | } while (len > 0 && (rtmsg.rtm.rtm_seq != seq || |
145 | rtmsg.rtm.rtm_pid != pid)); | |
9360d9b7 | 146 | close(rtsock); |
9da6989c YT |
147 | if (len == -1) { |
148 | VLOG_ERR("Error reading from routing socket: %s", ovs_strerror(errno)); | |
9360d9b7 EM |
149 | return false; |
150 | } | |
151 | ||
ec6c5379 | 152 | *gw6 = in6addr_any; |
9360d9b7 EM |
153 | sa = (struct sockaddr *)(rtm + 1); |
154 | for (i = 1; i; i <<= 1) { | |
155 | if (rtm->rtm_addrs & i) { | |
156 | if (i == RTA_IFP && sa->sa_family == AF_LINK && | |
e29915b2 YT |
157 | ALIGNED_CAST(struct sockaddr_dl *, sa)->sdl_nlen) { |
158 | ifp = ALIGNED_CAST(struct sockaddr_dl *, sa); | |
9360d9b7 EM |
159 | namelen = ifp->sdl_nlen; |
160 | if (namelen > IFNAMSIZ - 1) | |
161 | namelen = IFNAMSIZ - 1; | |
162 | memcpy(name, ifp->sdl_data, namelen); | |
163 | name[namelen] = '\0'; | |
36673528 | 164 | VLOG_DBG("got ifp %s", name); |
a7701e29 YT |
165 | got_ifp = true; |
166 | } else if (i == RTA_GATEWAY && sa->sa_family == AF_INET) { | |
167 | const struct sockaddr_in *sin_dst = | |
168 | ALIGNED_CAST(struct sockaddr_in *, sa); | |
169 | ||
ec6c5379 PS |
170 | in6_addr_set_mapped_ipv4(gw6, sin_dst->sin_addr.s_addr); |
171 | VLOG_DBG("got gateway " IP_FMT, IP_ARGS(sin_dst->sin_addr.s_addr)); | |
9360d9b7 | 172 | } |
339f0a19 | 173 | #if defined(__FreeBSD__) |
9360d9b7 | 174 | sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); |
339f0a19 YT |
175 | #elif defined(__NetBSD__) |
176 | sa = (struct sockaddr *)((char *)sa + RT_ROUNDUP(sa->sa_len)); | |
97d0619c LR |
177 | #elif defined(__MACH__) |
178 | sa = (struct sockaddr *)((char *)sa + RT_ROUNDUP(sa->sa_len)); | |
339f0a19 YT |
179 | #else |
180 | #error unimplemented | |
181 | #endif | |
9360d9b7 EM |
182 | } |
183 | } | |
a7701e29 | 184 | return got_ifp; |
9360d9b7 EM |
185 | } |
186 | ||
41ca1e0a AW |
187 | uint64_t |
188 | route_table_get_change_seq(void) | |
189 | { | |
190 | return 0; | |
191 | } | |
192 | ||
9360d9b7 | 193 | void |
b772066f | 194 | route_table_init(void) |
9360d9b7 | 195 | { |
88ffdc93 | 196 | ovs_router_init(); |
9360d9b7 EM |
197 | } |
198 | ||
199 | void | |
200 | route_table_run(void) | |
201 | { | |
202 | } | |
203 | ||
204 | void | |
205 | route_table_wait(void) | |
206 | { | |
207 | } |