1 /* Copyright (c) 2015, 2016 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "byte-order.h"
21 #include "openvswitch/match.h"
22 #include "openvswitch/ofp-actions.h"
23 #include "openvswitch/ofpbuf.h"
24 #include "openvswitch/vlog.h"
25 #include "ovn-controller.h"
26 #include "ovn/lib/ovn-sb-idl.h"
27 #include "ovn/lib/ovn-util.h"
33 #include "vswitch-idl.h"
35 VLOG_DEFINE_THIS_MODULE(physical
);
38 physical_register_ovs_idl(struct ovsdb_idl
*ovs_idl
)
40 ovsdb_idl_add_table(ovs_idl
, &ovsrec_table_bridge
);
41 ovsdb_idl_add_column(ovs_idl
, &ovsrec_bridge_col_ports
);
43 ovsdb_idl_add_table(ovs_idl
, &ovsrec_table_port
);
44 ovsdb_idl_add_column(ovs_idl
, &ovsrec_port_col_name
);
45 ovsdb_idl_add_column(ovs_idl
, &ovsrec_port_col_interfaces
);
46 ovsdb_idl_add_column(ovs_idl
, &ovsrec_port_col_external_ids
);
48 ovsdb_idl_add_table(ovs_idl
, &ovsrec_table_interface
);
49 ovsdb_idl_add_column(ovs_idl
, &ovsrec_interface_col_name
);
50 ovsdb_idl_add_column(ovs_idl
, &ovsrec_interface_col_ofport
);
51 ovsdb_idl_add_column(ovs_idl
, &ovsrec_interface_col_external_ids
);
54 static struct simap localvif_to_ofport
=
55 SIMAP_INITIALIZER(&localvif_to_ofport
);
56 static struct hmap tunnels
= HMAP_INITIALIZER(&tunnels
);
58 /* Maps from a chassis to the OpenFlow port number of the tunnel that can be
59 * used to reach that chassis. */
60 struct chassis_tunnel
{
61 struct hmap_node hmap_node
;
62 const char *chassis_id
;
64 enum chassis_tunnel_type type
;
67 static struct chassis_tunnel
*
68 chassis_tunnel_find(const char *chassis_id
)
70 struct chassis_tunnel
*tun
;
71 HMAP_FOR_EACH_WITH_HASH (tun
, hmap_node
, hash_string(chassis_id
, 0),
73 if (!strcmp(tun
->chassis_id
, chassis_id
)) {
81 put_load(uint64_t value
, enum mf_field_id dst
, int ofs
, int n_bits
,
82 struct ofpbuf
*ofpacts
)
84 struct ofpact_set_field
*sf
= ofpact_put_SET_FIELD(ofpacts
);
85 sf
->field
= mf_from_id(dst
);
86 sf
->flow_has_vlan
= false;
88 ovs_be64 n_value
= htonll(value
);
89 bitwise_copy(&n_value
, 8, 0, &sf
->value
, sf
->field
->n_bytes
, ofs
, n_bits
);
90 bitwise_one(&sf
->mask
, sf
->field
->n_bytes
, ofs
, n_bits
);
94 put_move(enum mf_field_id src
, int src_ofs
,
95 enum mf_field_id dst
, int dst_ofs
,
97 struct ofpbuf
*ofpacts
)
99 struct ofpact_reg_move
*move
= ofpact_put_REG_MOVE(ofpacts
);
100 move
->src
.field
= mf_from_id(src
);
101 move
->src
.ofs
= src_ofs
;
102 move
->src
.n_bits
= n_bits
;
103 move
->dst
.field
= mf_from_id(dst
);
104 move
->dst
.ofs
= dst_ofs
;
105 move
->dst
.n_bits
= n_bits
;
109 put_resubmit(uint8_t table_id
, struct ofpbuf
*ofpacts
)
111 struct ofpact_resubmit
*resubmit
= ofpact_put_RESUBMIT(ofpacts
);
112 resubmit
->in_port
= OFPP_IN_PORT
;
113 resubmit
->table_id
= table_id
;
117 put_encapsulation(enum mf_field_id mff_ovn_geneve
,
118 const struct chassis_tunnel
*tun
,
119 const struct sbrec_datapath_binding
*datapath
,
120 uint16_t outport
, struct ofpbuf
*ofpacts
)
122 if (tun
->type
== GENEVE
) {
123 put_load(datapath
->tunnel_key
, MFF_TUN_ID
, 0, 24, ofpacts
);
124 put_load(outport
, mff_ovn_geneve
, 0, 32, ofpacts
);
125 put_move(MFF_LOG_INPORT
, 0, mff_ovn_geneve
, 16, 15, ofpacts
);
126 } else if (tun
->type
== STT
) {
127 put_load(datapath
->tunnel_key
| (outport
<< 24), MFF_TUN_ID
, 0, 64,
129 put_move(MFF_LOG_INPORT
, 0, MFF_TUN_ID
, 40, 15, ofpacts
);
130 } else if (tun
->type
== VXLAN
) {
131 put_load(datapath
->tunnel_key
, MFF_TUN_ID
, 0, 24, ofpacts
);
138 put_stack(enum mf_field_id field
, struct ofpact_stack
*stack
)
140 stack
->subfield
.field
= mf_from_id(field
);
141 stack
->subfield
.ofs
= 0;
142 stack
->subfield
.n_bits
= stack
->subfield
.field
->n_bits
;
145 static const struct sbrec_port_binding
*
146 get_localnet_port(struct hmap
*local_datapaths
, int64_t tunnel_key
)
148 struct local_datapath
*ld
= get_local_datapath(local_datapaths
,
150 return ld
? ld
->localnet_port
: NULL
;
154 consider_port_binding(struct hmap
*flow_table
,
155 enum mf_field_id mff_ovn_geneve
,
156 const struct simap
*ct_zones
,
157 struct hmap
*local_datapaths
,
158 struct hmap
*patched_datapaths
,
159 const struct sbrec_port_binding
*binding
,
160 struct ofpbuf
*ofpacts_p
)
162 /* Skip the port binding if the port is on a datapath that is neither
163 * local nor with any logical patch port connected, because local ports
164 * would never need to talk to those ports.
166 * Even with this approach there could still be unnecessary port
167 * bindings processed. A better approach would be a kind of "flood
170 * 1. Initialize set S to the logical datapaths that have a port
171 * located on the hypervisor.
173 * 2. For each patch port P in a logical datapath in S, add the
174 * logical datapath of the remote end of P to S. Iterate
175 * until S reaches a fixed point.
177 * This can be implemented in northd, which can generate the sets and
178 * save it on each port-binding record in SB, and ovn-controller can
179 * use the information directly. However, there can be update storms
180 * when a pair of patch ports are added/removed to connect/disconnect
181 * large lrouters and lswitches. This need to be studied further.
183 uint32_t dp_key
= binding
->datapath
->tunnel_key
;
184 uint32_t port_key
= binding
->tunnel_key
;
185 if (!get_local_datapath(local_datapaths
, dp_key
)
186 && !get_patched_datapath(patched_datapaths
, dp_key
)) {
190 /* Find the OpenFlow port for the logical port, as 'ofport'. This is
193 * - If the port is a VIF on the chassis we're managing, the
194 * OpenFlow port for the VIF. 'tun' will be NULL.
196 * The same logic handles logical patch ports, as well as
197 * localnet patch ports.
199 * For a container nested inside a VM and accessible via a VLAN,
200 * 'tag' is the VLAN ID; otherwise 'tag' is 0.
202 * For a localnet patch port, if a VLAN ID was configured, 'tag'
203 * is set to that VLAN ID; otherwise 'tag' is 0.
205 * - If the port is on a remote chassis, the OpenFlow port for a
206 * tunnel to the VIF's remote chassis. 'tun' identifies that
212 bool is_remote
= false;
213 if (binding
->parent_port
&& *binding
->parent_port
) {
217 ofport
= u16_to_ofp(simap_get(&localvif_to_ofport
,
218 binding
->parent_port
));
223 ofport
= u16_to_ofp(simap_get(&localvif_to_ofport
,
224 binding
->logical_port
));
225 if ((!strcmp(binding
->type
, "localnet")
226 || !strcmp(binding
->type
, "l2gateway"))
227 && ofport
&& binding
->tag
) {
232 const struct chassis_tunnel
*tun
= NULL
;
233 const struct sbrec_port_binding
*localnet_port
=
234 get_localnet_port(local_datapaths
, dp_key
);
236 /* It is remote port, may be reached by tunnel or localnet port */
238 if (!binding
->chassis
) {
242 ofport
= u16_to_ofp(simap_get(&localvif_to_ofport
,
243 localnet_port
->logical_port
));
248 tun
= chassis_tunnel_find(binding
->chassis
->name
);
252 ofport
= tun
->ofport
;
258 int zone_id
= simap_get(ct_zones
, binding
->logical_port
);
259 /* Packets that arrive from a vif can belong to a VM or
260 * to a container located inside that VM. Packets that
261 * arrive from containers have a tag (vlan) associated with them.
264 /* Table 0, Priority 150 and 100.
265 * ==============================
267 * Priority 150 is for tagged traffic. This may be containers in a
268 * VM or a VLAN on a local network. For such traffic, match on the
269 * tags and then strip the tag.
271 * Priority 100 is for traffic belonging to VMs or untagged locally
272 * connected networks.
274 * For both types of traffic: set MFF_LOG_INPORT to the logical
275 * input port, MFF_LOG_DATAPATH to the logical datapath, and
276 * resubmit into the logical ingress pipeline starting at table
278 ofpbuf_clear(ofpacts_p
);
279 match_init_catchall(&match
);
280 match_set_in_port(&match
, ofport
);
282 /* Match a VLAN tag and strip it, including stripping priority tags
283 * (e.g. VLAN ID 0). In the latter case we'll add a second flow
284 * for frames that lack any 802.1Q header later. */
285 if (tag
|| !strcmp(binding
->type
, "localnet")
286 || !strcmp(binding
->type
, "l2gateway")) {
287 match_set_dl_vlan(&match
, htons(tag
));
288 ofpact_put_STRIP_VLAN(ofpacts_p
);
291 /* Remember the size with just strip vlan added so far,
292 * as we're going to remove this with ofpbuf_pull() later. */
293 uint32_t ofpacts_orig_size
= ofpacts_p
->size
;
296 put_load(zone_id
, MFF_LOG_CT_ZONE
, 0, 32, ofpacts_p
);
299 int zone_id_dnat
, zone_id_snat
;
300 char *dnat
= alloc_nat_zone_key(binding
, "dnat");
301 char *snat
= alloc_nat_zone_key(binding
, "snat");
302 zone_id_dnat
= simap_get(ct_zones
, dnat
);
304 put_load(zone_id_dnat
, MFF_LOG_DNAT_ZONE
, 0, 32, ofpacts_p
);
308 zone_id_snat
= simap_get(ct_zones
, snat
);
310 put_load(zone_id_snat
, MFF_LOG_SNAT_ZONE
, 0, 32, ofpacts_p
);
314 /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */
315 put_load(dp_key
, MFF_LOG_DATAPATH
, 0, 64, ofpacts_p
);
316 put_load(port_key
, MFF_LOG_INPORT
, 0, 32, ofpacts_p
);
318 /* Resubmit to first logical ingress pipeline table. */
319 put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE
, ofpacts_p
);
320 ofctrl_add_flow(flow_table
, OFTABLE_PHY_TO_LOG
,
321 tag
? 150 : 100, &match
, ofpacts_p
);
323 if (!tag
&& (!strcmp(binding
->type
, "localnet")
324 || !strcmp(binding
->type
, "l2gateway"))) {
326 /* Add a second flow for frames that lack any 802.1Q
327 * header. For these, drop the OFPACT_STRIP_VLAN
329 ofpbuf_pull(ofpacts_p
, ofpacts_orig_size
);
330 match_set_dl_tci_masked(&match
, 0, htons(VLAN_CFI
));
331 ofctrl_add_flow(flow_table
, 0, 100, &match
, ofpacts_p
);
334 /* Table 33, priority 100.
335 * =======================
337 * Implements output to local hypervisor. Each flow matches a
338 * logical output port on the local hypervisor, and resubmits to
342 match_init_catchall(&match
);
343 ofpbuf_clear(ofpacts_p
);
345 /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
346 match_set_metadata(&match
, htonll(dp_key
));
347 match_set_reg(&match
, MFF_LOG_OUTPORT
- MFF_REG0
, port_key
);
350 put_load(zone_id
, MFF_LOG_CT_ZONE
, 0, 32, ofpacts_p
);
353 put_load(zone_id_dnat
, MFF_LOG_DNAT_ZONE
, 0, 32, ofpacts_p
);
356 put_load(zone_id_snat
, MFF_LOG_SNAT_ZONE
, 0, 32, ofpacts_p
);
359 /* Resubmit to table 34. */
360 put_resubmit(OFTABLE_DROP_LOOPBACK
, ofpacts_p
);
361 ofctrl_add_flow(flow_table
, OFTABLE_LOCAL_OUTPUT
, 100,
364 /* Table 34, Priority 100.
365 * =======================
367 * Drop packets whose logical inport and outport are the same. */
368 match_init_catchall(&match
);
369 ofpbuf_clear(ofpacts_p
);
370 match_set_metadata(&match
, htonll(dp_key
));
371 match_set_reg(&match
, MFF_LOG_INPORT
- MFF_REG0
, port_key
);
372 match_set_reg(&match
, MFF_LOG_OUTPORT
- MFF_REG0
, port_key
);
373 ofctrl_add_flow(flow_table
, OFTABLE_DROP_LOOPBACK
, 100,
376 /* Table 64, Priority 100.
377 * =======================
379 * Deliver the packet to the local vif. */
380 match_init_catchall(&match
);
381 ofpbuf_clear(ofpacts_p
);
382 match_set_metadata(&match
, htonll(dp_key
));
383 match_set_reg(&match
, MFF_LOG_OUTPORT
- MFF_REG0
, port_key
);
385 /* For containers sitting behind a local vif, tag the packets
386 * before delivering them. */
387 struct ofpact_vlan_vid
*vlan_vid
;
388 vlan_vid
= ofpact_put_SET_VLAN_VID(ofpacts_p
);
389 vlan_vid
->vlan_vid
= tag
;
390 vlan_vid
->push_vlan_if_needed
= true;
392 /* A packet might need to hair-pin back into its ingress
393 * OpenFlow port (to a different logical port, which we already
394 * checked back in table 34), so set the in_port to zero. */
395 put_stack(MFF_IN_PORT
, ofpact_put_STACK_PUSH(ofpacts_p
));
396 put_load(0, MFF_IN_PORT
, 0, 16, ofpacts_p
);
398 ofpact_put_OUTPUT(ofpacts_p
)->port
= ofport
;
400 /* Revert the tag added to the packets headed to containers
401 * in the previous step. If we don't do this, the packets
402 * that are to be broadcasted to a VM in the same logical
403 * switch will also contain the tag. Also revert the zero'd
405 ofpact_put_STRIP_VLAN(ofpacts_p
);
406 put_stack(MFF_IN_PORT
, ofpact_put_STACK_POP(ofpacts_p
));
408 ofctrl_add_flow(flow_table
, OFTABLE_LOG_TO_PHY
, 100,
411 /* Remote port connected by localnet port */
412 /* Table 33, priority 100.
413 * =======================
415 * Implements switching to localnet port. Each flow matches a
416 * logical output port on remote hypervisor, switch the output port
417 * to connected localnet port and resubmits to same table.
420 match_init_catchall(&match
);
421 ofpbuf_clear(ofpacts_p
);
423 /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
424 match_set_metadata(&match
, htonll(dp_key
));
425 match_set_reg(&match
, MFF_LOG_OUTPORT
- MFF_REG0
, port_key
);
427 put_load(localnet_port
->tunnel_key
, MFF_LOG_OUTPORT
, 0, 32, ofpacts_p
);
429 /* Resubmit to table 33. */
430 put_resubmit(OFTABLE_LOCAL_OUTPUT
, ofpacts_p
);
431 ofctrl_add_flow(flow_table
, OFTABLE_LOCAL_OUTPUT
, 100,
434 /* Remote port connected by tunnel */
435 /* Table 32, priority 100.
436 * =======================
438 * Implements output to remote hypervisors. Each flow matches an
439 * output port that includes a logical port on a remote hypervisor,
440 * and tunnels the packet to that hypervisor.
443 match_init_catchall(&match
);
444 ofpbuf_clear(ofpacts_p
);
446 /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
447 match_set_metadata(&match
, htonll(dp_key
));
448 match_set_reg(&match
, MFF_LOG_OUTPORT
- MFF_REG0
, port_key
);
450 put_encapsulation(mff_ovn_geneve
, tun
, binding
->datapath
,
451 port_key
, ofpacts_p
);
453 /* Output to tunnel. */
454 ofpact_put_OUTPUT(ofpacts_p
)->port
= ofport
;
455 ofctrl_add_flow(flow_table
, OFTABLE_REMOTE_OUTPUT
, 100,
461 consider_mc_group(struct hmap
*flow_table
,
462 enum mf_field_id mff_ovn_geneve
,
463 const struct simap
*ct_zones
,
464 struct hmap
*local_datapaths
,
465 const struct sbrec_multicast_group
*mc
,
466 struct ofpbuf
*ofpacts_p
,
467 struct ofpbuf
*remote_ofpacts_p
)
469 struct sset remote_chassis
= SSET_INITIALIZER(&remote_chassis
);
472 match_init_catchall(&match
);
473 match_set_metadata(&match
, htonll(mc
->datapath
->tunnel_key
));
474 match_set_reg(&match
, MFF_LOG_OUTPORT
- MFF_REG0
, mc
->tunnel_key
);
476 /* Go through all of the ports in the multicast group:
478 * - For remote ports, add the chassis to 'remote_chassis'.
480 * - For local ports (other than logical patch ports), add actions
481 * to 'ofpacts_p' to set the output port and resubmit.
483 * - For logical patch ports, add actions to 'remote_ofpacts_p'
484 * instead. (If we put them in 'ofpacts', then the output
485 * would happen on every hypervisor in the multicast group,
486 * effectively duplicating the packet.)
488 ofpbuf_clear(ofpacts_p
);
489 ofpbuf_clear(remote_ofpacts_p
);
490 for (size_t i
= 0; i
< mc
->n_ports
; i
++) {
491 struct sbrec_port_binding
*port
= mc
->ports
[i
];
493 if (port
->datapath
!= mc
->datapath
) {
494 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 1);
495 VLOG_WARN_RL(&rl
, UUID_FMT
": multicast group contains ports "
497 UUID_ARGS(&mc
->header_
.uuid
));
501 int zone_id
= simap_get(ct_zones
, port
->logical_port
);
503 put_load(zone_id
, MFF_LOG_CT_ZONE
, 0, 32, ofpacts_p
);
506 if (!strcmp(port
->type
, "patch")) {
507 put_load(port
->tunnel_key
, MFF_LOG_OUTPORT
, 0, 32,
509 put_resubmit(OFTABLE_DROP_LOOPBACK
, remote_ofpacts_p
);
510 } else if (simap_contains(&localvif_to_ofport
,
511 (port
->parent_port
&& *port
->parent_port
)
512 ? port
->parent_port
: port
->logical_port
)) {
513 put_load(port
->tunnel_key
, MFF_LOG_OUTPORT
, 0, 32, ofpacts_p
);
514 put_resubmit(OFTABLE_DROP_LOOPBACK
, ofpacts_p
);
515 } else if (port
->chassis
&& !get_localnet_port(local_datapaths
,
516 mc
->datapath
->tunnel_key
)) {
517 /* Add remote chassis only when localnet port not exist,
518 * otherwise multicast will reach remote ports through localnet
520 sset_add(&remote_chassis
, port
->chassis
->name
);
524 /* Table 33, priority 100.
525 * =======================
527 * Handle output to the local logical ports in the multicast group, if
529 bool local_ports
= ofpacts_p
->size
> 0;
531 /* Following delivery to local logical ports, restore the multicast
532 * group as the logical output port. */
533 put_load(mc
->tunnel_key
, MFF_LOG_OUTPORT
, 0, 32, ofpacts_p
);
535 ofctrl_add_flow(flow_table
, OFTABLE_LOCAL_OUTPUT
, 100,
539 /* Table 32, priority 100.
540 * =======================
542 * Handle output to the remote chassis in the multicast group, if
544 if (!sset_is_empty(&remote_chassis
) || remote_ofpacts_p
->size
> 0) {
545 if (remote_ofpacts_p
->size
> 0) {
546 /* Following delivery to logical patch ports, restore the
547 * multicast group as the logical output port. */
548 put_load(mc
->tunnel_key
, MFF_LOG_OUTPORT
, 0, 32,
553 const struct chassis_tunnel
*prev
= NULL
;
554 SSET_FOR_EACH (chassis
, &remote_chassis
) {
555 const struct chassis_tunnel
*tun
556 = chassis_tunnel_find(chassis
);
561 if (!prev
|| tun
->type
!= prev
->type
) {
562 put_encapsulation(mff_ovn_geneve
, tun
, mc
->datapath
,
563 mc
->tunnel_key
, remote_ofpacts_p
);
566 ofpact_put_OUTPUT(remote_ofpacts_p
)->port
= tun
->ofport
;
569 if (remote_ofpacts_p
->size
) {
571 put_resubmit(OFTABLE_LOCAL_OUTPUT
, remote_ofpacts_p
);
573 ofctrl_add_flow(flow_table
, OFTABLE_REMOTE_OUTPUT
, 100,
574 &match
, remote_ofpacts_p
);
577 sset_destroy(&remote_chassis
);
581 physical_run(struct controller_ctx
*ctx
, enum mf_field_id mff_ovn_geneve
,
582 const struct ovsrec_bridge
*br_int
, const char *this_chassis_id
,
583 const struct simap
*ct_zones
, struct hmap
*flow_table
,
584 struct hmap
*local_datapaths
, struct hmap
*patched_datapaths
)
586 for (int i
= 0; i
< br_int
->n_ports
; i
++) {
587 const struct ovsrec_port
*port_rec
= br_int
->ports
[i
];
588 if (!strcmp(port_rec
->name
, br_int
->name
)) {
592 const char *chassis_id
= smap_get(&port_rec
->external_ids
,
594 if (chassis_id
&& !strcmp(chassis_id
, this_chassis_id
)) {
598 const char *localnet
= smap_get(&port_rec
->external_ids
,
599 "ovn-localnet-port");
600 const char *l2gateway
= smap_get(&port_rec
->external_ids
,
601 "ovn-l2gateway-port");
602 const char *logpatch
= smap_get(&port_rec
->external_ids
,
603 "ovn-logical-patch-port");
605 for (int j
= 0; j
< port_rec
->n_interfaces
; j
++) {
606 const struct ovsrec_interface
*iface_rec
= port_rec
->interfaces
[j
];
608 /* Get OpenFlow port number. */
609 if (!iface_rec
->n_ofport
) {
612 int64_t ofport
= iface_rec
->ofport
[0];
613 if (ofport
< 1 || ofport
> ofp_to_u16(OFPP_MAX
)) {
617 /* Record as patch to local net, logical patch port, chassis, or
618 * local logical port. */
619 bool is_patch
= !strcmp(iface_rec
->type
, "patch");
620 if (is_patch
&& localnet
) {
621 /* localnet patch ports can be handled just like VIFs. */
622 simap_put(&localvif_to_ofport
, localnet
, ofport
);
624 } else if (is_patch
&& l2gateway
) {
625 /* L2 gateway patch ports can be handled just like VIFs. */
626 simap_put(&localvif_to_ofport
, l2gateway
, ofport
);
628 } else if (is_patch
&& logpatch
) {
629 /* Logical patch ports can be handled just like VIFs. */
630 simap_put(&localvif_to_ofport
, logpatch
, ofport
);
632 } else if (chassis_id
) {
633 enum chassis_tunnel_type tunnel_type
;
634 if (!strcmp(iface_rec
->type
, "geneve")) {
635 tunnel_type
= GENEVE
;
636 if (!mff_ovn_geneve
) {
639 } else if (!strcmp(iface_rec
->type
, "stt")) {
641 } else if (!strcmp(iface_rec
->type
, "vxlan")) {
647 struct chassis_tunnel
*tun
= xmalloc(sizeof *tun
);
648 hmap_insert(&tunnels
, &tun
->hmap_node
,
649 hash_string(chassis_id
, 0));
650 tun
->chassis_id
= chassis_id
;
651 tun
->ofport
= u16_to_ofp(ofport
);
652 tun
->type
= tunnel_type
;
655 const char *iface_id
= smap_get(&iface_rec
->external_ids
,
658 simap_put(&localvif_to_ofport
, iface_id
, ofport
);
664 struct ofpbuf ofpacts
;
665 ofpbuf_init(&ofpacts
, 0);
667 /* Set up flows in table 0 for physical-to-logical translation and in table
668 * 64 for logical-to-physical translation. */
669 const struct sbrec_port_binding
*binding
;
670 SBREC_PORT_BINDING_FOR_EACH (binding
, ctx
->ovnsb_idl
) {
671 consider_port_binding(flow_table
, mff_ovn_geneve
, ct_zones
,
672 local_datapaths
, patched_datapaths
, binding
,
676 /* Handle output to multicast groups, in tables 32 and 33. */
677 const struct sbrec_multicast_group
*mc
;
678 struct ofpbuf remote_ofpacts
;
679 ofpbuf_init(&remote_ofpacts
, 0);
680 SBREC_MULTICAST_GROUP_FOR_EACH (mc
, ctx
->ovnsb_idl
) {
681 consider_mc_group(flow_table
, mff_ovn_geneve
, ct_zones
,
682 local_datapaths
, mc
, &ofpacts
, &remote_ofpacts
);
685 ofpbuf_uninit(&remote_ofpacts
);
687 /* Table 0, priority 100.
688 * ======================
690 * Process packets that arrive from a remote hypervisor (by matching
691 * on tunnel in_port). */
693 /* Add flows for Geneve and STT encapsulations. These
694 * encapsulations have metadata about the ingress and egress logical
695 * ports. We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and
696 * MFF_LOG_OUTPORT from the tunnel key data, then resubmit to table
697 * 33 to handle packets to the local hypervisor. */
698 struct chassis_tunnel
*tun
;
699 HMAP_FOR_EACH (tun
, hmap_node
, &tunnels
) {
700 struct match match
= MATCH_CATCHALL_INITIALIZER
;
701 match_set_in_port(&match
, tun
->ofport
);
703 ofpbuf_clear(&ofpacts
);
704 if (tun
->type
== GENEVE
) {
705 put_move(MFF_TUN_ID
, 0, MFF_LOG_DATAPATH
, 0, 24, &ofpacts
);
706 put_move(mff_ovn_geneve
, 16, MFF_LOG_INPORT
, 0, 15,
708 put_move(mff_ovn_geneve
, 0, MFF_LOG_OUTPORT
, 0, 16,
710 } else if (tun
->type
== STT
) {
711 put_move(MFF_TUN_ID
, 40, MFF_LOG_INPORT
, 0, 15, &ofpacts
);
712 put_move(MFF_TUN_ID
, 24, MFF_LOG_OUTPORT
, 0, 16, &ofpacts
);
713 put_move(MFF_TUN_ID
, 0, MFF_LOG_DATAPATH
, 0, 24, &ofpacts
);
714 } else if (tun
->type
== VXLAN
) {
715 /* We'll handle VXLAN later. */
721 put_resubmit(OFTABLE_LOCAL_OUTPUT
, &ofpacts
);
723 ofctrl_add_flow(flow_table
, OFTABLE_PHY_TO_LOG
, 100, &match
, &ofpacts
);
726 /* Add flows for VXLAN encapsulations. Due to the limited amount of
727 * metadata, we only support VXLAN for connections to gateways. The
728 * VNI is used to populate MFF_LOG_DATAPATH. The gateway's logical
729 * port is set to MFF_LOG_INPORT. Then the packet is resubmitted to
730 * table 16 to determine the logical egress port.
732 * xxx Due to resubmitting to table 16, broadcasts will be re-sent to
733 * xxx all logical ports, including non-local ones which could cause
734 * xxx duplicate packets to be received by multiply-connected gateways. */
735 HMAP_FOR_EACH (tun
, hmap_node
, &tunnels
) {
736 if (tun
->type
!= VXLAN
) {
740 SBREC_PORT_BINDING_FOR_EACH (binding
, ctx
->ovnsb_idl
) {
741 struct match match
= MATCH_CATCHALL_INITIALIZER
;
743 if (!binding
->chassis
||
744 strcmp(tun
->chassis_id
, binding
->chassis
->name
)) {
748 match_set_in_port(&match
, tun
->ofport
);
749 match_set_tun_id(&match
, htonll(binding
->datapath
->tunnel_key
));
751 ofpbuf_clear(&ofpacts
);
752 put_move(MFF_TUN_ID
, 0, MFF_LOG_DATAPATH
, 0, 24, &ofpacts
);
753 put_load(binding
->tunnel_key
, MFF_LOG_INPORT
, 0, 15, &ofpacts
);
754 put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE
, &ofpacts
);
756 ofctrl_add_flow(flow_table
, OFTABLE_PHY_TO_LOG
, 100, &match
,
761 /* Table 32, Priority 0.
762 * =======================
764 * Resubmit packets that are not directed at tunnels or part of a
765 * multicast group to the local output table. */
767 match_init_catchall(&match
);
768 ofpbuf_clear(&ofpacts
);
769 put_resubmit(OFTABLE_LOCAL_OUTPUT
, &ofpacts
);
770 ofctrl_add_flow(flow_table
, OFTABLE_REMOTE_OUTPUT
, 0, &match
, &ofpacts
);
772 /* Table 34, Priority 0.
773 * =======================
775 * Resubmit packets that don't output to the ingress port (already checked
776 * in table 33) to the logical egress pipeline, clearing the logical
777 * registers (for consistent behavior with packets that get tunneled). */
778 match_init_catchall(&match
);
779 ofpbuf_clear(&ofpacts
);
780 #define MFF_LOG_REG(ID) put_load(0, ID, 0, 32, &ofpacts);
783 put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE
, &ofpacts
);
784 ofctrl_add_flow(flow_table
, OFTABLE_DROP_LOOPBACK
, 0, &match
, &ofpacts
);
786 ofpbuf_uninit(&ofpacts
);
787 simap_clear(&localvif_to_ofport
);
788 HMAP_FOR_EACH_POP (tun
, hmap_node
, &tunnels
) {
791 hmap_clear(&tunnels
);