@@ -139,8 +139,9 @@ bfd_travel_gw_related_chassis(struct local_datapath *dp,
struct local_datapath_node, node);
dp = dp_binding->dp;
free(dp_binding);
+ const struct sbrec_datapath_binding *pdp;
for (size_t i = 0; i < dp->n_peer_dps; i++) {
- const struct sbrec_datapath_binding *pdp = dp->peer_dps[i];
+ pdp = dp->peer_dps[i]->peer_dp;
if (!pdp) {
continue;
}
@@ -148,10 +148,14 @@ add_local_datapath__(struct controller_ctx *ctx,
"lport-by-datapath", &cursor);
SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, &cursor, lpval) {
+ if (!strcmp(pb->type, "chassisredirect")) {
+ ld->chassisredirect_port = pb;
+ }
if (!strcmp(pb->type, "patch")) {
const char *peer_name = smap_get(&pb->options, "peer");
if (peer_name) {
const struct sbrec_port_binding *peer;
+ struct peer_datapath *pdp;
peer = lport_lookup_by_name( ctx->ovnsb_idl, peer_name);
@@ -162,8 +166,12 @@ add_local_datapath__(struct controller_ctx *ctx,
ld->peer_dps = xrealloc(
ld->peer_dps,
ld->n_peer_dps * sizeof *ld->peer_dps);
- ld->peer_dps[ld->n_peer_dps - 1] = datapath_lookup_by_key(
+ pdp = xcalloc(1, sizeof(struct peer_datapath));
+ pdp->peer_dp = datapath_lookup_by_key(
ctx->ovnsb_idl, peer->datapath->tunnel_key);
+ pdp->patch = pb;
+ pdp->peer = peer;
+ ld->peer_dps[ld->n_peer_dps - 1] = pdp;
}
}
}
@@ -803,6 +803,9 @@ main(int argc, char *argv[])
struct local_datapath *cur_node, *next_node;
HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, &local_datapaths) {
+ for (int i = 0; i < cur_node->n_peer_dps; i++) {
+ free(cur_node->peer_dps[i]);
+ }
free(cur_node->peer_dps);
hmap_remove(&local_datapaths, &cur_node->hmap_node);
free(cur_node);
@@ -46,6 +46,17 @@ struct ct_zone_pending_entry {
enum ct_zone_pending_state state;
};
+/* Represents a peer datapath connected to a given datapath */
+struct peer_datapath {
+ const struct sbrec_datapath_binding *peer_dp;
+
+ /* Patch port connected to local datapath */
+ const struct sbrec_port_binding *patch;
+
+ /* Peer patch port connected to peer datapath */
+ const struct sbrec_port_binding *peer;
+};
+
/* A logical datapath that has some relevance to this hypervisor. A logical
* datapath D is relevant to hypervisor H if:
*
@@ -63,10 +74,13 @@ struct local_datapath {
/* The localnet port in this datapath, if any (at most one is allowed). */
const struct sbrec_port_binding *localnet_port;
+ /* The chassisredirect port in this datapath */
+ const struct sbrec_port_binding *chassisredirect_port;
+
/* True if this datapath contains an l3gateway port located on this
* hypervisor. */
bool has_local_l3gateway;
- const struct sbrec_datapath_binding **peer_dps;
+ struct peer_datapath **peer_dps;
size_t n_peer_dps;
};
@@ -539,6 +539,47 @@ consider_port_binding(struct controller_ctx *ctx,
* input port, MFF_LOG_DATAPATH to the logical datapath, and
* resubmit into the logical ingress pipeline starting at table
* 16. */
+
+ /* Match a VLAN tag and strip it. If the vlan network is connected
+ * to a router which has a gateway port on redirect-chassis,
+ * set MLF_RCV_FROM_VLAN flag, router metadata and input port to
+ * connecting patch port */
+ int vlan_tag = binding->tag ? *binding->tag : 0;
+ if (!strcmp(binding->type, "localnet") && vlan_tag) {
+ struct local_datapath *ldp = get_local_datapath(
+ local_datapaths, binding->datapath->tunnel_key);
+ for (int i = 0; i < ldp->n_peer_dps; i++) {
+ struct local_datapath *peer_ldp = get_local_datapath(
+ local_datapaths, ldp->peer_dps[i]->peer_dp->tunnel_key);
+ const struct sbrec_port_binding *crp;
+ crp = peer_ldp->chassisredirect_port;
+ if (crp && crp->chassis &&
+ !strcmp(crp->chassis->name, chassis->name)) {
+ const char *gwp = smap_get(&crp->options,
+ "distributed-port");
+ if (strcmp(gwp, ldp->peer_dps[i]->peer->logical_port)) {
+ ofpbuf_clear(ofpacts_p);
+ match_init_catchall(&match);
+
+ match_set_in_port(&match, ofport);
+ match_set_dl_vlan(&match, htons(vlan_tag));
+
+ ofpact_put_STRIP_VLAN(ofpacts_p);
+ put_load(peer_ldp->datapath->tunnel_key,
+ MFF_LOG_DATAPATH, 0, 64, ofpacts_p);
+ put_load(ldp->peer_dps[i]->peer->tunnel_key,
+ MFF_LOG_INPORT, 0, 32, ofpacts_p);
+ put_load(1, MFF_LOG_FLAGS,
+ MLF_RCV_FROM_VLAN_BIT, 1, ofpacts_p);
+ put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p);
+
+ ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG,
+ 150, 0, &match, ofpacts_p);
+ }
+ }
+ }
+ }
+
ofpbuf_clear(ofpacts_p);
match_init_catchall(&match);
match_set_in_port(&match, ofport);
@@ -639,6 +680,48 @@ consider_port_binding(struct controller_ctx *ctx,
* flow matches an output port that includes a logical port on a remote
* hypervisor, and tunnels the packet to that hypervisor.
*/
+
+ /* For each vlan network connected to the router, add that network's
+ * vlan tag to the packet and output it through localnet port */
+ struct local_datapath *ldp = get_local_datapath(local_datapaths,
+ dp_key);
+ struct ofpact_vlan_vid *vlan_vid;
+ for (int i = 0; i < ldp->n_peer_dps; i++) {
+ ofp_port_t port_ofport = 0;
+ const struct peer_datapath *pdp = ldp->peer_dps[i];
+ const struct local_datapath *peer_ldp = get_local_datapath(
+ local_datapaths, pdp->peer_dp->tunnel_key);
+ const struct sbrec_port_binding *lnp = peer_ldp->localnet_port;
+ if (lnp && pdp->patch->tunnel_key) {
+ int vlan_tag = lnp->tag ? *lnp->tag : 0;
+ if (!vlan_tag) {
+ continue;
+ }
+ port_ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
+ lnp->logical_port));
+ if (!port_ofport) {
+ continue;
+ }
+
+ match_init_catchall(&match);
+ ofpbuf_clear(ofpacts_p);
+
+ match_set_metadata(&match, htonll(dp_key));
+ match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0,
+ pdp->patch->tunnel_key);
+ match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
+
+ vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts_p);
+ vlan_vid->vlan_vid = vlan_tag;
+ vlan_vid->push_vlan_if_needed = true;
+ ofpact_put_OUTPUT(ofpacts_p)->port = port_ofport;
+ ofpact_put_STRIP_VLAN(ofpacts_p);
+
+ ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
+ &match, ofpacts_p);
+ }
+ }
+
match_init_catchall(&match);
ofpbuf_clear(ofpacts_p);
@@ -105,6 +105,10 @@ ovn_init_symtab(struct shash *symtab)
MLF_FORCE_SNAT_FOR_LB_BIT);
expr_symtab_add_subfield(symtab, "flags.force_snat_for_lb", NULL,
flags_str);
+ snprintf(flags_str, sizeof flags_str, "flags[%d]",
+ MLF_RCV_FROM_VLAN_BIT);
+ expr_symtab_add_subfield(symtab, "flags.rcv_from_vlan", NULL,
+ flags_str);
/* Connection tracking state. */
expr_symtab_add_field(symtab, "ct_mark", MFF_CT_MARK, NULL, false);
@@ -50,6 +50,7 @@ enum mff_log_flags_bits {
MLF_FORCE_SNAT_FOR_DNAT_BIT = 2,
MLF_FORCE_SNAT_FOR_LB_BIT = 3,
MLF_LOCAL_ONLY_BIT = 4,
+ MLF_RCV_FROM_VLAN_BIT = 5,
};
/* MFF_LOG_FLAGS_REG flag assignments */
@@ -75,6 +76,7 @@ enum mff_log_flags {
* hypervisors should instead only be output to local targets
*/
MLF_LOCAL_ONLY = (1 << MLF_LOCAL_ONLY_BIT),
+ MLF_RCV_FROM_VLAN = (1 << MLF_RCV_FROM_VLAN_BIT),
};
#endif /* ovn/lib/logical-fields.h */
@@ -4822,6 +4822,19 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
}
ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50,
ds_cstr(&match), "next;");
+
+ /* VLAN traffic from localnet port should be allowed for
+ * router processing on the "redirect-chassis". */
+ if (op->od->l3dgw_port && op->od->l3redirect_port && op->peer &&
+ op->peer->od->localnet_port && (op != op->od->l3dgw_port)) {
+ ds_clear(&match);
+ ds_put_format(&match, "flags.rcv_from_vlan == 1");
+ ds_put_format(&match, " && inport == %s", op->json_key);
+ ds_put_format(&match, " && is_chassis_resident(%s)",
+ op->od->l3redirect_port->json_key);
+ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 100,
+ ds_cstr(&match), "next;");
+ }
}
/* Logical router ingress table 1: IP Input. */
@@ -5870,6 +5883,25 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
}
}
+ /* Traffic from VLAN network to external network should be redirected
+ * "redirect-chassis" by setting REGBIT_NAT_REDIRECT flag.
+ * Later physical table 32 will output this traffic to gateway
+ * chassis using vlan networks */
+ HMAP_FOR_EACH (op, key_node, ports) {
+ if (op->nbrp && op->od->l3redirect_port && op->peer &&
+ op->peer->od->localnet_port &&
+ (op != op->od->l3dgw_port)) {
+ ds_clear(&match);
+ ds_put_format(&match, "inport == %s", op->json_key);
+ ds_put_format(&match, " && !is_chassis_resident(%s)",
+ op->od->l3redirect_port->json_key);
+
+ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 1,
+ ds_cstr(&match),
+ REGBIT_NAT_REDIRECT" = 1; next;");
+ }
+ }
+
/* Convert the static routes to flows. */
HMAP_FOR_EACH (od, key_node, datapaths) {
if (!od->nbr) {