Branch data Line data Source code
1 : : /* Copyright (c) 2015, 2016 Nicira, 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 : : #include "bitmap.h"
18 : : #include "byte-order.h"
19 : : #include "dirs.h"
20 : : #include "flow.h"
21 : : #include "hash.h"
22 : : #include "lflow.h"
23 : : #include "ofctrl.h"
24 : : #include "openflow/openflow.h"
25 : : #include "openvswitch/dynamic-string.h"
26 : : #include "openvswitch/hmap.h"
27 : : #include "openvswitch/list.h"
28 : : #include "openvswitch/match.h"
29 : : #include "openvswitch/ofp-actions.h"
30 : : #include "openvswitch/ofp-msgs.h"
31 : : #include "openvswitch/ofp-parse.h"
32 : : #include "openvswitch/ofp-print.h"
33 : : #include "openvswitch/ofp-util.h"
34 : : #include "openvswitch/ofpbuf.h"
35 : : #include "openvswitch/vlog.h"
36 : : #include "ovn-controller.h"
37 : : #include "ovn/actions.h"
38 : : #include "poll-loop.h"
39 : : #include "physical.h"
40 : : #include "rconn.h"
41 : : #include "socket-util.h"
42 : : #include "util.h"
43 : : #include "vswitch-idl.h"
44 : :
45 : 94 : VLOG_DEFINE_THIS_MODULE(ofctrl);
46 : :
47 : : /* An OpenFlow flow. */
48 : : struct ovn_flow {
49 : : struct hmap_node hmap_node; /* For match based hashing. */
50 : : struct ovs_list list_node; /* For handling lists of flows. */
51 : :
52 : : /* Key. */
53 : : uint8_t table_id;
54 : : uint16_t priority;
55 : : struct match match;
56 : :
57 : : /* Data. */
58 : : struct ofpact *ofpacts;
59 : : size_t ofpacts_len;
60 : : };
61 : :
62 : : static uint32_t ovn_flow_hash(const struct ovn_flow *);
63 : : static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
64 : : const struct ovn_flow *target);
65 : : static char *ovn_flow_to_string(const struct ovn_flow *);
66 : : static void ovn_flow_log(const struct ovn_flow *, const char *action);
67 : : static void ovn_flow_destroy(struct ovn_flow *);
68 : :
69 : : /* OpenFlow connection to the switch. */
70 : : static struct rconn *swconn;
71 : :
72 : : /* Last seen sequence number for 'swconn'. When this differs from
73 : : * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
74 : : static unsigned int seqno;
75 : :
76 : : /* Connection state machine. */
77 : : #define STATES \
78 : : STATE(S_NEW) \
79 : : STATE(S_TLV_TABLE_REQUESTED) \
80 : : STATE(S_TLV_TABLE_MOD_SENT) \
81 : : STATE(S_CLEAR_FLOWS) \
82 : : STATE(S_UPDATE_FLOWS)
83 : : enum ofctrl_state {
84 : : #define STATE(NAME) NAME,
85 : : STATES
86 : : #undef STATE
87 : : };
88 : :
89 : : /* An in-flight update to the switch's flow table.
90 : : *
91 : : * When we receive a barrier reply from the switch with the given 'xid', we
92 : : * know that the switch is caught up to northbound database sequence number
93 : : * 'nb_cfg' (and make that available to the client via ofctrl_get_cur_cfg(), so
94 : : * that it can store it into our Chassis record's nb_cfg column). */
95 : : struct ofctrl_flow_update {
96 : : struct ovs_list list_node; /* In 'flow_updates'. */
97 : : ovs_be32 xid; /* OpenFlow transaction ID for barrier. */
98 : : int64_t nb_cfg; /* Northbound database sequence number. */
99 : : };
100 : :
101 : : static struct ofctrl_flow_update *
102 : 1640 : ofctrl_flow_update_from_list_node(const struct ovs_list *list_node)
103 : : {
104 : 1640 : return CONTAINER_OF(list_node, struct ofctrl_flow_update, list_node);
105 : : }
106 : :
107 : : /* Currently in-flight updates. */
108 : : static struct ovs_list flow_updates;
109 : :
110 : : /* nb_cfg of latest committed flow update. */
111 : : static int64_t cur_cfg;
112 : :
113 : : /* Current state. */
114 : : static enum ofctrl_state state;
115 : :
116 : : /* Transaction IDs for messages in flight to the switch. */
117 : : static ovs_be32 xid, xid2;
118 : :
119 : : /* Counter for in-flight OpenFlow messages on 'swconn'. We only send a new
120 : : * round of flow table modifications to the switch when the counter falls to
121 : : * zero, to avoid unbounded buffering. */
122 : : static struct rconn_packet_counter *tx_counter;
123 : :
124 : : /* Flow table of "struct ovn_flow"s, that holds the flow table currently
125 : : * installed in the switch. */
126 : : static struct hmap installed_flows;
127 : :
128 : : /* A reference to the group_table. */
129 : : static struct group_table *groups;
130 : :
131 : : /* MFF_* field ID for our Geneve option. In S_TLV_TABLE_MOD_SENT, this is
132 : : * the option we requested (we don't know whether we obtained it yet). In
133 : : * S_CLEAR_FLOWS or S_UPDATE_FLOWS, this is really the option we have. */
134 : : static enum mf_field_id mff_ovn_geneve;
135 : :
136 : : static ovs_be32 queue_msg(struct ofpbuf *);
137 : :
138 : : static struct ofpbuf *encode_flow_mod(struct ofputil_flow_mod *);
139 : :
140 : : static struct ofpbuf *encode_group_mod(const struct ofputil_group_mod *);
141 : :
142 : : static void ovn_flow_table_clear(struct hmap *flow_table);
143 : : static void ovn_flow_table_destroy(struct hmap *flow_table);
144 : :
145 : : static void ofctrl_recv(const struct ofp_header *, enum ofptype);
146 : :
147 : : void
148 : 44 : ofctrl_init(struct group_table *group_table)
149 : : {
150 : 44 : swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
151 : 44 : tx_counter = rconn_packet_counter_create();
152 : 44 : hmap_init(&installed_flows);
153 : 44 : ovs_list_init(&flow_updates);
154 : 44 : groups = group_table;
155 : 44 : }
156 : :
157 : : /* S_NEW, for a new connection.
158 : : *
159 : : * Sends NXT_TLV_TABLE_REQUEST and transitions to
160 : : * S_TLV_TABLE_REQUESTED. */
161 : :
162 : : static void
163 : 46 : run_S_NEW(void)
164 : : {
165 : 46 : struct ofpbuf *buf = ofpraw_alloc(OFPRAW_NXT_TLV_TABLE_REQUEST,
166 : 46 : rconn_get_version(swconn), 0);
167 : 46 : xid = queue_msg(buf);
168 : 46 : state = S_TLV_TABLE_REQUESTED;
169 : 46 : }
170 : :
171 : : static void
172 : 0 : recv_S_NEW(const struct ofp_header *oh OVS_UNUSED,
173 : : enum ofptype type OVS_UNUSED)
174 : : {
175 : 0 : OVS_NOT_REACHED();
176 : : }
177 : :
178 : : /* S_TLV_TABLE_REQUESTED, when NXT_TLV_TABLE_REQUEST has been sent
179 : : * and we're waiting for a reply.
180 : : *
181 : : * If we receive an NXT_TLV_TABLE_REPLY:
182 : : *
183 : : * - If it contains our tunnel metadata option, assign its field ID to
184 : : * mff_ovn_geneve and transition to S_CLEAR_FLOWS.
185 : : *
186 : : * - Otherwise, if there is an unused tunnel metadata field ID, send
187 : : * NXT_TLV_TABLE_MOD and OFPT_BARRIER_REQUEST, and transition to
188 : : * S_TLV_TABLE_MOD_SENT.
189 : : *
190 : : * - Otherwise, log an error, disable Geneve, and transition to
191 : : * S_CLEAR_FLOWS.
192 : : *
193 : : * If we receive an OFPT_ERROR:
194 : : *
195 : : * - Log an error, disable Geneve, and transition to S_CLEAR_FLOWS. */
196 : :
197 : : static void
198 : 50 : run_S_TLV_TABLE_REQUESTED(void)
199 : : {
200 : 50 : }
201 : :
202 : : static bool
203 : 46 : process_tlv_table_reply(const struct ofputil_tlv_table_reply *reply)
204 : : {
205 : : const struct ofputil_tlv_map *map;
206 : 46 : uint64_t md_free = UINT64_MAX;
207 : : BUILD_ASSERT(TUN_METADATA_NUM_OPTS == 64);
208 : :
209 [ - + ]: 46 : LIST_FOR_EACH (map, list_node, &reply->mappings) {
210 [ # # ]: 0 : if (map->option_class == OVN_GENEVE_CLASS
211 [ # # ]: 0 : && map->option_type == OVN_GENEVE_TYPE
212 [ # # ]: 0 : && map->option_len == OVN_GENEVE_LEN) {
213 [ # # ]: 0 : if (map->index >= TUN_METADATA_NUM_OPTS) {
214 [ # # ]: 0 : VLOG_ERR("desired Geneve tunnel option 0x%"PRIx16","
215 : : "%"PRIu8",%"PRIu8" already in use with "
216 : : "unsupported index %"PRIu16,
217 : : map->option_class, map->option_type,
218 : : map->option_len, map->index);
219 : 0 : return false;
220 : : } else {
221 : 0 : mff_ovn_geneve = MFF_TUN_METADATA0 + map->index;
222 : 0 : state = S_CLEAR_FLOWS;
223 : 0 : return true;
224 : : }
225 : : }
226 : :
227 [ # # ]: 0 : if (map->index < TUN_METADATA_NUM_OPTS) {
228 : 0 : md_free &= ~(UINT64_C(1) << map->index);
229 : : }
230 : : }
231 : :
232 [ - + ]: 46 : VLOG_DBG("OVN Geneve option not found");
233 [ - + ]: 46 : if (!md_free) {
234 [ # # ]: 0 : VLOG_ERR("no Geneve options free for use by OVN");
235 : 0 : return false;
236 : : }
237 : :
238 : 46 : unsigned int index = rightmost_1bit_idx(md_free);
239 : 46 : mff_ovn_geneve = MFF_TUN_METADATA0 + index;
240 : : struct ofputil_tlv_map tm;
241 : 46 : tm.option_class = OVN_GENEVE_CLASS;
242 : 46 : tm.option_type = OVN_GENEVE_TYPE;
243 : 46 : tm.option_len = OVN_GENEVE_LEN;
244 : 46 : tm.index = index;
245 : :
246 : : struct ofputil_tlv_table_mod ttm;
247 : 46 : ttm.command = NXTTMC_ADD;
248 : 46 : ovs_list_init(&ttm.mappings);
249 : 46 : ovs_list_push_back(&ttm.mappings, &tm.list_node);
250 : :
251 : 46 : xid = queue_msg(ofputil_encode_tlv_table_mod(OFP13_VERSION, &ttm));
252 : 46 : xid2 = queue_msg(ofputil_encode_barrier_request(OFP13_VERSION));
253 : 46 : state = S_TLV_TABLE_MOD_SENT;
254 : :
255 : 46 : return true;
256 : : }
257 : :
258 : : static void
259 : 46 : recv_S_TLV_TABLE_REQUESTED(const struct ofp_header *oh, enum ofptype type)
260 : : {
261 [ - + ]: 46 : if (oh->xid != xid) {
262 : 0 : ofctrl_recv(oh, type);
263 : 0 : return;
264 [ + - ]: 46 : } else if (type == OFPTYPE_NXT_TLV_TABLE_REPLY) {
265 : : struct ofputil_tlv_table_reply reply;
266 : 46 : enum ofperr error = ofputil_decode_tlv_table_reply(oh, &reply);
267 [ + - ]: 46 : if (!error) {
268 : 46 : bool ok = process_tlv_table_reply(&reply);
269 : 46 : ofputil_uninit_tlv_table(&reply.mappings);
270 [ + - ]: 46 : if (ok) {
271 : 46 : return;
272 : : }
273 : : } else {
274 [ # # ]: 0 : VLOG_ERR("failed to decode TLV table request (%s)",
275 : : ofperr_to_string(error));
276 : : }
277 [ # # ]: 0 : } else if (type == OFPTYPE_ERROR) {
278 [ # # ]: 0 : VLOG_ERR("switch refused to allocate Geneve option (%s)",
279 : : ofperr_to_string(ofperr_decode_msg(oh, NULL)));
280 : : } else {
281 : 0 : char *s = ofp_to_string(oh, ntohs(oh->length), 1);
282 [ # # ]: 0 : VLOG_ERR("unexpected reply to TLV table request (%s)", s);
283 : 0 : free(s);
284 : : }
285 : :
286 : : /* Error path. */
287 : 0 : mff_ovn_geneve = 0;
288 : 0 : state = S_CLEAR_FLOWS;
289 : : }
290 : :
291 : : /* S_TLV_TABLE_MOD_SENT, when NXT_TLV_TABLE_MOD and OFPT_BARRIER_REQUEST
292 : : * have been sent and we're waiting for a reply to one or the other.
293 : : *
294 : : * If we receive an OFPT_ERROR:
295 : : *
296 : : * - If the error is NXTTMFC_ALREADY_MAPPED or NXTTMFC_DUP_ENTRY, we
297 : : * raced with some other controller. Transition to S_NEW.
298 : : *
299 : : * - Otherwise, log an error, disable Geneve, and transition to
300 : : * S_CLEAR_FLOWS.
301 : : *
302 : : * If we receive OFPT_BARRIER_REPLY:
303 : : *
304 : : * - Set the tunnel metadata field ID to the one that we requested.
305 : : * Transition to S_CLEAR_FLOWS.
306 : : */
307 : :
308 : : static void
309 : 80 : run_S_TLV_TABLE_MOD_SENT(void)
310 : : {
311 : 80 : }
312 : :
313 : : static void
314 : 46 : recv_S_TLV_TABLE_MOD_SENT(const struct ofp_header *oh, enum ofptype type)
315 : : {
316 [ + - ][ - + ]: 46 : if (oh->xid != xid && oh->xid != xid2) {
317 : 0 : ofctrl_recv(oh, type);
318 [ + - ][ + - ]: 46 : } else if (oh->xid == xid2 && type == OFPTYPE_BARRIER_REPLY) {
319 : 46 : state = S_CLEAR_FLOWS;
320 [ # # ][ # # ]: 0 : } else if (oh->xid == xid && type == OFPTYPE_ERROR) {
321 : 0 : enum ofperr error = ofperr_decode_msg(oh, NULL);
322 [ # # ][ # # ]: 0 : if (error == OFPERR_NXTTMFC_ALREADY_MAPPED ||
323 : : error == OFPERR_NXTTMFC_DUP_ENTRY) {
324 [ # # ]: 0 : VLOG_INFO("raced with another controller adding "
325 : : "Geneve option (%s); trying again",
326 : : ofperr_to_string(error));
327 : 0 : state = S_NEW;
328 : : } else {
329 [ # # ]: 0 : VLOG_ERR("error adding Geneve option (%s)",
330 : : ofperr_to_string(error));
331 : 0 : goto error;
332 : : }
333 : : } else {
334 : 0 : char *s = ofp_to_string(oh, ntohs(oh->length), 1);
335 [ # # ]: 0 : VLOG_ERR("unexpected reply to Geneve option allocation request (%s)",
336 : : s);
337 : 0 : free(s);
338 : 0 : goto error;
339 : : }
340 : 46 : return;
341 : :
342 : : error:
343 : 0 : state = S_CLEAR_FLOWS;
344 : : }
345 : :
346 : : /* S_CLEAR_FLOWS, after we've established a Geneve metadata field ID and it's
347 : : * time to set up some flows.
348 : : *
349 : : * Sends an OFPT_TABLE_MOD to clear all flows, then transitions to
350 : : * S_UPDATE_FLOWS. */
351 : :
352 : : static void
353 : 46 : run_S_CLEAR_FLOWS(void)
354 : : {
355 : : /* Send a flow_mod to delete all flows. */
356 : 46 : struct ofputil_flow_mod fm = {
357 : : .match = MATCH_CATCHALL_INITIALIZER,
358 : : .table_id = OFPTT_ALL,
359 : : .command = OFPFC_DELETE,
360 : : };
361 : 46 : queue_msg(encode_flow_mod(&fm));
362 [ - + ]: 46 : VLOG_DBG("clearing all flows");
363 : :
364 : : /* Clear installed_flows, to match the state of the switch. */
365 : 46 : ovn_flow_table_clear(&installed_flows);
366 : :
367 : : /* Send a group_mod to delete all groups. */
368 : : struct ofputil_group_mod gm;
369 : 46 : memset(&gm, 0, sizeof gm);
370 : 46 : gm.command = OFPGC11_DELETE;
371 : 46 : gm.group_id = OFPG_ALL;
372 : 46 : gm.command_bucket_id = OFPG15_BUCKET_ALL;
373 : 46 : ovs_list_init(&gm.buckets);
374 : 46 : queue_msg(encode_group_mod(&gm));
375 : 46 : ofputil_uninit_group_mod(&gm);
376 : :
377 : : /* Clear existing groups, to match the state of the switch. */
378 [ + - ]: 46 : if (groups) {
379 : 46 : ovn_group_table_clear(groups, true);
380 : : }
381 : :
382 : : /* All flow updates are irrelevant now. */
383 : : struct ofctrl_flow_update *fup, *next;
384 [ - + ][ - + ]: 46 : LIST_FOR_EACH_SAFE (fup, next, list_node, &flow_updates) {
385 : 0 : ovs_list_remove(&fup->list_node);
386 : 0 : free(fup);
387 : : }
388 : :
389 : 46 : state = S_UPDATE_FLOWS;
390 : 46 : }
391 : :
392 : : static void
393 : 0 : recv_S_CLEAR_FLOWS(const struct ofp_header *oh, enum ofptype type)
394 : : {
395 : 0 : ofctrl_recv(oh, type);
396 : 0 : }
397 : :
398 : : /* S_UPDATE_FLOWS, for maintaining the flow table over time.
399 : : *
400 : : * Compare the installed flows to the ones we want. Send OFPT_FLOW_MOD as
401 : : * necessary.
402 : : *
403 : : * This is a terminal state. We only transition out of it if the connection
404 : : * drops. */
405 : :
406 : : static void
407 : 4891 : run_S_UPDATE_FLOWS(void)
408 : : {
409 : : /* Nothing to do here.
410 : : *
411 : : * Being in this state enables ofctrl_put() to work, however. */
412 : 4891 : }
413 : :
414 : : static void
415 : 1831 : recv_S_UPDATE_FLOWS(const struct ofp_header *oh, enum ofptype type)
416 : : {
417 [ + + ][ + - ]: 3098 : if (type == OFPTYPE_BARRIER_REPLY && !ovs_list_is_empty(&flow_updates)) {
418 : 1267 : struct ofctrl_flow_update *fup = ofctrl_flow_update_from_list_node(
419 : 1267 : ovs_list_front(&flow_updates));
420 [ + + ]: 1267 : if (fup->xid == oh->xid) {
421 [ + - ]: 802 : if (fup->nb_cfg >= cur_cfg) {
422 : 802 : cur_cfg = fup->nb_cfg;
423 : : }
424 : 802 : ovs_list_remove(&fup->list_node);
425 : 802 : free(fup);
426 : : }
427 : : } else {
428 : 564 : ofctrl_recv(oh, type);
429 : : }
430 : 1831 : }
431 : :
432 : : /* Runs the OpenFlow state machine against 'br_int', which is local to the
433 : : * hypervisor on which we are running. Attempts to negotiate a Geneve option
434 : : * field for class OVN_GENEVE_CLASS, type OVN_GENEVE_TYPE. If successful,
435 : : * returns the MFF_* field ID for the option, otherwise returns 0. */
436 : : enum mf_field_id
437 : 3167 : ofctrl_run(const struct ovsrec_bridge *br_int)
438 : : {
439 : 3167 : char *target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), br_int->name);
440 [ + + ]: 3167 : if (strcmp(target, rconn_get_target(swconn))) {
441 [ + - ]: 44 : VLOG_INFO("%s: connecting to switch", target);
442 : 44 : rconn_connect(swconn, target, target);
443 : : }
444 : 3167 : free(target);
445 : :
446 : 3167 : rconn_run(swconn);
447 : :
448 [ + + ]: 3167 : if (!rconn_is_connected(swconn)) {
449 : 42 : return 0;
450 : : }
451 [ + + ]: 3125 : if (seqno != rconn_get_connection_seqno(swconn)) {
452 : 46 : seqno = rconn_get_connection_seqno(swconn);
453 : 46 : state = S_NEW;
454 : : }
455 : :
456 : 3125 : bool progress = true;
457 [ + + ][ + - ]: 8238 : for (int i = 0; progress && i < 50; i++) {
458 : : /* Allow the state machine to run. */
459 : 5113 : enum ofctrl_state old_state = state;
460 [ + + + + : 5113 : switch (state) {
+ - ]
461 : : #define STATE(NAME) case NAME: run_##NAME(); break;
462 : 5113 : STATES
463 : : #undef STATE
464 : : default:
465 : 0 : OVS_NOT_REACHED();
466 : : }
467 : :
468 : : /* Try to process a received packet. */
469 : 5113 : struct ofpbuf *msg = rconn_recv(swconn);
470 [ + + ]: 5113 : if (msg) {
471 : 1923 : const struct ofp_header *oh = msg->data;
472 : : enum ofptype type;
473 : : enum ofperr error;
474 : :
475 : 1923 : error = ofptype_decode(&type, oh);
476 [ + - ]: 1923 : if (!error) {
477 [ - + + - : 1923 : switch (state) {
+ - ]
478 : : #define STATE(NAME) case NAME: recv_##NAME(oh, type); break;
479 : 1923 : STATES
480 : : #undef STATE
481 : : default:
482 : 1923 : OVS_NOT_REACHED();
483 : : }
484 : : } else {
485 : 0 : char *s = ofp_to_string(oh, ntohs(oh->length), 1);
486 [ # # ]: 0 : VLOG_WARN("could not decode OpenFlow message (%s): %s",
487 : : ofperr_to_string(error), s);
488 : 0 : free(s);
489 : : }
490 : :
491 : 1923 : ofpbuf_delete(msg);
492 : : }
493 : :
494 : : /* If we did some work, plan to go around again. */
495 [ + + ][ + + ]: 5113 : progress = old_state != state || msg;
496 : : }
497 [ - + ]: 3125 : if (progress) {
498 : : /* We bailed out to limit the amount of work we do in one go, to allow
499 : : * other code a chance to run. We were still making progress at that
500 : : * point, so ensure that we come back again without waiting. */
501 : 0 : poll_immediate_wake();
502 : : }
503 : :
504 [ + - ][ + + ]: 3125 : return (state == S_CLEAR_FLOWS || state == S_UPDATE_FLOWS
505 : : ? mff_ovn_geneve : 0);
506 : : }
507 : :
508 : : void
509 : 3167 : ofctrl_wait(void)
510 : : {
511 : 3167 : rconn_run_wait(swconn);
512 : 3167 : rconn_recv_wait(swconn);
513 : 3167 : }
514 : :
515 : : void
516 : 44 : ofctrl_destroy(void)
517 : : {
518 : 44 : rconn_destroy(swconn);
519 : 44 : ovn_flow_table_destroy(&installed_flows);
520 : 44 : rconn_packet_counter_destroy(tx_counter);
521 : 44 : }
522 : :
523 : : int64_t
524 : 2670 : ofctrl_get_cur_cfg(void)
525 : : {
526 : 2670 : return cur_cfg;
527 : : }
528 : :
529 : : static ovs_be32
530 : 23031 : queue_msg(struct ofpbuf *msg)
531 : : {
532 : 23031 : const struct ofp_header *oh = msg->data;
533 : 23031 : ovs_be32 xid = oh->xid;
534 : 23031 : rconn_send(swconn, msg, tx_counter);
535 : 23031 : return xid;
536 : : }
537 : :
538 : : static void
539 : 558 : log_openflow_rl(struct vlog_rate_limit *rl, enum vlog_level level,
540 : : const struct ofp_header *oh, const char *title)
541 : : {
542 [ + - ]: 558 : if (!vlog_should_drop(&this_module, level, rl)) {
543 : 558 : char *s = ofp_to_string(oh, ntohs(oh->length), 2);
544 : 558 : vlog(&this_module, level, "%s: %s", title, s);
545 : 558 : free(s);
546 : : }
547 : 558 : }
548 : :
549 : : static void
550 : 564 : ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
551 : : {
552 [ + + ]: 564 : if (type == OFPTYPE_ECHO_REQUEST) {
553 : 6 : queue_msg(make_echo_reply(oh));
554 [ + - ]: 558 : } else if (type == OFPTYPE_ERROR) {
555 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
556 : 558 : log_openflow_rl(&rl, VLL_INFO, oh, "OpenFlow error");
557 [ # # ][ # # ]: 0 : } else if (type != OFPTYPE_ECHO_REPLY &&
558 [ # # ]: 0 : type != OFPTYPE_BARRIER_REPLY &&
559 [ # # ]: 0 : type != OFPTYPE_PACKET_IN &&
560 [ # # ]: 0 : type != OFPTYPE_PORT_STATUS &&
561 : : type != OFPTYPE_FLOW_REMOVED) {
562 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
563 : 0 : log_openflow_rl(&rl, VLL_DBG, oh, "OpenFlow packet ignored");
564 : : }
565 : 564 : }
566 : :
567 : : /* Flow table interfaces to the rest of ovn-controller. */
568 : :
569 : : /* Adds a flow to 'desired_flows' with the specified 'match' and 'actions' to
570 : : * the OpenFlow table numbered 'table_id' with the given 'priority'. The
571 : : * caller retains ownership of 'match' and 'actions'.
572 : : *
573 : : * This just assembles the desired flow table in memory. Nothing is actually
574 : : * sent to the switch until a later call to ofctrl_run().
575 : : *
576 : : * The caller should initialize its own hmap to hold the flows. */
577 : : void
578 : 1051738 : ofctrl_add_flow(struct hmap *desired_flows,
579 : : uint8_t table_id, uint16_t priority,
580 : : const struct match *match, const struct ofpbuf *actions)
581 : : {
582 : 1051738 : struct ovn_flow *f = xmalloc(sizeof *f);
583 : 1051738 : f->table_id = table_id;
584 : 1051738 : f->priority = priority;
585 : 1051738 : f->match = *match;
586 : 1051738 : f->ofpacts = xmemdup(actions->data, actions->size);
587 : 1051738 : f->ofpacts_len = actions->size;
588 : 1051738 : f->hmap_node.hash = ovn_flow_hash(f);
589 : :
590 [ + + ]: 1051738 : if (ovn_flow_lookup(desired_flows, f)) {
591 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
592 [ + + ]: 17337 : if (!VLOG_DROP_INFO(&rl)) {
593 : 118 : char *s = ovn_flow_to_string(f);
594 [ + - ]: 118 : VLOG_INFO("dropping duplicate flow: %s", s);
595 : 118 : free(s);
596 : : }
597 : :
598 : 17337 : ovn_flow_destroy(f);
599 : 17337 : return;
600 : : }
601 : :
602 : 1034401 : hmap_insert(desired_flows, &f->hmap_node, f->hmap_node.hash);
603 : : }
604 : :
605 : :
606 : : /* ovn_flow. */
607 : :
608 : : /* Returns a hash of the key in 'f'. */
609 : : static uint32_t
610 : 1051738 : ovn_flow_hash(const struct ovn_flow *f)
611 : : {
612 : 1051738 : return hash_2words((f->table_id << 16) | f->priority,
613 : : match_hash(&f->match, 0));
614 : :
615 : : }
616 : :
617 : : /* Duplicate an ovn_flow structure. */
618 : : struct ovn_flow *
619 : 0 : ofctrl_dup_flow(struct ovn_flow *src)
620 : : {
621 : 0 : struct ovn_flow *dst = xmalloc(sizeof *dst);
622 : 0 : dst->table_id = src->table_id;
623 : 0 : dst->priority = src->priority;
624 : 0 : dst->match = src->match;
625 : 0 : dst->ofpacts = xmemdup(src->ofpacts, src->ofpacts_len);
626 : 0 : dst->ofpacts_len = src->ofpacts_len;
627 : 0 : dst->hmap_node.hash = ovn_flow_hash(dst);
628 : 0 : return dst;
629 : : }
630 : :
631 : : /* Finds and returns an ovn_flow in 'flow_table' whose key is identical to
632 : : * 'target''s key, or NULL if there is none. */
633 : : static struct ovn_flow *
634 : 2052263 : ovn_flow_lookup(struct hmap *flow_table, const struct ovn_flow *target)
635 : : {
636 : : struct ovn_flow *f;
637 : :
638 [ + + ][ - + ]: 2052263 : HMAP_FOR_EACH_WITH_HASH (f, hmap_node, target->hmap_node.hash,
639 : : flow_table) {
640 [ + - ]: 1012224 : if (f->table_id == target->table_id
641 [ + - ]: 1012224 : && f->priority == target->priority
642 [ + - ]: 1012224 : && match_equal(&f->match, &target->match)) {
643 : 1012224 : return f;
644 : : }
645 : : }
646 : 1040039 : return NULL;
647 : : }
648 : :
649 : : static char *
650 : 118 : ovn_flow_to_string(const struct ovn_flow *f)
651 : : {
652 : 118 : struct ds s = DS_EMPTY_INITIALIZER;
653 : 118 : ds_put_format(&s, "table_id=%"PRIu8", ", f->table_id);
654 : 118 : ds_put_format(&s, "priority=%"PRIu16", ", f->priority);
655 : 118 : match_format(&f->match, &s, OFP_DEFAULT_PRIORITY);
656 : 118 : ds_put_cstr(&s, ", actions=");
657 : 118 : ofpacts_format(f->ofpacts, f->ofpacts_len, &s);
658 : 118 : return ds_steal_cstr(&s);
659 : : }
660 : :
661 : : static void
662 : 21522 : ovn_flow_log(const struct ovn_flow *f, const char *action)
663 : : {
664 [ - + ]: 21522 : if (VLOG_IS_DBG_ENABLED()) {
665 : 0 : char *s = ovn_flow_to_string(f);
666 [ # # ]: 0 : VLOG_DBG("%s flow: %s", action, s);
667 : 0 : free(s);
668 : : }
669 : 21522 : }
670 : :
671 : : static void
672 : 1051738 : ovn_flow_destroy(struct ovn_flow *f)
673 : : {
674 [ + - ]: 1051738 : if (f) {
675 : 1051738 : free(f->ofpacts);
676 : 1051738 : free(f);
677 : : }
678 : 1051738 : }
679 : :
680 : : /* Flow tables of struct ovn_flow. */
681 : :
682 : : static void
683 : 246 : ovn_flow_table_clear(struct hmap *flow_table)
684 : : {
685 : : struct ovn_flow *f, *next;
686 [ + + ][ - + ]: 34122 : HMAP_FOR_EACH_SAFE (f, next, hmap_node, flow_table) {
[ + + ]
687 : 33876 : hmap_remove(flow_table, &f->hmap_node);
688 : 33876 : ovn_flow_destroy(f);
689 : : }
690 : 246 : }
691 : :
692 : : static void
693 : 44 : ovn_flow_table_destroy(struct hmap *flow_table)
694 : : {
695 : 44 : ovn_flow_table_clear(flow_table);
696 : 44 : hmap_destroy(flow_table);
697 : 44 : }
698 : :
699 : : /* Flow table update. */
700 : :
701 : : static struct ofpbuf *
702 : 21568 : encode_flow_mod(struct ofputil_flow_mod *fm)
703 : : {
704 : 21568 : fm->buffer_id = UINT32_MAX;
705 : 21568 : fm->out_port = OFPP_ANY;
706 : 21568 : fm->out_group = OFPG_ANY;
707 : 21568 : return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM);
708 : : }
709 : :
710 : : static void
711 : 21522 : add_flow_mod(struct ofputil_flow_mod *fm, struct ovs_list *msgs)
712 : : {
713 : 21522 : struct ofpbuf *msg = encode_flow_mod(fm);
714 : 21522 : ovs_list_push_back(msgs, &msg->list_node);
715 : 21522 : }
716 : :
717 : : /* group_table. */
718 : :
719 : : /* Finds and returns a group_info in 'existing_groups' whose key is identical
720 : : * to 'target''s key, or NULL if there is none. */
721 : : static struct group_info *
722 : 135 : ovn_group_lookup(struct hmap *exisiting_groups,
723 : : const struct group_info *target)
724 : : {
725 : : struct group_info *e;
726 : :
727 [ + + ][ - + ]: 135 : HMAP_FOR_EACH_WITH_HASH(e, hmap_node, target->hmap_node.hash,
728 : : exisiting_groups) {
729 [ + - ]: 123 : if (e->group_id == target->group_id) {
730 : 123 : return e;
731 : : }
732 : : }
733 : 12 : return NULL;
734 : : }
735 : :
736 : : /* Clear either desired_groups or existing_groups in group_table. */
737 : : void
738 : 202 : ovn_group_table_clear(struct group_table *group_table, bool existing)
739 : : {
740 : : struct group_info *g, *next;
741 : 202 : struct hmap *target_group = existing
742 : : ? &group_table->existing_groups
743 [ + + ]: 202 : : &group_table->desired_groups;
744 : :
745 [ + - ][ - + ]: 202 : HMAP_FOR_EACH_SAFE (g, next, hmap_node, target_group) {
[ - + ]
746 : 0 : hmap_remove(target_group, &g->hmap_node);
747 : : /* Don't unset bitmap for desired group_info if the group_id
748 : : * was not freshly reserved. */
749 [ # # ][ # # ]: 0 : if (existing || g->new_group_id) {
750 : 0 : bitmap_set0(group_table->group_ids, g->group_id);
751 : : }
752 : 0 : ds_destroy(&g->group);
753 : 0 : free(g);
754 : : }
755 : 202 : }
756 : :
757 : : static struct ofpbuf *
758 : 52 : encode_group_mod(const struct ofputil_group_mod *gm)
759 : : {
760 : 52 : return ofputil_encode_group_mod(OFP13_VERSION, gm);
761 : : }
762 : :
763 : : static void
764 : 6 : add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs)
765 : : {
766 : 6 : struct ofpbuf *msg = encode_group_mod(gm);
767 : 6 : ovs_list_push_back(msgs, &msg->list_node);
768 : 6 : }
769 : :
770 : :
771 : : /* Replaces the flow table on the switch, if possible, by the flows added
772 : : * with ofctrl_add_flow().
773 : : *
774 : : * Replaces the group table on the switch, if possible, by the contents of
775 : : * 'groups->desired_groups'. Regardless of whether the group table
776 : : * is updated, this deletes all the groups from the
777 : : * 'groups->desired_groups' and frees them. (The hmap itself isn't
778 : : * destroyed.)
779 : : *
780 : : * This should be called after ofctrl_run() within the main loop. */
781 : : void
782 : 3167 : ofctrl_put(struct hmap *flow_table, int64_t nb_cfg)
783 : : {
784 : : /* The flow table can be updated if the connection to the switch is up and
785 : : * in the correct state and not backlogged with existing flow_mods. (Our
786 : : * criteria for being backlogged appear very conservative, but the socket
787 : : * between ovn-controller and OVS provides some buffering.) */
788 [ + + ]: 3167 : if (state != S_UPDATE_FLOWS
789 [ + + ]: 3080 : || rconn_packet_counter_n_packets(tx_counter)) {
790 : 156 : ovn_flow_table_clear(flow_table);
791 : 156 : ovn_group_table_clear(groups, false);
792 : 156 : return;
793 : : }
794 : :
795 : : /* OpenFlow messages to send to the switch to bring it up-to-date. */
796 : 3011 : struct ovs_list msgs = OVS_LIST_INITIALIZER(&msgs);
797 : :
798 : : /* Iterate through all the desired groups. If there are new ones,
799 : : * add them to the switch. */
800 : : struct group_info *desired;
801 [ + + ][ - + ]: 3058 : HMAP_FOR_EACH(desired, hmap_node, &groups->desired_groups) {
802 [ + + ]: 47 : if (!ovn_group_lookup(&groups->existing_groups, desired)) {
803 : : /* Create and install new group. */
804 : : struct ofputil_group_mod gm;
805 : : enum ofputil_protocol usable_protocols;
806 : : char *error;
807 : 6 : struct ds group_string = DS_EMPTY_INITIALIZER;
808 : 6 : ds_put_format(&group_string, "group_id=%u,%s",
809 : : desired->group_id, ds_cstr(&desired->group));
810 : :
811 : 6 : error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD,
812 : 6 : ds_cstr(&group_string),
813 : : &usable_protocols);
814 [ + - ]: 6 : if (!error) {
815 : 6 : add_group_mod(&gm, &msgs);
816 : : } else {
817 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
818 [ # # ]: 0 : VLOG_ERR_RL(&rl, "new group %s %s", error,
819 : : ds_cstr(&group_string));
820 : 0 : free(error);
821 : : }
822 : 6 : ds_destroy(&group_string);
823 : 6 : ofputil_uninit_group_mod(&gm);
824 : : }
825 : : }
826 : :
827 : : /* Iterate through all of the installed flows. If any of them are no
828 : : * longer desired, delete them; if any of them should have different
829 : : * actions, update them. */
830 : : struct ovn_flow *i, *next;
831 [ + + ][ - + ]: 1003536 : HMAP_FOR_EACH_SAFE (i, next, hmap_node, &installed_flows) {
[ + + ]
832 : 1000525 : struct ovn_flow *d = ovn_flow_lookup(flow_table, i);
833 [ + + ]: 1000525 : if (!d) {
834 : : /* Installed flow is no longer desirable. Delete it from the
835 : : * switch and from installed_flows. */
836 : 16914 : struct ofputil_flow_mod fm = {
837 : : .match = i->match,
838 : 5638 : .priority = i->priority,
839 : 5638 : .table_id = i->table_id,
840 : : .command = OFPFC_DELETE_STRICT,
841 : : };
842 : 5638 : add_flow_mod(&fm, &msgs);
843 : 5638 : ovn_flow_log(i, "removing installed");
844 : :
845 : 5638 : hmap_remove(&installed_flows, &i->hmap_node);
846 : 5638 : ovn_flow_destroy(i);
847 : : } else {
848 [ + + ]: 994887 : if (!ofpacts_equal(i->ofpacts, i->ofpacts_len,
849 : 994887 : d->ofpacts, d->ofpacts_len)) {
850 : : /* Update actions in installed flow. */
851 : 1690 : struct ofputil_flow_mod fm = {
852 : : .match = i->match,
853 : 338 : .priority = i->priority,
854 : 338 : .table_id = i->table_id,
855 : 338 : .ofpacts = d->ofpacts,
856 : 338 : .ofpacts_len = d->ofpacts_len,
857 : : .command = OFPFC_MODIFY_STRICT,
858 : : };
859 : 338 : add_flow_mod(&fm, &msgs);
860 : 338 : ovn_flow_log(i, "updating installed");
861 : :
862 : : /* Replace 'i''s actions by 'd''s. */
863 : 338 : free(i->ofpacts);
864 : 338 : i->ofpacts = d->ofpacts;
865 : 338 : i->ofpacts_len = d->ofpacts_len;
866 : 338 : d->ofpacts = NULL;
867 : 338 : d->ofpacts_len = 0;
868 : : }
869 : :
870 : 994887 : hmap_remove(flow_table, &d->hmap_node);
871 : 994887 : ovn_flow_destroy(d);
872 : : }
873 : : }
874 : :
875 : : /* The previous loop removed from 'flow_table' all of the flows that are
876 : : * already installed. Thus, any flows remaining in 'flow_table' need to
877 : : * be added to the flow table. */
878 : : struct ovn_flow *d;
879 [ + + ][ - + ]: 18557 : HMAP_FOR_EACH_SAFE (d, next, hmap_node, flow_table) {
[ + + ]
880 : : /* Send flow_mod to add flow. */
881 : 77730 : struct ofputil_flow_mod fm = {
882 : : .match = d->match,
883 : 15546 : .priority = d->priority,
884 : 15546 : .table_id = d->table_id,
885 : 15546 : .ofpacts = d->ofpacts,
886 : 15546 : .ofpacts_len = d->ofpacts_len,
887 : : .command = OFPFC_ADD,
888 : : };
889 : 15546 : add_flow_mod(&fm, &msgs);
890 : 15546 : ovn_flow_log(d, "adding installed");
891 : :
892 : : /* Move 'd' from 'flow_table' to installed_flows. */
893 : 15546 : hmap_remove(flow_table, &d->hmap_node);
894 : 15546 : hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash);
895 : : }
896 : :
897 : : /* Iterate through the installed groups from previous runs. If they
898 : : * are not needed delete them. */
899 : : struct group_info *installed, *next_group;
900 [ + + ][ - + ]: 3052 : HMAP_FOR_EACH_SAFE(installed, next_group, hmap_node,
[ + + ]
901 : : &groups->existing_groups) {
902 [ - + ]: 41 : if (!ovn_group_lookup(&groups->desired_groups, installed)) {
903 : : /* Delete the group. */
904 : : struct ofputil_group_mod gm;
905 : : enum ofputil_protocol usable_protocols;
906 : : char *error;
907 : 0 : struct ds group_string = DS_EMPTY_INITIALIZER;
908 : 0 : ds_put_format(&group_string, "group_id=%u", installed->group_id);
909 : :
910 : 0 : error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
911 : 0 : ds_cstr(&group_string),
912 : : &usable_protocols);
913 [ # # ]: 0 : if (!error) {
914 : 0 : add_group_mod(&gm, &msgs);
915 : : } else {
916 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
917 [ # # ]: 0 : VLOG_ERR_RL(&rl, "Error deleting group %d: %s",
918 : : installed->group_id, error);
919 : 0 : free(error);
920 : : }
921 : 0 : ds_destroy(&group_string);
922 : 0 : ofputil_uninit_group_mod(&gm);
923 : :
924 : : /* Remove 'installed' from 'groups->existing_groups' */
925 : 0 : hmap_remove(&groups->existing_groups, &installed->hmap_node);
926 : 0 : ds_destroy(&installed->group);
927 : :
928 : : /* Dealloc group_id. */
929 : 0 : bitmap_set0(groups->group_ids, installed->group_id);
930 : 0 : free(installed);
931 : : }
932 : : }
933 : :
934 : : /* Move the contents of desired_groups to existing_groups. */
935 [ + + ][ - + ]: 3058 : HMAP_FOR_EACH_SAFE(desired, next_group, hmap_node,
[ + + ]
936 : : &groups->desired_groups) {
937 : 47 : hmap_remove(&groups->desired_groups, &desired->hmap_node);
938 [ + + ]: 47 : if (!ovn_group_lookup(&groups->existing_groups, desired)) {
939 : 6 : hmap_insert(&groups->existing_groups, &desired->hmap_node,
940 : : desired->hmap_node.hash);
941 : : } else {
942 : 41 : ds_destroy(&desired->group);
943 : 41 : free(desired);
944 : : }
945 : : }
946 : :
947 [ + + ]: 3011 : if (!ovs_list_is_empty(&msgs)) {
948 : : /* Add a barrier to the list of messages. */
949 : 1267 : struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP13_VERSION);
950 : 1267 : const struct ofp_header *oh = barrier->data;
951 : 1267 : ovs_be32 xid = oh->xid;
952 : 1267 : ovs_list_push_back(&msgs, &barrier->list_node);
953 : :
954 : : /* Queue the messages. */
955 : : struct ofpbuf *msg;
956 [ + + ]: 24062 : LIST_FOR_EACH_POP (msg, list_node, &msgs) {
957 : 22795 : queue_msg(msg);
958 : : }
959 : :
960 : : /* Track the flow update. */
961 : : struct ofctrl_flow_update *fup, *prev;
962 [ + + ][ + + ]: 1267 : LIST_FOR_EACH_REVERSE_SAFE (fup, prev, list_node, &flow_updates) {
963 [ - + ]: 465 : if (nb_cfg < fup->nb_cfg) {
964 : : /* This ofctrl_flow_update is for a configuration later than
965 : : * 'nb_cfg'. This should not normally happen, because it means
966 : : * that 'nb_cfg' in the SB_Global table of the southbound
967 : : * database decreased, and it should normally be monotonically
968 : : * increasing. */
969 [ # # ]: 0 : VLOG_WARN("nb_cfg regressed from %"PRId64" to %"PRId64,
970 : : fup->nb_cfg, nb_cfg);
971 : 0 : ovs_list_remove(&fup->list_node);
972 : 0 : free(fup);
973 [ + - ]: 465 : } else if (nb_cfg == fup->nb_cfg) {
974 : : /* This ofctrl_flow_update is for the same configuration as
975 : : * 'nb_cfg'. Probably, some change to the physical topology
976 : : * means that we had to revise the OpenFlow flow table even
977 : : * though the logical topology did not change. Update fp->xid,
978 : : * so that we don't send a notification that we're up-to-date
979 : : * until we're really caught up. */
980 [ - + ]: 465 : VLOG_DBG("advanced xid target for nb_cfg=%"PRId64, nb_cfg);
981 : 465 : fup->xid = xid;
982 : 465 : goto done;
983 : : } else {
984 : 0 : break;
985 : : }
986 : : }
987 : :
988 : : /* Add a flow update. */
989 : 802 : fup = xmalloc(sizeof *fup);
990 : 802 : ovs_list_push_back(&flow_updates, &fup->list_node);
991 : 802 : fup->xid = xid;
992 : 1267 : fup->nb_cfg = nb_cfg;
993 : : done:;
994 [ + + ]: 1744 : } else if (!ovs_list_is_empty(&flow_updates)) {
995 : : /* Getting up-to-date with 'nb_cfg' didn't require any extra flow table
996 : : * changes, so whenever we get up-to-date with the most recent flow
997 : : * table update, we're also up-to-date with 'nb_cfg'. */
998 : 373 : struct ofctrl_flow_update *fup = ofctrl_flow_update_from_list_node(
999 : 373 : ovs_list_back(&flow_updates));
1000 : 373 : fup->nb_cfg = nb_cfg;
1001 : : } else {
1002 : : /* We were completely up-to-date before and still are. */
1003 : 3011 : cur_cfg = nb_cfg;
1004 : : }
1005 : : }
|