Branch data Line data Source code
1 : : /* Copyright (c) 2015, 2016 Red Hat, Inc.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at:
6 : : *
7 : : * http://www.apache.org/licenses/LICENSE-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License.
14 : : */
15 : :
16 : : #include <config.h>
17 : :
18 : : #include "pinctrl.h"
19 : :
20 : : #include "coverage.h"
21 : : #include "csum.h"
22 : : #include "dirs.h"
23 : : #include "dp-packet.h"
24 : : #include "flow.h"
25 : : #include "lport.h"
26 : : #include "nx-match.h"
27 : : #include "ovn-controller.h"
28 : : #include "lib/packets.h"
29 : : #include "lib/sset.h"
30 : : #include "openvswitch/ofp-actions.h"
31 : : #include "openvswitch/ofp-msgs.h"
32 : : #include "openvswitch/ofp-print.h"
33 : : #include "openvswitch/ofp-util.h"
34 : : #include "openvswitch/vlog.h"
35 : :
36 : : #include "lib/dhcp.h"
37 : : #include "ovn-controller.h"
38 : : #include "ovn/actions.h"
39 : : #include "ovn/lib/logical-fields.h"
40 : : #include "ovn/lib/ovn-dhcp.h"
41 : : #include "ovn/lib/ovn-util.h"
42 : : #include "poll-loop.h"
43 : : #include "rconn.h"
44 : : #include "socket-util.h"
45 : : #include "timeval.h"
46 : : #include "vswitch-idl.h"
47 : :
48 : 94 : VLOG_DEFINE_THIS_MODULE(pinctrl);
49 : :
50 : : /* OpenFlow connection to the switch. */
51 : : static struct rconn *swconn;
52 : :
53 : : /* Last seen sequence number for 'swconn'. When this differs from
54 : : * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
55 : : static unsigned int conn_seq_no;
56 : :
57 : : static void pinctrl_handle_put_mac_binding(const struct flow *md,
58 : : const struct flow *headers,
59 : : bool is_arp);
60 : : static void init_put_mac_bindings(void);
61 : : static void destroy_put_mac_bindings(void);
62 : : static void run_put_mac_bindings(struct controller_ctx *,
63 : : const struct lport_index *lports);
64 : : static void wait_put_mac_bindings(struct controller_ctx *);
65 : : static void flush_put_mac_bindings(void);
66 : :
67 : : static void init_send_garps(void);
68 : : static void destroy_send_garps(void);
69 : : static void send_garp_wait(void);
70 : : static void send_garp_run(const struct ovsrec_bridge *,
71 : : const char *chassis_id,
72 : : const struct lport_index *lports,
73 : : struct hmap *local_datapaths);
74 : : static void pinctrl_handle_nd_na(const struct flow *ip_flow,
75 : : const struct match *md,
76 : : struct ofpbuf *userdata);
77 : : static void reload_metadata(struct ofpbuf *ofpacts,
78 : : const struct match *md);
79 : :
80 : 1930 : COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);
81 : :
82 : : void
83 : 44 : pinctrl_init(void)
84 : : {
85 : 44 : swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
86 : 44 : conn_seq_no = 0;
87 : 44 : init_put_mac_bindings();
88 : 44 : init_send_garps();
89 : 44 : }
90 : :
91 : : static ovs_be32
92 : 369 : queue_msg(struct ofpbuf *msg)
93 : : {
94 : 369 : const struct ofp_header *oh = msg->data;
95 : 369 : ovs_be32 xid = oh->xid;
96 : :
97 : 369 : rconn_send(swconn, msg, NULL);
98 : 369 : return xid;
99 : : }
100 : :
101 : : /* Sets up 'swconn', a newly (re)connected connection to a switch. */
102 : : static void
103 : 46 : pinctrl_setup(struct rconn *swconn)
104 : : {
105 : : /* Fetch the switch configuration. The response later will allow us to
106 : : * change the miss_send_len to UINT16_MAX, so that we can enable
107 : : * asynchronous messages. */
108 : 46 : queue_msg(ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST,
109 : 46 : rconn_get_version(swconn), 0));
110 : :
111 : : /* Set a packet-in format that supports userdata. */
112 : 46 : queue_msg(ofputil_make_set_packet_in_format(rconn_get_version(swconn),
113 : : NXPIF_NXT_PACKET_IN2));
114 : 46 : }
115 : :
116 : : static void
117 : 46 : set_switch_config(struct rconn *swconn,
118 : : const struct ofputil_switch_config *config)
119 : : {
120 : 46 : enum ofp_version version = rconn_get_version(swconn);
121 : 46 : struct ofpbuf *request = ofputil_encode_set_config(config, version);
122 : 46 : queue_msg(request);
123 : 46 : }
124 : :
125 : : static void
126 : 217 : pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
127 : : struct ofpbuf *userdata)
128 : : {
129 : : /* This action only works for IP packets, and the switch should only send
130 : : * us IP packets this way, but check here just to be sure. */
131 [ - + ]: 217 : if (ip_flow->dl_type != htons(ETH_TYPE_IP)) {
132 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
133 [ # # ]: 0 : VLOG_WARN_RL(&rl, "ARP action on non-IP packet (Ethertype %"PRIx16")",
134 : : ntohs(ip_flow->dl_type));
135 : 0 : return;
136 : : }
137 : :
138 : : /* Compose an ARP packet. */
139 : : uint64_t packet_stub[128 / 8];
140 : : struct dp_packet packet;
141 : 217 : dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
142 : 217 : compose_arp__(&packet);
143 : :
144 : 217 : struct eth_header *eth = dp_packet_l2(&packet);
145 : 217 : eth->eth_dst = ip_flow->dl_dst;
146 : 217 : eth->eth_src = ip_flow->dl_src;
147 : :
148 : 217 : struct arp_eth_header *arp = dp_packet_l3(&packet);
149 : 217 : arp->ar_op = htons(ARP_OP_REQUEST);
150 : 217 : arp->ar_sha = ip_flow->dl_src;
151 : 217 : put_16aligned_be32(&arp->ar_spa, ip_flow->nw_src);
152 : 217 : arp->ar_tha = eth_addr_zero;
153 : 217 : put_16aligned_be32(&arp->ar_tpa, ip_flow->nw_dst);
154 : :
155 [ - + ]: 217 : if (ip_flow->vlan_tci & htons(VLAN_CFI)) {
156 : 0 : eth_push_vlan(&packet, htons(ETH_TYPE_VLAN_8021Q), ip_flow->vlan_tci);
157 : : }
158 : :
159 : : /* Compose actions.
160 : : *
161 : : * First, copy metadata from 'md' into the packet-out via "set_field"
162 : : * actions, then add actions from 'userdata'.
163 : : */
164 : : uint64_t ofpacts_stub[4096 / 8];
165 : 217 : struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
166 : 217 : enum ofp_version version = rconn_get_version(swconn);
167 : :
168 : 217 : reload_metadata(&ofpacts, md);
169 : 217 : enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, version, &ofpacts);
170 [ - + ]: 217 : if (error) {
171 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
172 [ # # ]: 0 : VLOG_WARN_RL(&rl, "failed to parse arp actions (%s)",
173 : : ofperr_to_string(error));
174 : 0 : goto exit;
175 : : }
176 : :
177 : 868 : struct ofputil_packet_out po = {
178 : 217 : .packet = dp_packet_data(&packet),
179 : 217 : .packet_len = dp_packet_size(&packet),
180 : : .buffer_id = UINT32_MAX,
181 : : .in_port = OFPP_CONTROLLER,
182 : 217 : .ofpacts = ofpacts.data,
183 : 217 : .ofpacts_len = ofpacts.size,
184 : : };
185 : 217 : enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
186 : 217 : queue_msg(ofputil_encode_packet_out(&po, proto));
187 : :
188 : : exit:
189 : 217 : dp_packet_uninit(&packet);
190 : 217 : ofpbuf_uninit(&ofpacts);
191 : : }
192 : :
193 : : static void
194 : 3 : pinctrl_handle_put_dhcp_opts(
195 : : struct dp_packet *pkt_in, struct ofputil_packet_in *pin,
196 : : struct ofpbuf *userdata, struct ofpbuf *continuation)
197 : : {
198 : 3 : enum ofp_version version = rconn_get_version(swconn);
199 : 3 : enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
200 : 3 : struct dp_packet *pkt_out_ptr = NULL;
201 : 3 : uint32_t success = 0;
202 : :
203 : : /* Parse result field. */
204 : : const struct mf_field *f;
205 : 3 : enum ofperr ofperr = nx_pull_header(userdata, &f, NULL);
206 [ - + ]: 3 : if (ofperr) {
207 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
208 [ # # ]: 0 : VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr));
209 : 0 : goto exit;
210 : : }
211 : :
212 : : /* Parse result offset and offer IP. */
213 : 3 : ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp);
214 : 3 : ovs_be32 *offer_ip = ofpbuf_try_pull(userdata, sizeof *offer_ip);
215 [ + - ][ - + ]: 3 : if (!ofsp || !offer_ip) {
216 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
217 [ # # ]: 0 : VLOG_WARN_RL(&rl, "offset or offer_ip not present in the userdata");
218 : 0 : goto exit;
219 : : }
220 : :
221 : : /* Check that the result is valid and writable. */
222 : 3 : struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = 1 };
223 : 3 : ofperr = mf_check_dst(&dst, NULL);
224 [ - + ]: 3 : if (ofperr) {
225 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
226 [ # # ]: 0 : VLOG_WARN_RL(&rl, "bad result bit (%s)", ofperr_to_string(ofperr));
227 : 0 : goto exit;
228 : : }
229 : :
230 [ - + ]: 3 : if (!userdata->size) {
231 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
232 [ # # ]: 0 : VLOG_WARN_RL(&rl, "DHCP options not present in the userdata");
233 : 0 : goto exit;
234 : : }
235 : :
236 : : /* Validate the DHCP request packet.
237 : : * Format of the DHCP packet is
238 : : * ------------------------------------------------------------------------
239 : : *| UDP HEADER | DHCP HEADER | 4 Byte DHCP Cookie | DHCP OPTIONS(var len)|
240 : : * ------------------------------------------------------------------------
241 : : */
242 [ - + ]: 3 : if (dp_packet_l4_size(pkt_in) < (UDP_HEADER_LEN +
243 : : sizeof (struct dhcp_header) + sizeof(uint32_t) + 3)) {
244 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
245 [ # # ]: 0 : VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet recieved");
246 : 0 : goto exit;
247 : : }
248 : :
249 : 3 : struct dhcp_header const *in_dhcp_data = dp_packet_get_udp_payload(pkt_in);
250 [ - + ]: 3 : if (in_dhcp_data->op != DHCP_OP_REQUEST) {
251 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
252 [ # # ]: 0 : VLOG_WARN_RL(&rl, "Invalid opcode in the DHCP packet : %d",
253 : : in_dhcp_data->op);
254 : 0 : goto exit;
255 : : }
256 : :
257 : : /* DHCP options follow the DHCP header. The first 4 bytes of the DHCP
258 : : * options is the DHCP magic cookie followed by the actual DHCP options.
259 : : */
260 : 3 : const uint8_t *in_dhcp_opt =
261 : 3 : (const uint8_t *)dp_packet_get_udp_payload(pkt_in) +
262 : : sizeof (struct dhcp_header);
263 : :
264 : 3 : ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE);
265 [ - + ]: 3 : if (memcmp(in_dhcp_opt, &magic_cookie, sizeof(ovs_be32))) {
266 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
267 [ # # ]: 0 : VLOG_WARN_RL(&rl, "DHCP magic cookie not present in the DHCP packet");
268 : 0 : goto exit;
269 : : }
270 : :
271 : 3 : in_dhcp_opt += 4;
272 : : /* Check that the DHCP Message Type (opt 53) is present or not with
273 : : * valid values - DHCP_MSG_DISCOVER or DHCP_MSG_REQUEST as the first
274 : : * DHCP option.
275 : : */
276 [ + - ][ + - ]: 3 : if (!(in_dhcp_opt[0] == DHCP_OPT_MSG_TYPE && in_dhcp_opt[1] == 1 && (
[ + + ]
277 [ + + ]: 2 : in_dhcp_opt[2] == DHCP_MSG_DISCOVER ||
278 : 2 : in_dhcp_opt[2] == DHCP_MSG_REQUEST))) {
279 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
280 [ + - ]: 1 : VLOG_WARN_RL(&rl, "Invalid DHCP message type : opt code = %d,"
281 : : " opt value = %d", in_dhcp_opt[0], in_dhcp_opt[2]);
282 : 1 : goto exit;
283 : : }
284 : :
285 : : uint8_t msg_type;
286 [ + + ]: 2 : if (in_dhcp_opt[2] == DHCP_MSG_DISCOVER) {
287 : 1 : msg_type = DHCP_MSG_OFFER;
288 : : } else {
289 : 1 : msg_type = DHCP_MSG_ACK;
290 : : }
291 : :
292 : : /* Frame the DHCP reply packet
293 : : * Total DHCP options length will be options stored in the userdata +
294 : : * 16 bytes.
295 : : *
296 : : * --------------------------------------------------------------
297 : : *| 4 Bytes (dhcp cookie) | 3 Bytes (option type) | DHCP options |
298 : : * --------------------------------------------------------------
299 : : *| 4 Bytes padding | 1 Byte (option end 0xFF ) | 4 Bytes padding|
300 : : * --------------------------------------------------------------
301 : : */
302 : 2 : uint16_t new_l4_size = UDP_HEADER_LEN + DHCP_HEADER_LEN + \
303 : 2 : userdata->size + 16;
304 : 2 : size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
305 : :
306 : : struct dp_packet pkt_out;
307 : 2 : dp_packet_init(&pkt_out, new_packet_size);
308 : 2 : dp_packet_clear(&pkt_out);
309 : 2 : dp_packet_prealloc_tailroom(&pkt_out, new_packet_size);
310 : 2 : pkt_out_ptr = &pkt_out;
311 : :
312 : : /* Copy the L2 and L3 headers from the pkt_in as they would remain same*/
313 : 2 : dp_packet_put(
314 : 2 : &pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs), pkt_in->l4_ofs);
315 : :
316 : 2 : pkt_out.l2_5_ofs = pkt_in->l2_5_ofs;
317 : 2 : pkt_out.l2_pad_size = pkt_in->l2_pad_size;
318 : 2 : pkt_out.l3_ofs = pkt_in->l3_ofs;
319 : 2 : pkt_out.l4_ofs = pkt_in->l4_ofs;
320 : :
321 : 2 : struct udp_header *udp = dp_packet_put(
322 : 2 : &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN);
323 : :
324 : 2 : struct dhcp_header *dhcp_data = dp_packet_put(
325 : 2 : &pkt_out, dp_packet_pull(pkt_in, DHCP_HEADER_LEN), DHCP_HEADER_LEN);
326 : 2 : dhcp_data->op = DHCP_OP_REPLY;
327 : 2 : dhcp_data->yiaddr = *offer_ip;
328 : 2 : dp_packet_put(&pkt_out, &magic_cookie, sizeof(ovs_be32));
329 : :
330 : 2 : uint8_t *out_dhcp_opts = dp_packet_put_zeros(&pkt_out,
331 : 2 : userdata->size + 12);
332 : : /* DHCP option - type */
333 : 2 : out_dhcp_opts[0] = DHCP_OPT_MSG_TYPE;
334 : 2 : out_dhcp_opts[1] = 1;
335 : 2 : out_dhcp_opts[2] = msg_type;
336 : 2 : out_dhcp_opts += 3;
337 : :
338 : 2 : memcpy(out_dhcp_opts, userdata->data, userdata->size);
339 : 2 : out_dhcp_opts += userdata->size;
340 : : /* Padding */
341 : 2 : out_dhcp_opts += 4;
342 : : /* End */
343 : 2 : out_dhcp_opts[0] = DHCP_OPT_END;
344 : :
345 : 2 : udp->udp_len = htons(new_l4_size);
346 : :
347 : 2 : struct ip_header *out_ip = dp_packet_l3(&pkt_out);
348 : 2 : out_ip->ip_tot_len = htons(pkt_out.l4_ofs - pkt_out.l3_ofs + new_l4_size);
349 : 2 : udp->udp_csum = 0;
350 : : /* Checksum needs to be initialized to zero. */
351 : 2 : out_ip->ip_csum = 0;
352 : 2 : out_ip->ip_csum = csum(out_ip, sizeof *out_ip);
353 : :
354 : 2 : pin->packet = dp_packet_data(&pkt_out);
355 : 2 : pin->packet_len = dp_packet_size(&pkt_out);
356 : :
357 : 2 : success = 1;
358 : : exit:
359 [ + - ]: 3 : if (!ofperr) {
360 : : union mf_subvalue sv;
361 : 3 : sv.u8_val = success;
362 : 3 : mf_write_subfield(&dst, &sv, &pin->flow_metadata);
363 : : }
364 : 3 : queue_msg(ofputil_encode_resume(pin, continuation, proto));
365 [ + + ]: 3 : if (pkt_out_ptr) {
366 : 2 : dp_packet_uninit(pkt_out_ptr);
367 : : }
368 : 3 : }
369 : :
370 : : static bool
371 : 1 : compose_out_dhcpv6_opts(struct ofpbuf *userdata,
372 : : struct ofpbuf *out_dhcpv6_opts, ovs_be32 iaid)
373 : : {
374 [ + + ]: 3 : while (userdata->size) {
375 : 2 : struct dhcp_opt6_header *userdata_opt = ofpbuf_try_pull(
376 : : userdata, sizeof *userdata_opt);
377 [ - + ]: 2 : if (!userdata_opt) {
378 : 0 : return false;
379 : : }
380 : :
381 : 2 : uint8_t *userdata_opt_data = ofpbuf_try_pull(userdata,
382 : 2 : userdata_opt->len);
383 [ - + ]: 2 : if (!userdata_opt_data) {
384 : 0 : return false;
385 : : }
386 : :
387 [ + + - - : 2 : switch (userdata_opt->code) {
- ]
388 : : case DHCPV6_OPT_SERVER_ID_CODE:
389 : : {
390 : : /* The Server Identifier option carries a DUID
391 : : * identifying a server between a client and a server.
392 : : * See RFC 3315 Sec 9 and Sec 22.3.
393 : : *
394 : : * We use DUID Based on Link-layer Address [DUID-LL].
395 : : */
396 : :
397 : 1 : struct dhcpv6_opt_server_id *opt_server_id = ofpbuf_put_zeros(
398 : : out_dhcpv6_opts, sizeof *opt_server_id);
399 : :
400 : 1 : opt_server_id->opt.code = htons(DHCPV6_OPT_SERVER_ID_CODE);
401 : 1 : opt_server_id->opt.len = htons(userdata_opt->len + 4);
402 : 1 : opt_server_id->duid_type = htons(DHCPV6_DUID_LL);
403 : 1 : opt_server_id->hw_type = htons(DHCPV6_HW_TYPE_ETH);
404 : 1 : memcpy(&opt_server_id->mac, userdata_opt_data,
405 : : sizeof(struct eth_addr));
406 : 1 : break;
407 : : }
408 : :
409 : : case DHCPV6_OPT_IA_ADDR_CODE:
410 : : {
411 [ - + ]: 1 : if (userdata_opt->len != sizeof(struct in6_addr)) {
412 : 0 : return false;
413 : : }
414 : :
415 : : /* IA Address option is used to specify IPv6 addresses associated
416 : : * with an IA_NA or IA_TA. The IA Address option must be
417 : : * encapsulated in the Options field of an IA_NA or IA_TA option.
418 : : *
419 : : * We will encapsulate the IA Address within the IA_NA option.
420 : : * Please see RFC 3315 section 22.5 and 22.6
421 : : */
422 : 1 : struct dhcpv6_opt_ia_na *opt_ia_na = ofpbuf_put_zeros(
423 : : out_dhcpv6_opts, sizeof *opt_ia_na);
424 : 1 : opt_ia_na->opt.code = htons(DHCPV6_OPT_IA_NA_CODE);
425 : : /* IA_NA length (in bytes)-
426 : : * IAID - 4
427 : : * T1 - 4
428 : : * T2 - 4
429 : : * IA Address - sizeof(struct dhcpv6_opt_ia_addr)
430 : : */
431 : 1 : opt_ia_na->opt.len = htons(12 + sizeof(struct dhcpv6_opt_ia_addr));
432 : 1 : opt_ia_na->iaid = iaid;
433 : : /* Set the lifetime of the address(es) to infinity */
434 : 1 : opt_ia_na->t1 = OVS_BE32_MAX;
435 : 1 : opt_ia_na->t2 = OVS_BE32_MAX;
436 : :
437 : 1 : struct dhcpv6_opt_ia_addr *opt_ia_addr = ofpbuf_put_zeros(
438 : : out_dhcpv6_opts, sizeof *opt_ia_addr);
439 : 1 : opt_ia_addr->opt.code = htons(DHCPV6_OPT_IA_ADDR_CODE);
440 : 1 : opt_ia_addr->opt.len = htons(userdata_opt->len + 8);
441 : 1 : memcpy(opt_ia_addr->ipv6.s6_addr, userdata_opt_data,
442 : 1 : userdata_opt->len);
443 : 1 : opt_ia_addr->t1 = OVS_BE32_MAX;
444 : 1 : opt_ia_addr->t2 = OVS_BE32_MAX;
445 : 1 : break;
446 : : }
447 : :
448 : : case DHCPV6_OPT_DNS_SERVER_CODE:
449 : : {
450 : 0 : struct dhcpv6_opt_header *opt_dns = ofpbuf_put_zeros(
451 : : out_dhcpv6_opts, sizeof *opt_dns);
452 : 0 : opt_dns->code = htons(DHCPV6_OPT_DNS_SERVER_CODE);
453 : 0 : opt_dns->len = htons(userdata_opt->len);
454 : 0 : ofpbuf_put(out_dhcpv6_opts, userdata_opt_data, userdata_opt->len);
455 : 0 : break;
456 : : }
457 : :
458 : : case DHCPV6_OPT_DOMAIN_SEARCH_CODE:
459 : : {
460 : 0 : struct dhcpv6_opt_header *opt_dsl = ofpbuf_put_zeros(
461 : : out_dhcpv6_opts, sizeof *opt_dsl);
462 : 0 : opt_dsl->code = htons(DHCPV6_OPT_DOMAIN_SEARCH_CODE);
463 : 0 : opt_dsl->len = htons(userdata_opt->len + 2);
464 : 0 : uint8_t *data = ofpbuf_put_zeros(out_dhcpv6_opts,
465 : 0 : userdata_opt->len + 2);
466 : 0 : *data = userdata_opt->len;
467 : 0 : memcpy(data + 1, userdata_opt_data, userdata_opt->len);
468 : 0 : break;
469 : : }
470 : :
471 : : default:
472 : 0 : return false;
473 : : }
474 : : }
475 : 1 : return true;
476 : : }
477 : :
478 : : static void
479 : 2 : pinctrl_handle_put_dhcpv6_opts(
480 : : struct dp_packet *pkt_in, struct ofputil_packet_in *pin,
481 : : struct ofpbuf *userdata, struct ofpbuf *continuation OVS_UNUSED)
482 : : {
483 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
484 : 2 : enum ofp_version version = rconn_get_version(swconn);
485 : 2 : enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
486 : 2 : struct dp_packet *pkt_out_ptr = NULL;
487 : 2 : uint32_t success = 0;
488 : :
489 : : /* Parse result field. */
490 : : const struct mf_field *f;
491 : 2 : enum ofperr ofperr = nx_pull_header(userdata, &f, NULL);
492 [ - + ]: 2 : if (ofperr) {
493 [ # # ]: 0 : VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr));
494 : 0 : goto exit;
495 : : }
496 : :
497 : : /* Parse result offset. */
498 : 2 : ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp);
499 [ - + ]: 2 : if (!ofsp) {
500 [ # # ]: 0 : VLOG_WARN_RL(&rl, "offset not present in the userdata");
501 : 0 : goto exit;
502 : : }
503 : :
504 : : /* Check that the result is valid and writable. */
505 : 2 : struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = 1 };
506 : 2 : ofperr = mf_check_dst(&dst, NULL);
507 [ - + ]: 2 : if (ofperr) {
508 [ # # ]: 0 : VLOG_WARN_RL(&rl, "bad result bit (%s)", ofperr_to_string(ofperr));
509 : 0 : goto exit;
510 : : }
511 : :
512 [ - + ]: 2 : if (!userdata->size) {
513 [ # # ]: 0 : VLOG_WARN_RL(&rl, "DHCPv6 options not present in the userdata");
514 : 0 : goto exit;
515 : : }
516 : :
517 : 2 : struct udp_header *in_udp = dp_packet_l4(pkt_in);
518 : 2 : const uint8_t *in_dhcpv6_data = dp_packet_get_udp_payload(pkt_in);
519 : : uint8_t out_dhcpv6_msg_type;
520 [ + - + ]: 2 : switch(*in_dhcpv6_data) {
521 : : case DHCPV6_MSG_TYPE_SOLICIT:
522 : 1 : out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_ADVT;
523 : 1 : break;
524 : :
525 : : case DHCPV6_MSG_TYPE_REQUEST:
526 : : case DHCPV6_MSG_TYPE_CONFIRM:
527 : : case DHCPV6_MSG_TYPE_DECLINE:
528 : 0 : out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY;
529 : 0 : break;
530 : :
531 : : default:
532 : : /* Invalid or unsupported DHCPv6 message type */
533 : 1 : goto exit;
534 : : }
535 : :
536 : : /* Skip 4 bytes (message type (1 byte) + transaction ID (3 bytes). */
537 : 1 : in_dhcpv6_data += 4;
538 : : /* We need to extract IAID from the IA-NA option of the client's DHCPv6
539 : : * solicit/request/confirm packet and copy the same IAID in the Server's
540 : : * response. */
541 : 1 : ovs_be32 iaid = 0;
542 : 1 : struct dhcpv6_opt_header const *in_opt_client_id = NULL;
543 : 1 : size_t udp_len = ntohs(in_udp->udp_len);
544 : 1 : size_t l4_len = dp_packet_l4_size(pkt_in);
545 : 1 : uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len);
546 [ + + ]: 3 : while (in_dhcpv6_data < end) {
547 : 2 : struct dhcpv6_opt_header const *in_opt =
548 : : (struct dhcpv6_opt_header *)in_dhcpv6_data;
549 [ + + - ]: 2 : switch(ntohs(in_opt->code)) {
550 : : case DHCPV6_OPT_IA_NA_CODE:
551 : : {
552 : 1 : struct dhcpv6_opt_ia_na *opt_ia_na = (
553 : : struct dhcpv6_opt_ia_na *)in_opt;
554 : 1 : iaid = opt_ia_na->iaid;
555 : 1 : break;
556 : : }
557 : :
558 : : case DHCPV6_OPT_CLIENT_ID_CODE:
559 : 1 : in_opt_client_id = in_opt;
560 : 1 : break;
561 : :
562 : : default:
563 : 0 : break;
564 : : }
565 : 2 : in_dhcpv6_data += sizeof *in_opt + ntohs(in_opt->len);
566 : : }
567 : :
568 [ - + ]: 1 : if (!in_opt_client_id) {
569 [ # # ]: 0 : VLOG_WARN_RL(&rl, "DHCPv6 option - Client id not present in the "
570 : : " DHCPv6 packet");
571 : 0 : goto exit;
572 : : }
573 : :
574 [ - + ]: 1 : if (!iaid) {
575 [ # # ]: 0 : VLOG_WARN_RL(&rl, "DHCPv6 option - IA NA not present in the "
576 : : " DHCPv6 packet");
577 : 0 : goto exit;
578 : : }
579 : :
580 : : uint64_t out_ofpacts_dhcpv6_opts_stub[256 / 8];
581 : 1 : struct ofpbuf out_dhcpv6_opts =
582 : : OFPBUF_STUB_INITIALIZER(out_ofpacts_dhcpv6_opts_stub);
583 : :
584 [ - + ]: 1 : if (!compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, iaid)) {
585 [ # # ]: 0 : VLOG_WARN_RL(&rl, "Invalid userdata");
586 : 0 : goto exit;
587 : : }
588 : :
589 : 1 : uint16_t new_l4_size
590 : : = (UDP_HEADER_LEN + 4 + sizeof *in_opt_client_id +
591 : 1 : ntohs(in_opt_client_id->len) + out_dhcpv6_opts.size);
592 : 1 : size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
593 : :
594 : : struct dp_packet pkt_out;
595 : 1 : dp_packet_init(&pkt_out, new_packet_size);
596 : 1 : dp_packet_clear(&pkt_out);
597 : 1 : dp_packet_prealloc_tailroom(&pkt_out, new_packet_size);
598 : 1 : pkt_out_ptr = &pkt_out;
599 : :
600 : : /* Copy L2 and L3 headers from pkt_in. */
601 : 1 : dp_packet_put(&pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs),
602 : 1 : pkt_in->l4_ofs);
603 : :
604 : 1 : pkt_out.l2_5_ofs = pkt_in->l2_5_ofs;
605 : 1 : pkt_out.l2_pad_size = pkt_in->l2_pad_size;
606 : 1 : pkt_out.l3_ofs = pkt_in->l3_ofs;
607 : 1 : pkt_out.l4_ofs = pkt_in->l4_ofs;
608 : :
609 : : /* Pull the DHCPv6 message type and transaction id from the pkt_in.
610 : : * Need to preserve the transaction id in the DHCPv6 reply packet. */
611 : 1 : struct udp_header *out_udp = dp_packet_put(
612 : 1 : &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN);
613 : 1 : uint8_t *out_dhcpv6 = dp_packet_put(&pkt_out, dp_packet_pull(pkt_in, 4), 4);
614 : :
615 : : /* Set the proper DHCPv6 message type. */
616 : 1 : *out_dhcpv6 = out_dhcpv6_msg_type;
617 : :
618 : : /* Copy the Client Identifier. */
619 : 1 : dp_packet_put(&pkt_out, in_opt_client_id,
620 : 1 : sizeof *in_opt_client_id + ntohs(in_opt_client_id->len));
621 : :
622 : : /* Copy the DHCPv6 Options. */
623 : 1 : dp_packet_put(&pkt_out, out_dhcpv6_opts.data, out_dhcpv6_opts.size);
624 : 1 : out_udp->udp_len = htons(new_l4_size);
625 : 1 : out_udp->udp_csum = 0;
626 : :
627 : 1 : struct ovs_16aligned_ip6_hdr *out_ip6 = dp_packet_l3(&pkt_out);
628 : 1 : out_ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = out_udp->udp_len;
629 : :
630 : : uint32_t csum;
631 : 1 : csum = packet_csum_pseudoheader6(dp_packet_l3(&pkt_out));
632 : 2 : csum = csum_continue(csum, out_udp, dp_packet_size(&pkt_out) -
633 : 2 : ((const unsigned char *)out_udp -
634 : 1 : (const unsigned char *)dp_packet_l2(&pkt_out)));
635 : 1 : out_udp->udp_csum = csum_finish(csum);
636 [ - + ]: 1 : if (!out_udp->udp_csum) {
637 : 0 : out_udp->udp_csum = htons(0xffff);
638 : : }
639 : :
640 : 1 : pin->packet = dp_packet_data(&pkt_out);
641 : 1 : pin->packet_len = dp_packet_size(&pkt_out);
642 : 1 : ofpbuf_uninit(&out_dhcpv6_opts);
643 : 1 : success = 1;
644 : : exit:
645 [ + - ]: 2 : if (!ofperr) {
646 : : union mf_subvalue sv;
647 : 2 : sv.u8_val = success;
648 : 2 : mf_write_subfield(&dst, &sv, &pin->flow_metadata);
649 : : }
650 : 2 : queue_msg(ofputil_encode_resume(pin, continuation, proto));
651 : 2 : dp_packet_uninit(pkt_out_ptr);
652 : 2 : }
653 : :
654 : : static void
655 : 453 : process_packet_in(const struct ofp_header *msg)
656 : : {
657 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
658 : :
659 : : struct ofputil_packet_in pin;
660 : : struct ofpbuf continuation;
661 : 453 : enum ofperr error = ofputil_decode_packet_in(msg, true, &pin,
662 : : NULL, NULL, &continuation);
663 : :
664 [ - + ]: 453 : if (error) {
665 [ # # ]: 0 : VLOG_WARN_RL(&rl, "error decoding packet-in: %s",
666 : : ofperr_to_string(error));
667 : 0 : return;
668 : : }
669 [ - + ]: 453 : if (pin.reason != OFPR_ACTION) {
670 : 0 : return;
671 : : }
672 : :
673 : 453 : struct ofpbuf userdata = ofpbuf_const_initializer(pin.userdata,
674 : : pin.userdata_len);
675 : 453 : const struct action_header *ah = ofpbuf_pull(&userdata, sizeof *ah);
676 [ - + ]: 453 : if (!ah) {
677 [ # # ]: 0 : VLOG_WARN_RL(&rl, "packet-in userdata lacks action header");
678 : 0 : return;
679 : : }
680 : :
681 : : struct dp_packet packet;
682 : 453 : dp_packet_use_const(&packet, pin.packet, pin.packet_len);
683 : : struct flow headers;
684 : 453 : flow_extract(&packet, &headers);
685 : :
686 [ + + + + : 453 : switch (ntohl(ah->opcode)) {
+ + - ]
687 : : case ACTION_OPCODE_ARP:
688 : 217 : pinctrl_handle_arp(&headers, &pin.flow_metadata, &userdata);
689 : 217 : break;
690 : :
691 : : case ACTION_OPCODE_PUT_ARP:
692 : 216 : pinctrl_handle_put_mac_binding(&pin.flow_metadata.flow, &headers,
693 : : true);
694 : 216 : break;
695 : :
696 : : case ACTION_OPCODE_PUT_DHCP_OPTS:
697 : 3 : pinctrl_handle_put_dhcp_opts(&packet, &pin, &userdata, &continuation);
698 : 3 : break;
699 : :
700 : : case ACTION_OPCODE_ND_NA:
701 : 1 : pinctrl_handle_nd_na(&headers, &pin.flow_metadata, &userdata);
702 : 1 : break;
703 : :
704 : : case ACTION_OPCODE_PUT_ND:
705 : 14 : pinctrl_handle_put_mac_binding(&pin.flow_metadata.flow, &headers,
706 : : false);
707 : 14 : break;
708 : :
709 : : case ACTION_OPCODE_PUT_DHCPV6_OPTS:
710 : 2 : pinctrl_handle_put_dhcpv6_opts(&packet, &pin, &userdata,
711 : : &continuation);
712 : 2 : break;
713 : :
714 : : default:
715 [ # # ]: 0 : VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32,
716 : : ntohl(ah->opcode));
717 : 453 : break;
718 : : }
719 : : }
720 : :
721 : : static void
722 : 910 : pinctrl_recv(const struct ofp_header *oh, enum ofptype type)
723 : : {
724 [ + + ]: 910 : if (type == OFPTYPE_ECHO_REQUEST) {
725 : 6 : queue_msg(make_echo_reply(oh));
726 [ + + ]: 904 : } else if (type == OFPTYPE_GET_CONFIG_REPLY) {
727 : : /* Enable asynchronous messages (see "Asynchronous Messages" in
728 : : * DESIGN.md for more information). */
729 : : struct ofputil_switch_config config;
730 : :
731 : 46 : ofputil_decode_get_config_reply(oh, &config);
732 : 46 : config.miss_send_len = UINT16_MAX;
733 : 46 : set_switch_config(swconn, &config);
734 [ + + ]: 858 : } else if (type == OFPTYPE_PACKET_IN) {
735 : 453 : process_packet_in(oh);
736 [ + - ][ + - ]: 405 : } else if (type != OFPTYPE_ECHO_REPLY && type != OFPTYPE_BARRIER_REPLY) {
737 [ - + ]: 405 : if (VLOG_IS_DBG_ENABLED()) {
738 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
739 : :
740 : 0 : char *s = ofp_to_string(oh, ntohs(oh->length), 2);
741 : :
742 [ # # ]: 0 : VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s);
743 : 0 : free(s);
744 : : }
745 : : }
746 : 910 : }
747 : :
748 : : void
749 : 3167 : pinctrl_run(struct controller_ctx *ctx, const struct lport_index *lports,
750 : : const struct ovsrec_bridge *br_int,
751 : : const char *chassis_id,
752 : : struct hmap *local_datapaths)
753 : : {
754 : 3167 : char *target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), br_int->name);
755 [ + + ]: 3167 : if (strcmp(target, rconn_get_target(swconn))) {
756 [ + - ]: 44 : VLOG_INFO("%s: connecting to switch", target);
757 : 44 : rconn_connect(swconn, target, target);
758 : : }
759 : 3167 : free(target);
760 : :
761 : 3167 : rconn_run(swconn);
762 : :
763 [ + + ]: 3167 : if (rconn_is_connected(swconn)) {
764 [ + + ]: 3070 : if (conn_seq_no != rconn_get_connection_seqno(swconn)) {
765 : 46 : pinctrl_setup(swconn);
766 : 46 : conn_seq_no = rconn_get_connection_seqno(swconn);
767 : 46 : flush_put_mac_bindings();
768 : : }
769 : :
770 : : /* Process a limited number of messages per call. */
771 [ + - ]: 3980 : for (int i = 0; i < 50; i++) {
772 : 3980 : struct ofpbuf *msg = rconn_recv(swconn);
773 [ + + ]: 3980 : if (!msg) {
774 : 3070 : break;
775 : : }
776 : :
777 : 910 : const struct ofp_header *oh = msg->data;
778 : : enum ofptype type;
779 : :
780 : 910 : ofptype_decode(&type, oh);
781 : 910 : pinctrl_recv(oh, type);
782 : 910 : ofpbuf_delete(msg);
783 : : }
784 : : }
785 : :
786 : 3167 : run_put_mac_bindings(ctx, lports);
787 : 3167 : send_garp_run(br_int, chassis_id, lports, local_datapaths);
788 : 3167 : }
789 : :
790 : : void
791 : 3167 : pinctrl_wait(struct controller_ctx *ctx)
792 : : {
793 : 3167 : wait_put_mac_bindings(ctx);
794 : 3167 : rconn_run_wait(swconn);
795 : 3167 : rconn_recv_wait(swconn);
796 : 3167 : send_garp_wait();
797 : 3167 : }
798 : :
799 : : void
800 : 44 : pinctrl_destroy(void)
801 : : {
802 : 44 : rconn_destroy(swconn);
803 : 44 : destroy_put_mac_bindings();
804 : 44 : destroy_send_garps();
805 : 44 : }
806 : :
807 : : /* Implementation of the "put_arp" and "put_nd" OVN actions. These
808 : : * actions send a packet to ovn-controller, using the flow as an API
809 : : * (see actions.h for details). This code implements the actions by
810 : : * updating the MAC_Binding table in the southbound database.
811 : : *
812 : : * This code could be a lot simpler if the database could always be updated,
813 : : * but in fact we can only update it when ctx->ovnsb_idl_txn is nonnull. Thus,
814 : : * we buffer up a few put_mac_bindings (but we don't keep them longer
815 : : * than 1 second) and apply them whenever a database transaction is
816 : : * available. */
817 : :
818 : : /* Buffered "put_mac_binding" operation. */
819 : : struct put_mac_binding {
820 : : struct hmap_node hmap_node; /* In 'put_mac_bindings'. */
821 : :
822 : : long long int timestamp; /* In milliseconds. */
823 : :
824 : : /* Key. */
825 : : uint32_t dp_key;
826 : : uint32_t port_key;
827 : : char ip_s[INET6_ADDRSTRLEN + 1];
828 : :
829 : : /* Value. */
830 : : struct eth_addr mac;
831 : : };
832 : :
833 : : /* Contains "struct put_mac_binding"s. */
834 : : static struct hmap put_mac_bindings;
835 : :
836 : : static void
837 : 44 : init_put_mac_bindings(void)
838 : : {
839 : 44 : hmap_init(&put_mac_bindings);
840 : 44 : }
841 : :
842 : : static void
843 : 44 : destroy_put_mac_bindings(void)
844 : : {
845 : 44 : flush_put_mac_bindings();
846 : 44 : hmap_destroy(&put_mac_bindings);
847 : 44 : }
848 : :
849 : : static struct put_mac_binding *
850 : 230 : pinctrl_find_put_mac_binding(uint32_t dp_key, uint32_t port_key,
851 : : const char *ip_s, uint32_t hash)
852 : : {
853 : : struct put_mac_binding *pa;
854 [ - + ][ - + ]: 230 : HMAP_FOR_EACH_WITH_HASH (pa, hmap_node, hash, &put_mac_bindings) {
855 [ # # ]: 0 : if (pa->dp_key == dp_key
856 [ # # ]: 0 : && pa->port_key == port_key
857 [ # # ]: 0 : && !strcmp(pa->ip_s, ip_s)) {
858 : 0 : return pa;
859 : : }
860 : : }
861 : 230 : return NULL;
862 : : }
863 : :
864 : : static void
865 : 230 : pinctrl_handle_put_mac_binding(const struct flow *md,
866 : : const struct flow *headers, bool is_arp)
867 : : {
868 : 230 : uint32_t dp_key = ntohll(md->metadata);
869 : 230 : uint32_t port_key = md->regs[MFF_LOG_INPORT - MFF_REG0];
870 : : char ip_s[INET6_ADDRSTRLEN];
871 : :
872 [ + + ]: 230 : if (is_arp) {
873 : 216 : ovs_be32 ip = htonl(md->regs[0]);
874 : 216 : inet_ntop(AF_INET, &ip, ip_s, sizeof(ip_s));
875 : : } else {
876 : 14 : ovs_be128 ip6 = hton128(flow_get_xxreg(md, 0));
877 : 14 : inet_ntop(AF_INET6, &ip6, ip_s, sizeof(ip_s));
878 : : }
879 : 230 : uint32_t hash = hash_string(ip_s, hash_2words(dp_key, port_key));
880 : 230 : struct put_mac_binding *pmb
881 : : = pinctrl_find_put_mac_binding(dp_key, port_key, ip_s, hash);
882 [ + - ]: 230 : if (!pmb) {
883 [ - + ]: 230 : if (hmap_count(&put_mac_bindings) >= 1000) {
884 : 0 : COVERAGE_INC(pinctrl_drop_put_mac_binding);
885 : 0 : return;
886 : : }
887 : :
888 : 230 : pmb = xmalloc(sizeof *pmb);
889 : 230 : hmap_insert(&put_mac_bindings, &pmb->hmap_node, hash);
890 : 230 : pmb->dp_key = dp_key;
891 : 230 : pmb->port_key = port_key;
892 : 230 : ovs_strlcpy(pmb->ip_s, ip_s, sizeof pmb->ip_s);
893 : : }
894 : 230 : pmb->timestamp = time_msec();
895 : 230 : pmb->mac = headers->dl_src;
896 : : }
897 : :
898 : : static void
899 : 230 : run_put_mac_binding(struct controller_ctx *ctx,
900 : : const struct lport_index *lports,
901 : : const struct put_mac_binding *pmb)
902 : : {
903 [ - + ]: 230 : if (time_msec() > pmb->timestamp + 1000) {
904 : 4 : return;
905 : : }
906 : :
907 : : /* Convert logical datapath and logical port key into lport. */
908 : 230 : const struct sbrec_port_binding *pb
909 : 230 : = lport_lookup_by_key(lports, pmb->dp_key, pmb->port_key);
910 [ - + ]: 230 : if (!pb) {
911 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
912 : :
913 [ # # ]: 0 : VLOG_WARN_RL(&rl, "unknown logical port with datapath %"PRIu32" "
914 : : "and port %"PRIu32, pmb->dp_key, pmb->port_key);
915 : 0 : return;
916 : : }
917 : :
918 : : /* Convert ethernet argument to string form for database. */
919 : : char mac_string[ETH_ADDR_STRLEN + 1];
920 : 1380 : snprintf(mac_string, sizeof mac_string,
921 : 1380 : ETH_ADDR_FMT, ETH_ADDR_ARGS(pmb->mac));
922 : :
923 : : /* Check for an update an existing IP-MAC binding for this logical
924 : : * port.
925 : : *
926 : : * XXX This is not very efficient. */
927 : : const struct sbrec_mac_binding *b;
928 [ + + ]: 23263 : SBREC_MAC_BINDING_FOR_EACH (b, ctx->ovnsb_idl) {
929 [ + + ]: 23037 : if (!strcmp(b->logical_port, pb->logical_port)
930 [ + + ]: 2488 : && !strcmp(b->ip, pmb->ip_s)) {
931 [ - + ]: 4 : if (strcmp(b->mac, mac_string)) {
932 : 0 : sbrec_mac_binding_set_mac(b, mac_string);
933 : : }
934 : 4 : return;
935 : : }
936 : : }
937 : :
938 : : /* Add new IP-MAC binding for this logical port. */
939 : 226 : b = sbrec_mac_binding_insert(ctx->ovnsb_idl_txn);
940 : 226 : sbrec_mac_binding_set_logical_port(b, pb->logical_port);
941 : 226 : sbrec_mac_binding_set_ip(b, pmb->ip_s);
942 : 226 : sbrec_mac_binding_set_mac(b, mac_string);
943 : 226 : sbrec_mac_binding_set_datapath(b, pb->datapath);
944 : : }
945 : :
946 : : static void
947 : 3167 : run_put_mac_bindings(struct controller_ctx *ctx,
948 : : const struct lport_index *lports)
949 : : {
950 [ + + ]: 3167 : if (!ctx->ovnsb_idl_txn) {
951 : 497 : return;
952 : : }
953 : :
954 : : const struct put_mac_binding *pmb;
955 [ + + ][ - + ]: 2900 : HMAP_FOR_EACH (pmb, hmap_node, &put_mac_bindings) {
956 : 230 : run_put_mac_binding(ctx, lports, pmb);
957 : : }
958 : 2670 : flush_put_mac_bindings();
959 : : }
960 : :
961 : : static void
962 : 3167 : wait_put_mac_bindings(struct controller_ctx *ctx)
963 : : {
964 [ + + ][ - + ]: 3167 : if (ctx->ovnsb_idl_txn && !hmap_is_empty(&put_mac_bindings)) {
965 : 0 : poll_immediate_wake();
966 : : }
967 : 3167 : }
968 : :
969 : : static void
970 : 2760 : flush_put_mac_bindings(void)
971 : : {
972 : : struct put_mac_binding *pmb;
973 [ + + ][ - + ]: 2990 : HMAP_FOR_EACH_POP (pmb, hmap_node, &put_mac_bindings) {
[ + + ]
974 : 230 : free(pmb);
975 : : }
976 : 2760 : }
977 : :
978 : : /*
979 : : * Send gratuitous ARP for vif on localnet.
980 : : *
981 : : * When a new vif on localnet is added, gratuitous ARPs are sent announcing
982 : : * the port's mac,ip mapping. On localnet, such announcements are needed for
983 : : * switches and routers on the broadcast segment to update their port-mac
984 : : * and ARP tables.
985 : : */
986 : : struct garp_data {
987 : : struct eth_addr ea; /* Ethernet address of port. */
988 : : ovs_be32 ipv4; /* Ipv4 address of port. */
989 : : long long int announce_time; /* Next announcement in ms. */
990 : : int backoff; /* Backoff for the next announcement. */
991 : : ofp_port_t ofport; /* ofport used to output this GARP. */
992 : : };
993 : :
994 : : /* Contains GARPs to be sent. */
995 : : static struct shash send_garp_data;
996 : :
997 : : /* Next GARP announcement in ms. */
998 : : static long long int send_garp_time;
999 : :
1000 : : static void
1001 : 44 : init_send_garps(void)
1002 : : {
1003 : 44 : shash_init(&send_garp_data);
1004 : 44 : send_garp_time = LLONG_MAX;
1005 : 44 : }
1006 : :
1007 : : static void
1008 : 44 : destroy_send_garps(void)
1009 : : {
1010 : 44 : shash_destroy_free_data(&send_garp_data);
1011 : 44 : }
1012 : :
1013 : : static void
1014 : 3 : add_garp(const char *name, ofp_port_t ofport,
1015 : : const struct eth_addr ea, ovs_be32 ip)
1016 : : {
1017 : 3 : struct garp_data *garp = xmalloc(sizeof *garp);
1018 : 3 : garp->ea = ea;
1019 : 3 : garp->ipv4 = ip;
1020 : 3 : garp->announce_time = time_msec() + 1000;
1021 : 3 : garp->backoff = 1;
1022 : 3 : garp->ofport = ofport;
1023 : 3 : shash_add(&send_garp_data, name, garp);
1024 : 3 : }
1025 : :
1026 : : /* Add or update a vif for which GARPs need to be announced. */
1027 : : static void
1028 : 1194 : send_garp_update(const struct sbrec_port_binding *binding_rec,
1029 : : struct simap *localnet_ofports, struct hmap *local_datapaths,
1030 : : struct shash *nat_addresses)
1031 : : {
1032 : : /* Find the localnet ofport to send this GARP. */
1033 : 1194 : struct local_datapath *ld
1034 : 1194 : = get_local_datapath(local_datapaths,
1035 : 1194 : binding_rec->datapath->tunnel_key);
1036 [ + + ][ + + ]: 1194 : if (!ld || !ld->localnet_port) {
1037 : 635 : return;
1038 : : }
1039 : 559 : ofp_port_t ofport = u16_to_ofp(simap_get(localnet_ofports,
1040 : 559 : ld->localnet_port->logical_port));
1041 : :
1042 : 559 : volatile struct garp_data *garp = NULL;
1043 : : /* Update GARP for NAT IP if it exists. */
1044 [ + + ]: 559 : if (!strcmp(binding_rec->type, "l3gateway")) {
1045 : 8 : struct lport_addresses *laddrs = NULL;
1046 : 8 : laddrs = shash_find_data(nat_addresses, binding_rec->logical_port);
1047 [ - + ]: 8 : if (!laddrs) {
1048 : 0 : return;
1049 : : }
1050 : : int i;
1051 [ + + ]: 16 : for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
1052 : 8 : char *name = xasprintf("%s-%s", binding_rec->logical_port,
1053 : 8 : laddrs->ipv4_addrs[i].addr_s);
1054 : 8 : garp = shash_find_data(&send_garp_data, name);
1055 [ + + ]: 8 : if (garp) {
1056 : 7 : garp->ofport = ofport;
1057 : : } else {
1058 : 1 : add_garp(name, ofport, laddrs->ea, laddrs->ipv4_addrs[i].addr);
1059 : : }
1060 : 8 : free(name);
1061 : : }
1062 : 8 : return;
1063 : : }
1064 : :
1065 : : /* Update GARP for vif if it exists. */
1066 : 551 : garp = shash_find_data(&send_garp_data, binding_rec->logical_port);
1067 [ + + ]: 551 : if (garp) {
1068 : 10 : garp->ofport = ofport;
1069 : 10 : return;
1070 : : }
1071 : :
1072 : : /* Add GARP for new vif. */
1073 : : int i;
1074 [ + + ]: 1031 : for (i = 0; i < binding_rec->n_mac; i++) {
1075 : : struct lport_addresses laddrs;
1076 [ + - ]: 492 : if (!extract_lsp_addresses(binding_rec->mac[i], &laddrs)
1077 [ + + ]: 492 : || !laddrs.n_ipv4_addrs) {
1078 : 490 : continue;
1079 : : }
1080 : :
1081 : 2 : add_garp(binding_rec->logical_port, ofport,
1082 : 2 : laddrs.ea, laddrs.ipv4_addrs[0].addr);
1083 : :
1084 : 2 : destroy_lport_addresses(&laddrs);
1085 : 2 : break;
1086 : : }
1087 : : }
1088 : :
1089 : : /* Remove a vif from GARP announcements. */
1090 : : static void
1091 : 2 : send_garp_delete(const char *lport)
1092 : : {
1093 : 2 : struct garp_data *garp = shash_find_and_delete(&send_garp_data, lport);
1094 : 2 : free(garp);
1095 : 2 : }
1096 : :
1097 : : static long long int
1098 : 21 : send_garp(struct garp_data *garp, long long int current_time)
1099 : : {
1100 [ + + ]: 21 : if (current_time < garp->announce_time) {
1101 : 19 : return garp->announce_time;
1102 : : }
1103 : :
1104 : : /* Compose a GARP request packet. */
1105 : : uint64_t packet_stub[128 / 8];
1106 : : struct dp_packet packet;
1107 : 2 : dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
1108 : 2 : compose_arp(&packet, ARP_OP_REQUEST, garp->ea, eth_addr_zero,
1109 : : true, garp->ipv4, garp->ipv4);
1110 : :
1111 : : /* Compose actions. The garp request is output on localnet ofport. */
1112 : : uint64_t ofpacts_stub[4096 / 8];
1113 : 2 : struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
1114 : 2 : enum ofp_version version = rconn_get_version(swconn);
1115 : 2 : ofpact_put_OUTPUT(&ofpacts)->port = garp->ofport;
1116 : :
1117 : 8 : struct ofputil_packet_out po = {
1118 : 2 : .packet = dp_packet_data(&packet),
1119 : 2 : .packet_len = dp_packet_size(&packet),
1120 : : .buffer_id = UINT32_MAX,
1121 : : .in_port = OFPP_CONTROLLER,
1122 : 2 : .ofpacts = ofpacts.data,
1123 : 2 : .ofpacts_len = ofpacts.size,
1124 : : };
1125 : 2 : enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
1126 : 2 : queue_msg(ofputil_encode_packet_out(&po, proto));
1127 : 2 : dp_packet_uninit(&packet);
1128 : 2 : ofpbuf_uninit(&ofpacts);
1129 : :
1130 : : /* Set the next announcement. At most 5 announcements are sent for a
1131 : : * vif. */
1132 [ + - ]: 2 : if (garp->backoff < 16) {
1133 : 2 : garp->backoff *= 2;
1134 : 2 : garp->announce_time = current_time + garp->backoff * 1000;
1135 : : } else {
1136 : 0 : garp->announce_time = LLONG_MAX;
1137 : : }
1138 : 21 : return garp->announce_time;
1139 : : }
1140 : :
1141 : : /* Get localnet vifs, local l3gw ports and ofport for localnet patch ports. */
1142 : : static void
1143 : 3167 : get_localnet_vifs_l3gwports(const struct ovsrec_bridge *br_int,
1144 : : const char *this_chassis_id,
1145 : : const struct lport_index *lports,
1146 : : struct hmap *local_datapaths,
1147 : : struct sset *localnet_vifs,
1148 : : struct simap *localnet_ofports,
1149 : : struct sset *local_l3gw_ports)
1150 : : {
1151 [ + + ]: 47616 : for (int i = 0; i < br_int->n_ports; i++) {
1152 : 44449 : const struct ovsrec_port *port_rec = br_int->ports[i];
1153 [ + + ]: 44449 : if (!strcmp(port_rec->name, br_int->name)) {
1154 : 3167 : continue;
1155 : : }
1156 : 41282 : const char *chassis_id = smap_get(&port_rec->external_ids,
1157 : : "ovn-chassis-id");
1158 [ + + ][ - + ]: 41282 : if (chassis_id && !strcmp(chassis_id, this_chassis_id)) {
1159 : 0 : continue;
1160 : : }
1161 : 41282 : const char *localnet = smap_get(&port_rec->external_ids,
1162 : : "ovn-localnet-port");
1163 : 41282 : const char *l3_gateway_port = smap_get(&port_rec->external_ids,
1164 : : "ovn-l3gateway-port");
1165 [ + + ]: 82564 : for (int j = 0; j < port_rec->n_interfaces; j++) {
1166 : 41282 : const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
1167 [ + + ]: 41282 : if (!iface_rec->n_ofport) {
1168 : 1100 : continue;
1169 : : }
1170 [ + + ]: 40182 : if (localnet) {
1171 : 327 : int64_t ofport = iface_rec->ofport[0];
1172 [ + - ][ - + ]: 327 : if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) {
1173 : 0 : continue;
1174 : : }
1175 : 327 : simap_put(localnet_ofports, localnet, ofport);
1176 : 327 : continue;
1177 : : }
1178 [ + + ]: 39855 : if (l3_gateway_port) {
1179 : 643 : sset_add(local_l3gw_ports, l3_gateway_port);
1180 : 643 : continue;
1181 : : }
1182 : 39212 : const char *iface_id = smap_get(&iface_rec->external_ids,
1183 : : "iface-id");
1184 [ + + ]: 39212 : if (!iface_id) {
1185 : 26447 : continue;
1186 : : }
1187 : 12765 : const struct sbrec_port_binding *pb
1188 : : = lport_lookup_by_name(lports, iface_id);
1189 [ + + ]: 12765 : if (!pb) {
1190 : 379 : continue;
1191 : : }
1192 : 12386 : struct local_datapath *ld
1193 : 12386 : = get_local_datapath(local_datapaths,
1194 : 12386 : pb->datapath->tunnel_key);
1195 [ + - ][ + + ]: 12386 : if (ld && ld->localnet_port) {
1196 : 551 : sset_add(localnet_vifs, iface_id);
1197 : : }
1198 : : }
1199 : : }
1200 : 3167 : }
1201 : :
1202 : : static void
1203 : 3167 : get_nat_addresses_and_keys(struct sset *nat_address_keys,
1204 : : struct sset *local_l3gw_ports,
1205 : : const struct lport_index *lports,
1206 : : struct shash *nat_addresses)
1207 : : {
1208 : : const char *gw_port;
1209 [ + + ][ + + ]: 3810 : SSET_FOR_EACH(gw_port, local_l3gw_ports) {
[ + + ]
1210 : 643 : const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
1211 : : gw_port);
1212 [ - + ]: 643 : if (!pb) {
1213 : 0 : continue;
1214 : : }
1215 : 643 : const char *nat_addresses_options = smap_get(&pb->options,
1216 : : "nat-addresses");
1217 [ + + ]: 643 : if (!nat_addresses_options) {
1218 : 617 : continue;
1219 : : }
1220 : :
1221 : 26 : struct lport_addresses *laddrs = xmalloc(sizeof *laddrs);
1222 [ - + ]: 26 : if (!extract_lsp_addresses(nat_addresses_options, laddrs)) {
1223 : 0 : free(laddrs);
1224 : 0 : continue;
1225 : : }
1226 : : int i;
1227 [ + + ]: 52 : for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
1228 : 26 : char *name = xasprintf("%s-%s", pb->logical_port,
1229 : 26 : laddrs->ipv4_addrs[i].addr_s);
1230 : 26 : sset_add(nat_address_keys, name);
1231 : 26 : free(name);
1232 : : }
1233 : 26 : shash_add(nat_addresses, pb->logical_port, laddrs);
1234 : : }
1235 : 3167 : }
1236 : :
1237 : : static void
1238 : 3167 : send_garp_wait(void)
1239 : : {
1240 : 3167 : poll_timer_wait_until(send_garp_time);
1241 : 3167 : }
1242 : :
1243 : : static void
1244 : 3167 : send_garp_run(const struct ovsrec_bridge *br_int, const char *chassis_id,
1245 : : const struct lport_index *lports,
1246 : : struct hmap *local_datapaths)
1247 : : {
1248 : 3167 : struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs);
1249 : 3167 : struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports);
1250 : 3167 : struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys);
1251 : 3167 : struct simap localnet_ofports = SIMAP_INITIALIZER(&localnet_ofports);
1252 : : struct shash nat_addresses;
1253 : :
1254 : 3167 : shash_init(&nat_addresses);
1255 : :
1256 : 3167 : get_localnet_vifs_l3gwports(br_int, chassis_id, lports, local_datapaths,
1257 : : &localnet_vifs, &localnet_ofports, &local_l3gw_ports);
1258 : :
1259 : 3167 : get_nat_addresses_and_keys(&nat_ip_keys, &local_l3gw_ports, lports,
1260 : : &nat_addresses);
1261 : : /* For deleted ports and deleted nat ips, remove from send_garp_data. */
1262 : : struct shash_node *iter, *next;
1263 [ + + ][ - + ]: 3187 : SHASH_FOR_EACH_SAFE (iter, next, &send_garp_data) {
[ + + ]
1264 [ + + + + ]: 30 : if (!sset_contains(&localnet_vifs, iter->name) &&
1265 : 10 : !sset_contains(&nat_ip_keys, iter->name)) {
1266 : 2 : send_garp_delete(iter->name);
1267 : : }
1268 : : }
1269 : :
1270 : : /* Update send_garp_data. */
1271 : : const char *iface_id;
1272 [ + + ][ + + ]: 3718 : SSET_FOR_EACH (iface_id, &localnet_vifs) {
[ + + ]
1273 : 551 : const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
1274 : : iface_id);
1275 [ + - ]: 551 : if (pb) {
1276 : 551 : send_garp_update(pb, &localnet_ofports, local_datapaths,
1277 : : &nat_addresses);
1278 : : }
1279 : : }
1280 : :
1281 : : /* Update send_garp_data for nat-addresses. */
1282 : : const char *gw_port;
1283 [ + + ][ + + ]: 3810 : SSET_FOR_EACH (gw_port, &local_l3gw_ports) {
[ + + ]
1284 : 643 : const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
1285 : : gw_port);
1286 [ + - ]: 643 : if (pb) {
1287 : 643 : send_garp_update(pb, &localnet_ofports, local_datapaths,
1288 : : &nat_addresses);
1289 : : }
1290 : : }
1291 : :
1292 : : /* Send GARPs, and update the next announcement. */
1293 : 3167 : long long int current_time = time_msec();
1294 : 3167 : send_garp_time = LLONG_MAX;
1295 [ + + ][ - + ]: 3188 : SHASH_FOR_EACH (iter, &send_garp_data) {
1296 : 21 : long long int next_announce = send_garp(iter->data, current_time);
1297 [ + - ]: 21 : if (send_garp_time > next_announce) {
1298 : 21 : send_garp_time = next_announce;
1299 : : }
1300 : : }
1301 : 3167 : sset_destroy(&localnet_vifs);
1302 : 3167 : sset_destroy(&local_l3gw_ports);
1303 : 3167 : simap_destroy(&localnet_ofports);
1304 : :
1305 [ + + ][ - + ]: 3193 : SHASH_FOR_EACH_SAFE (iter, next, &nat_addresses) {
[ + + ]
1306 : 26 : struct lport_addresses *laddrs = iter->data;
1307 : 26 : destroy_lport_addresses(laddrs);
1308 : 26 : shash_delete(&nat_addresses, iter);
1309 : 26 : free(laddrs);
1310 : : }
1311 : 3167 : shash_destroy(&nat_addresses);
1312 : :
1313 : 3167 : sset_destroy(&nat_ip_keys);
1314 : 3167 : }
1315 : :
1316 : : static void
1317 : 218 : reload_metadata(struct ofpbuf *ofpacts, const struct match *md)
1318 : : {
1319 : 218 : enum mf_field_id md_fields[] = {
1320 : : #if FLOW_N_REGS == 16
1321 : : MFF_REG0,
1322 : : MFF_REG1,
1323 : : MFF_REG2,
1324 : : MFF_REG3,
1325 : : MFF_REG4,
1326 : : MFF_REG5,
1327 : : MFF_REG6,
1328 : : MFF_REG7,
1329 : : MFF_REG8,
1330 : : MFF_REG9,
1331 : : MFF_REG10,
1332 : : MFF_REG11,
1333 : : MFF_REG12,
1334 : : MFF_REG13,
1335 : : MFF_REG14,
1336 : : MFF_REG15,
1337 : : #else
1338 : : #error
1339 : : #endif
1340 : : MFF_METADATA,
1341 : : };
1342 [ + + ]: 3924 : for (size_t i = 0; i < ARRAY_SIZE(md_fields); i++) {
1343 : 3706 : const struct mf_field *field = mf_from_id(md_fields[i]);
1344 [ + + ]: 3706 : if (!mf_is_all_wild(field, &md->wc)) {
1345 : : union mf_value value;
1346 : 1305 : mf_get_value(field, &md->flow, &value);
1347 : 1305 : ofpact_put_set_field(ofpacts, field, &value, NULL);
1348 : : }
1349 : : }
1350 : 218 : }
1351 : :
1352 : : static void
1353 : 1 : pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md,
1354 : : struct ofpbuf *userdata)
1355 : : {
1356 : : /* This action only works for IPv6 ND packets, and the switch should only
1357 : : * send us ND packets this way, but check here just to be sure. */
1358 [ - + ]: 1 : if (!is_nd(ip_flow, NULL)) {
1359 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
1360 [ # # ]: 0 : VLOG_WARN_RL(&rl, "NA action on non-ND packet");
1361 : 0 : return;
1362 : : }
1363 : :
1364 : 1 : enum ofp_version version = rconn_get_version(swconn);
1365 : 1 : enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
1366 : :
1367 : : uint64_t packet_stub[128 / 8];
1368 : : struct dp_packet packet;
1369 : 1 : dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
1370 : :
1371 : : /* xxx These flags are not exactly correct. Look at section 7.2.4
1372 : : * xxx of RFC 4861. For example, we need to set ND_RSO_ROUTER for
1373 : : * xxx router's interfaces and ND_RSO_SOLICITED only if it was
1374 : : * xxx requested. */
1375 : 1 : compose_nd_na(&packet, ip_flow->dl_dst, ip_flow->dl_src,
1376 : : &ip_flow->nd_target, &ip_flow->ipv6_src,
1377 : : htonl(ND_RSO_SOLICITED | ND_RSO_OVERRIDE));
1378 : :
1379 : : /* Reload previous packet metadata. */
1380 : : uint64_t ofpacts_stub[4096 / 8];
1381 : 1 : struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
1382 : 1 : reload_metadata(&ofpacts, md);
1383 : :
1384 : 1 : enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size,
1385 : : version, &ofpacts);
1386 [ - + ]: 1 : if (error) {
1387 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
1388 [ # # ]: 0 : VLOG_WARN_RL(&rl, "failed to parse actions for 'na' (%s)",
1389 : : ofperr_to_string(error));
1390 : 0 : goto exit;
1391 : : }
1392 : :
1393 : 4 : struct ofputil_packet_out po = {
1394 : 1 : .packet = dp_packet_data(&packet),
1395 : 1 : .packet_len = dp_packet_size(&packet),
1396 : : .buffer_id = UINT32_MAX,
1397 : : .in_port = OFPP_CONTROLLER,
1398 : 1 : .ofpacts = ofpacts.data,
1399 : 1 : .ofpacts_len = ofpacts.size,
1400 : : };
1401 : :
1402 : 1 : queue_msg(ofputil_encode_packet_out(&po, proto));
1403 : :
1404 : : exit:
1405 : 1 : dp_packet_uninit(&packet);
1406 : 1 : ofpbuf_uninit(&ofpacts);
1407 : : }
|