@@ -2157,8 +2157,47 @@ get_nat_addresses_and_keys(struct controller_ctx *ctx,
const struct sbrec_chassis *chassis,
const struct chassis_index *chassis_index,
struct sset *active_tunnels,
- struct shash *nat_addresses)
+ struct shash *nat_addresses,
+ struct hmap *local_datapaths)
{
+ /* When a router has tenant vlan networks, gARP for distributed gateway
+ * router port has to be sent through internal tenant vlan network's
+ * localnet port, so that external switches can learn this MAC and forward
+ * tenant vlan network traffic with distributed gateway router port MAC
+ * as destination MAC address */
+
+ struct local_datapath *ldp;
+ struct shash router_vlan_ports;
+
+ shash_init(&router_vlan_ports);
+ HMAP_FOR_EACH (ldp, hmap_node, local_datapaths) {
+ const struct sbrec_port_binding *crp;
+ crp = ldp->chassisredirect_port;
+ /* check if it a router with chassis redirect port,
+ * get corresponding distributed port */
+ if (crp && crp->chassis &&
+ !strcmp(crp->chassis->name, chassis->name)) {
+ const struct sbrec_port_binding *dp = NULL;
+ for (int i = 0; i < ldp->n_peer_dps; i++) {
+ if (!strcmp(ldp->peer_dps[i]->patch->logical_port,
+ smap_get(&crp->options, "distributed-port"))) {
+ dp = ldp->peer_dps[i]->peer;
+ break;
+ }
+ }
+
+ /* Save router internal port (patch port on tenant vlan network)
+ * along with distributed port. */
+ for (int i = 0; i < ldp->n_peer_dps; i++) {
+ if (strcmp(ldp->peer_dps[i]->patch->logical_port,
+ smap_get(&crp->options, "distributed-port"))) {
+ shash_add(&router_vlan_ports,
+ ldp->peer_dps[i]->peer->logical_port, dp);
+ }
+ }
+ }
+ }
+
const char *gw_port;
SSET_FOR_EACH(gw_port, local_l3gw_ports) {
const struct sbrec_port_binding *pb;
@@ -2168,9 +2207,14 @@ get_nat_addresses_and_keys(struct controller_ctx *ctx,
continue;
}
- if (pb->n_nat_addresses) {
- for (int i = 0; i < pb->n_nat_addresses; i++) {
- consider_nat_address(ctx, pb->nat_addresses[i], pb,
+ /* Router internatl ports should send gARP for distributed port
+ * NAT addresses */
+ const struct sbrec_port_binding *dp;
+ dp = shash_find_data(&router_vlan_ports, pb->logical_port);
+ const struct sbrec_port_binding *nat_port = dp ? dp : pb;
+ if (nat_port->n_nat_addresses) {
+ for (int i = 0; i < nat_port->n_nat_addresses; i++) {
+ consider_nat_address(ctx, nat_port->nat_addresses[i], pb,
nat_address_keys, chassis,
chassis_index, active_tunnels,
nat_addresses);
@@ -2178,7 +2222,7 @@ get_nat_addresses_and_keys(struct controller_ctx *ctx,
} else {
/* Continue to support options:nat-addresses for version
* upgrade. */
- const char *nat_addresses_options = smap_get(&pb->options,
+ const char *nat_addresses_options = smap_get(&nat_port->options,
"nat-addresses");
if (nat_addresses_options) {
consider_nat_address(ctx, nat_addresses_options, pb,
@@ -2188,6 +2232,7 @@ get_nat_addresses_and_keys(struct controller_ctx *ctx,
}
}
}
+ shash_destroy(&router_vlan_ports);
}
static void
@@ -2217,7 +2262,7 @@ send_garp_run(struct controller_ctx *ctx,
get_nat_addresses_and_keys(ctx, &nat_ip_keys, &local_l3gw_ports,
chassis, chassis_index, active_tunnels,
- &nat_addresses);
+ &nat_addresses, local_datapaths);
/* For deleted ports and deleted nat ips, remove from send_garp_data. */
struct shash_node *iter, *next;
SHASH_FOR_EACH_SAFE (iter, next, &send_garp_data) {
@@ -4993,6 +4993,63 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
ds_cstr(&match), ds_cstr(&actions));
}
+ /* ARP requests for distributed port IP address but coming from router
+ * internal network vlan, should be replied through router internal
+ * network vlan ports */
+ if (op->od->l3dgw_port && op == op->od->l3dgw_port
+ && op->od->l3redirect_port) {
+ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
+ ds_clear(&match);
+ ds_put_format(&match,
+ "flags.rcv_from_vlan == 1 && "
+ "arp.tpa == %s && arp.op == 1 && "
+ "is_chassis_resident(%s)",
+ op->lrp_networks.ipv4_addrs[i].addr_s,
+ op->od->l3redirect_port->json_key);
+
+ ds_clear(&actions);
+ ds_put_format(&actions,
+ "eth.dst = eth.src; "
+ "eth.src = %s; "
+ "arp.op = 2; /* ARP reply */ "
+ "arp.tha = arp.sha; "
+ "arp.sha = %s; "
+ "arp.tpa = arp.spa; "
+ "arp.spa = %s; "
+ "flags.loopback = 1; ",
+ op->lrp_networks.ea_s,
+ op->lrp_networks.ea_s,
+ op->lrp_networks.ipv4_addrs[i].addr_s);
+
+ /* Add internal vlan network ports as output ports */
+ bool router_ports_exist = false;
+ struct ovn_datapath *dp;
+ HMAP_FOR_EACH (dp, key_node, datapaths) {
+ if (!dp->nbs) {
+ continue;
+ }
+ if (!dp->localnet_port) {
+ continue;
+ }
+ for (size_t j = 0; j < dp->n_router_ports; j++) {
+ struct ovn_port *rp = dp->router_ports[j];
+ if (rp->peer && rp->peer->od == op->od &&
+ rp->peer != op) {
+ router_ports_exist = true;
+ ds_put_format(&actions,
+ "outport = %s; "
+ "output;",
+ rp->peer->json_key);
+ }
+ }
+ }
+ if (router_ports_exist) {
+ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
+ ds_cstr(&match), ds_cstr(&actions));
+ }
+ }
+ }
+
/* A set to hold all load-balancer vips that need ARP responses. */
struct sset all_ips = SSET_INITIALIZER(&all_ips);
int addr_family;
@@ -7889,6 +7889,12 @@ foo_mac="000001010203"
gw_mac="000002010203"
nexthop_mac="f00000010204"
+# gARP for distributed port has to be sent through router internal patch port
+# which is connected to vlan network
+garp=ffffffffffff${gw_mac}8100000208060001080006040001${gw_mac}${gw_ip}000000000000${gw_ip}
+echo $garp >> hv1-br-ex_n2-rx.expected
+OVN_CHECK_PACKETS([hv1/br-ex_n2-rx.pcap], [hv1-br-ex_n2-rx.expected])
+
# Send ip packet from foo1 to 8.8.8.8
src_mac="f00000010203"
dst_mac="000001010203"