|
|
5f9769 |
From 761f760a42d97184c870e892d299587e657a2c52 Mon Sep 17 00:00:00 2001
|
|
|
5f9769 |
Message-Id: <761f760a42d97184c870e892d299587e657a2c52.1610458802.git.lorenzo.bianconi@redhat.com>
|
|
|
5f9769 |
In-Reply-To: <f21c1b7a467a691847b5552d4570af706fcc5bb0.1610458802.git.lorenzo.bianconi@redhat.com>
|
|
|
5f9769 |
References: <f21c1b7a467a691847b5552d4570af706fcc5bb0.1610458802.git.lorenzo.bianconi@redhat.com>
|
|
|
5f9769 |
From: Anton Ivanov <anton.ivanov@cambridgegreys.com>
|
|
|
5f9769 |
Date: Tue, 5 Jan 2021 17:49:37 +0000
|
|
|
5f9769 |
Subject: [PATCH 10/16] ovn-northd: Move ipv4 input to a function.
|
|
|
5f9769 |
|
|
|
5f9769 |
Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
|
|
|
5f9769 |
Signed-off-by: Numan Siddique <numans@ovn.org>
|
|
|
5f9769 |
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
|
|
|
5f9769 |
---
|
|
|
5f9769 |
northd/ovn-northd.c | 499 ++++++++++++++++++++++----------------------
|
|
|
5f9769 |
1 file changed, 249 insertions(+), 250 deletions(-)
|
|
|
5f9769 |
|
|
|
5f9769 |
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
|
|
|
5f9769 |
index 7f7bb07be..f9b8d588b 100644
|
|
|
5f9769 |
--- a/northd/ovn-northd.c
|
|
|
5f9769 |
+++ b/northd/ovn-northd.c
|
|
|
5f9769 |
@@ -8924,7 +8924,7 @@ build_lrouter_force_snat_flows(struct hmap *lflows, struct ovn_datapath *od,
|
|
|
5f9769 |
}
|
|
|
5f9769 |
|
|
|
5f9769 |
static void
|
|
|
5f9769 |
-build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
5f9769 |
+build_lrouter_flows(struct hmap *datapaths,
|
|
|
5f9769 |
struct hmap *lflows, struct shash *meter_groups,
|
|
|
5f9769 |
struct hmap *lbs)
|
|
|
5f9769 |
{
|
|
|
5f9769 |
@@ -8935,254 +8935,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
5f9769 |
struct ds actions = DS_EMPTY_INITIALIZER;
|
|
|
5f9769 |
|
|
|
5f9769 |
struct ovn_datapath *od;
|
|
|
5f9769 |
- struct ovn_port *op;
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* Logical router ingress table 3: IP Input for IPv4. */
|
|
|
5f9769 |
- HMAP_FOR_EACH (op, key_node, ports) {
|
|
|
5f9769 |
- if (!op->nbrp) {
|
|
|
5f9769 |
- continue;
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- if (op->derived) {
|
|
|
5f9769 |
- /* No ingress packets are accepted on a chassisredirect
|
|
|
5f9769 |
- * port, so no need to program flows for that port. */
|
|
|
5f9769 |
- continue;
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- if (op->lrp_networks.n_ipv4_addrs) {
|
|
|
5f9769 |
- /* L3 admission control: drop packets that originate from an
|
|
|
5f9769 |
- * IPv4 address owned by the router or a broadcast address
|
|
|
5f9769 |
- * known to the router (priority 100). */
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_put_cstr(&match, "ip4.src == ");
|
|
|
5f9769 |
- op_put_v4_networks(&match, op, true);
|
|
|
5f9769 |
- ds_put_cstr(&match, " && "REGBIT_EGRESS_LOOPBACK" == 0");
|
|
|
5f9769 |
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
|
|
|
5f9769 |
- ds_cstr(&match), "drop;",
|
|
|
5f9769 |
- &op->nbrp->header_);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* ICMP echo reply. These flows reply to ICMP echo requests
|
|
|
5f9769 |
- * received for the router's IP address. Since packets only
|
|
|
5f9769 |
- * get here as part of the logical router datapath, the inport
|
|
|
5f9769 |
- * (i.e. the incoming locally attached net) does not matter.
|
|
|
5f9769 |
- * The ip.ttl also does not matter (RFC1812 section 4.2.2.9) */
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_put_cstr(&match, "ip4.dst == ");
|
|
|
5f9769 |
- op_put_v4_networks(&match, op, false);
|
|
|
5f9769 |
- ds_put_cstr(&match, " && icmp4.type == 8 && icmp4.code == 0");
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- const char * icmp_actions = "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
- "ip.ttl = 255; "
|
|
|
5f9769 |
- "icmp4.type = 0; "
|
|
|
5f9769 |
- "flags.loopback = 1; "
|
|
|
5f9769 |
- "next; ";
|
|
|
5f9769 |
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
|
|
|
5f9769 |
- ds_cstr(&match), icmp_actions,
|
|
|
5f9769 |
- &op->nbrp->header_);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* ICMP time exceeded */
|
|
|
5f9769 |
- for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_clear(&actions);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- ds_put_format(&match,
|
|
|
5f9769 |
- "inport == %s && ip4 && "
|
|
|
5f9769 |
- "ip.ttl == {0, 1} && !ip.later_frag", op->json_key);
|
|
|
5f9769 |
- ds_put_format(&actions,
|
|
|
5f9769 |
- "icmp4 {"
|
|
|
5f9769 |
- "eth.dst <-> eth.src; "
|
|
|
5f9769 |
- "icmp4.type = 11; /* Time exceeded */ "
|
|
|
5f9769 |
- "icmp4.code = 0; /* TTL exceeded in transit */ "
|
|
|
5f9769 |
- "ip4.dst = ip4.src; "
|
|
|
5f9769 |
- "ip4.src = %s; "
|
|
|
5f9769 |
- "ip.ttl = 255; "
|
|
|
5f9769 |
- "next; };",
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40,
|
|
|
5f9769 |
- ds_cstr(&match), ds_cstr(&actions),
|
|
|
5f9769 |
- &op->nbrp->header_);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* ARP reply. These flows reply to ARP requests for the router's own
|
|
|
5f9769 |
- * IP address. */
|
|
|
5f9769 |
- for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_put_format(&match, "arp.spa == %s/%u",
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].network_s,
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].plen);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- if (op->od->l3dgw_port && op->od->l3redirect_port && op->peer
|
|
|
5f9769 |
- && op->peer->od->n_localnet_ports) {
|
|
|
5f9769 |
- bool add_chassis_resident_check = false;
|
|
|
5f9769 |
- if (op == op->od->l3dgw_port) {
|
|
|
5f9769 |
- /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s
|
|
|
5f9769 |
- * should only be sent from the gateway chassis, so that
|
|
|
5f9769 |
- * upstream MAC learning points to the gateway chassis.
|
|
|
5f9769 |
- * Also need to avoid generation of multiple ARP responses
|
|
|
5f9769 |
- * from different chassis. */
|
|
|
5f9769 |
- add_chassis_resident_check = true;
|
|
|
5f9769 |
- } else {
|
|
|
5f9769 |
- /* Check if the option 'reside-on-redirect-chassis'
|
|
|
5f9769 |
- * is set to true on the router port. If set to true
|
|
|
5f9769 |
- * and if peer's logical switch has a localnet port, it
|
|
|
5f9769 |
- * means the router pipeline for the packets from
|
|
|
5f9769 |
- * peer's logical switch is be run on the chassis
|
|
|
5f9769 |
- * hosting the gateway port and it should reply to the
|
|
|
5f9769 |
- * ARP requests for the router port IPs.
|
|
|
5f9769 |
- */
|
|
|
5f9769 |
- add_chassis_resident_check = smap_get_bool(
|
|
|
5f9769 |
- &op->nbrp->options,
|
|
|
5f9769 |
- "reside-on-redirect-chassis", false);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- if (add_chassis_resident_check) {
|
|
|
5f9769 |
- ds_put_format(&match, " && is_chassis_resident(%s)",
|
|
|
5f9769 |
- op->od->l3redirect_port->json_key);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- build_lrouter_arp_flow(op->od, op,
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].addr_s,
|
|
|
5f9769 |
- REG_INPORT_ETH_ADDR, &match, false, 90,
|
|
|
5f9769 |
- &op->nbrp->header_, lflows);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* A set to hold all load-balancer vips that need ARP responses. */
|
|
|
5f9769 |
- struct sset all_ips_v4 = SSET_INITIALIZER(&all_ips_v4);
|
|
|
5f9769 |
- struct sset all_ips_v6 = SSET_INITIALIZER(&all_ips_v6);
|
|
|
5f9769 |
- get_router_load_balancer_ips(op->od, &all_ips_v4, &all_ips_v6);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- const char *ip_address;
|
|
|
5f9769 |
- SSET_FOR_EACH (ip_address, &all_ips_v4) {
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- if (op == op->od->l3dgw_port) {
|
|
|
5f9769 |
- ds_put_format(&match, "is_chassis_resident(%s)",
|
|
|
5f9769 |
- op->od->l3redirect_port->json_key);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- build_lrouter_arp_flow(op->od, op,
|
|
|
5f9769 |
- ip_address, REG_INPORT_ETH_ADDR,
|
|
|
5f9769 |
- &match, false, 90, NULL, lflows);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- SSET_FOR_EACH (ip_address, &all_ips_v6) {
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- if (op == op->od->l3dgw_port) {
|
|
|
5f9769 |
- ds_put_format(&match, "is_chassis_resident(%s)",
|
|
|
5f9769 |
- op->od->l3redirect_port->json_key);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- build_lrouter_nd_flow(op->od, op, "nd_na",
|
|
|
5f9769 |
- ip_address, NULL, REG_INPORT_ETH_ADDR,
|
|
|
5f9769 |
- &match, false, 90, NULL, lflows);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- sset_destroy(&all_ips_v4);
|
|
|
5f9769 |
- sset_destroy(&all_ips_v6);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- if (!smap_get(&op->od->nbr->options, "chassis")
|
|
|
5f9769 |
- && !op->od->l3dgw_port) {
|
|
|
5f9769 |
- /* UDP/TCP port unreachable. */
|
|
|
5f9769 |
- for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_put_format(&match,
|
|
|
5f9769 |
- "ip4 && ip4.dst == %s && !ip.later_frag && udp",
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
- const char *action = "icmp4 {"
|
|
|
5f9769 |
- "eth.dst <-> eth.src; "
|
|
|
5f9769 |
- "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
- "ip.ttl = 255; "
|
|
|
5f9769 |
- "icmp4.type = 3; "
|
|
|
5f9769 |
- "icmp4.code = 3; "
|
|
|
5f9769 |
- "next; };";
|
|
|
5f9769 |
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
|
|
|
5f9769 |
- 80, ds_cstr(&match), action,
|
|
|
5f9769 |
- &op->nbrp->header_);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_put_format(&match,
|
|
|
5f9769 |
- "ip4 && ip4.dst == %s && !ip.later_frag && tcp",
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
- action = "tcp_reset {"
|
|
|
5f9769 |
- "eth.dst <-> eth.src; "
|
|
|
5f9769 |
- "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
- "next; };";
|
|
|
5f9769 |
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
|
|
|
5f9769 |
- 80, ds_cstr(&match), action,
|
|
|
5f9769 |
- &op->nbrp->header_);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- ds_clear(&match);
|
|
|
5f9769 |
- ds_put_format(&match,
|
|
|
5f9769 |
- "ip4 && ip4.dst == %s && !ip.later_frag",
|
|
|
5f9769 |
- op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
- action = "icmp4 {"
|
|
|
5f9769 |
- "eth.dst <-> eth.src; "
|
|
|
5f9769 |
- "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
- "ip.ttl = 255; "
|
|
|
5f9769 |
- "icmp4.type = 3; "
|
|
|
5f9769 |
- "icmp4.code = 2; "
|
|
|
5f9769 |
- "next; };";
|
|
|
5f9769 |
- ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
|
|
|
5f9769 |
- 70, ds_cstr(&match), action,
|
|
|
5f9769 |
- &op->nbrp->header_);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* Drop IP traffic destined to router owned IPs except if the IP is
|
|
|
5f9769 |
- * also a SNAT IP. Those are dropped later, in stage
|
|
|
5f9769 |
- * "lr_in_arp_resolve", if unSNAT was unsuccessful.
|
|
|
5f9769 |
- *
|
|
|
5f9769 |
- * Priority 60.
|
|
|
5f9769 |
- */
|
|
|
5f9769 |
- build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false,
|
|
|
5f9769 |
- lflows);
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* ARP / ND handling for external IP addresses.
|
|
|
5f9769 |
- *
|
|
|
5f9769 |
- * DNAT and SNAT IP addresses are external IP addresses that need ARP
|
|
|
5f9769 |
- * handling.
|
|
|
5f9769 |
- *
|
|
|
5f9769 |
- * These are already taken care globally, per router. The only
|
|
|
5f9769 |
- * exception is on the l3dgw_port where we might need to use a
|
|
|
5f9769 |
- * different ETH address.
|
|
|
5f9769 |
- */
|
|
|
5f9769 |
- if (op != op->od->l3dgw_port) {
|
|
|
5f9769 |
- continue;
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
|
|
|
5f9769 |
- struct ovn_nat *nat_entry = &op->od->nat_entries[i];
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* Skip entries we failed to parse. */
|
|
|
5f9769 |
- if (!nat_entry_is_valid(nat_entry)) {
|
|
|
5f9769 |
- continue;
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* Skip SNAT entries for now, we handle unique SNAT IPs separately
|
|
|
5f9769 |
- * below.
|
|
|
5f9769 |
- */
|
|
|
5f9769 |
- if (!strcmp(nat_entry->nb->type, "snat")) {
|
|
|
5f9769 |
- continue;
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
- build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- /* Now handle SNAT entries too, one per unique SNAT IP. */
|
|
|
5f9769 |
- struct shash_node *snat_snode;
|
|
|
5f9769 |
- SHASH_FOR_EACH (snat_snode, &op->od->snat_ips) {
|
|
|
5f9769 |
- struct ovn_snat_ip *snat_ip = snat_snode->data;
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- if (ovs_list_is_empty(&snat_ip->snat_entries)) {
|
|
|
5f9769 |
- continue;
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
-
|
|
|
5f9769 |
- struct ovn_nat *nat_entry =
|
|
|
5f9769 |
- CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
|
|
|
5f9769 |
- struct ovn_nat, ext_addr_list_node);
|
|
|
5f9769 |
- build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows);
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
- }
|
|
|
5f9769 |
|
|
|
5f9769 |
/* NAT, Defrag and load balancing. */
|
|
|
5f9769 |
HMAP_FOR_EACH (od, key_node, datapaths) {
|
|
|
5f9769 |
@@ -11310,6 +11062,251 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od,
|
|
|
5f9769 |
}
|
|
|
5f9769 |
}
|
|
|
5f9769 |
|
|
|
5f9769 |
+/* Logical router ingress table 3: IP Input for IPv4. */
|
|
|
5f9769 |
+static void
|
|
|
5f9769 |
+build_lrouter_ipv4_ip_input(struct ovn_port *op,
|
|
|
5f9769 |
+ struct hmap *lflows,
|
|
|
5f9769 |
+ struct ds *match, struct ds *actions)
|
|
|
5f9769 |
+{
|
|
|
5f9769 |
+ /* No ingress packets are accepted on a chassisredirect
|
|
|
5f9769 |
+ * port, so no need to program flows for that port. */
|
|
|
5f9769 |
+ if (op->nbrp && (!op->derived)) {
|
|
|
5f9769 |
+ if (op->lrp_networks.n_ipv4_addrs) {
|
|
|
5f9769 |
+ /* L3 admission control: drop packets that originate from an
|
|
|
5f9769 |
+ * IPv4 address owned by the router or a broadcast address
|
|
|
5f9769 |
+ * known to the router (priority 100). */
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_put_cstr(match, "ip4.src == ");
|
|
|
5f9769 |
+ op_put_v4_networks(match, op, true);
|
|
|
5f9769 |
+ ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0");
|
|
|
5f9769 |
+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
|
|
|
5f9769 |
+ ds_cstr(match), "drop;",
|
|
|
5f9769 |
+ &op->nbrp->header_);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* ICMP echo reply. These flows reply to ICMP echo requests
|
|
|
5f9769 |
+ * received for the router's IP address. Since packets only
|
|
|
5f9769 |
+ * get here as part of the logical router datapath, the inport
|
|
|
5f9769 |
+ * (i.e. the incoming locally attached net) does not matter.
|
|
|
5f9769 |
+ * The ip.ttl also does not matter (RFC1812 section 4.2.2.9) */
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_put_cstr(match, "ip4.dst == ");
|
|
|
5f9769 |
+ op_put_v4_networks(match, op, false);
|
|
|
5f9769 |
+ ds_put_cstr(match, " && icmp4.type == 8 && icmp4.code == 0");
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ const char * icmp_actions = "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
+ "ip.ttl = 255; "
|
|
|
5f9769 |
+ "icmp4.type = 0; "
|
|
|
5f9769 |
+ "flags.loopback = 1; "
|
|
|
5f9769 |
+ "next; ";
|
|
|
5f9769 |
+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
|
|
|
5f9769 |
+ ds_cstr(match), icmp_actions,
|
|
|
5f9769 |
+ &op->nbrp->header_);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* ICMP time exceeded */
|
|
|
5f9769 |
+ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_clear(actions);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ ds_put_format(match,
|
|
|
5f9769 |
+ "inport == %s && ip4 && "
|
|
|
5f9769 |
+ "ip.ttl == {0, 1} && !ip.later_frag", op->json_key);
|
|
|
5f9769 |
+ ds_put_format(actions,
|
|
|
5f9769 |
+ "icmp4 {"
|
|
|
5f9769 |
+ "eth.dst <-> eth.src; "
|
|
|
5f9769 |
+ "icmp4.type = 11; /* Time exceeded */ "
|
|
|
5f9769 |
+ "icmp4.code = 0; /* TTL exceeded in transit */ "
|
|
|
5f9769 |
+ "ip4.dst = ip4.src; "
|
|
|
5f9769 |
+ "ip4.src = %s; "
|
|
|
5f9769 |
+ "ip.ttl = 255; "
|
|
|
5f9769 |
+ "next; };",
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40,
|
|
|
5f9769 |
+ ds_cstr(match), ds_cstr(actions),
|
|
|
5f9769 |
+ &op->nbrp->header_);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* ARP reply. These flows reply to ARP requests for the router's own
|
|
|
5f9769 |
+ * IP address. */
|
|
|
5f9769 |
+ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_put_format(match, "arp.spa == %s/%u",
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].network_s,
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].plen);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ if (op->od->l3dgw_port && op->od->l3redirect_port && op->peer
|
|
|
5f9769 |
+ && op->peer->od->n_localnet_ports) {
|
|
|
5f9769 |
+ bool add_chassis_resident_check = false;
|
|
|
5f9769 |
+ if (op == op->od->l3dgw_port) {
|
|
|
5f9769 |
+ /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s
|
|
|
5f9769 |
+ * should only be sent from the gateway chassis, so that
|
|
|
5f9769 |
+ * upstream MAC learning points to the gateway chassis.
|
|
|
5f9769 |
+ * Also need to avoid generation of multiple ARP responses
|
|
|
5f9769 |
+ * from different chassis. */
|
|
|
5f9769 |
+ add_chassis_resident_check = true;
|
|
|
5f9769 |
+ } else {
|
|
|
5f9769 |
+ /* Check if the option 'reside-on-redirect-chassis'
|
|
|
5f9769 |
+ * is set to true on the router port. If set to true
|
|
|
5f9769 |
+ * and if peer's logical switch has a localnet port, it
|
|
|
5f9769 |
+ * means the router pipeline for the packets from
|
|
|
5f9769 |
+ * peer's logical switch is be run on the chassis
|
|
|
5f9769 |
+ * hosting the gateway port and it should reply to the
|
|
|
5f9769 |
+ * ARP requests for the router port IPs.
|
|
|
5f9769 |
+ */
|
|
|
5f9769 |
+ add_chassis_resident_check = smap_get_bool(
|
|
|
5f9769 |
+ &op->nbrp->options,
|
|
|
5f9769 |
+ "reside-on-redirect-chassis", false);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ if (add_chassis_resident_check) {
|
|
|
5f9769 |
+ ds_put_format(match, " && is_chassis_resident(%s)",
|
|
|
5f9769 |
+ op->od->l3redirect_port->json_key);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ build_lrouter_arp_flow(op->od, op,
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].addr_s,
|
|
|
5f9769 |
+ REG_INPORT_ETH_ADDR, match, false, 90,
|
|
|
5f9769 |
+ &op->nbrp->header_, lflows);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* A set to hold all load-balancer vips that need ARP responses. */
|
|
|
5f9769 |
+ struct sset all_ips_v4 = SSET_INITIALIZER(&all_ips_v4);
|
|
|
5f9769 |
+ struct sset all_ips_v6 = SSET_INITIALIZER(&all_ips_v6);
|
|
|
5f9769 |
+ get_router_load_balancer_ips(op->od, &all_ips_v4, &all_ips_v6);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ const char *ip_address;
|
|
|
5f9769 |
+ SSET_FOR_EACH (ip_address, &all_ips_v4) {
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ if (op == op->od->l3dgw_port) {
|
|
|
5f9769 |
+ ds_put_format(match, "is_chassis_resident(%s)",
|
|
|
5f9769 |
+ op->od->l3redirect_port->json_key);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ build_lrouter_arp_flow(op->od, op,
|
|
|
5f9769 |
+ ip_address, REG_INPORT_ETH_ADDR,
|
|
|
5f9769 |
+ match, false, 90, NULL, lflows);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ SSET_FOR_EACH (ip_address, &all_ips_v6) {
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ if (op == op->od->l3dgw_port) {
|
|
|
5f9769 |
+ ds_put_format(match, "is_chassis_resident(%s)",
|
|
|
5f9769 |
+ op->od->l3redirect_port->json_key);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ build_lrouter_nd_flow(op->od, op, "nd_na",
|
|
|
5f9769 |
+ ip_address, NULL, REG_INPORT_ETH_ADDR,
|
|
|
5f9769 |
+ match, false, 90, NULL, lflows);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ sset_destroy(&all_ips_v4);
|
|
|
5f9769 |
+ sset_destroy(&all_ips_v6);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ if (!smap_get(&op->od->nbr->options, "chassis")
|
|
|
5f9769 |
+ && !op->od->l3dgw_port) {
|
|
|
5f9769 |
+ /* UDP/TCP port unreachable. */
|
|
|
5f9769 |
+ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_put_format(match,
|
|
|
5f9769 |
+ "ip4 && ip4.dst == %s && !ip.later_frag && udp",
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
+ const char *action = "icmp4 {"
|
|
|
5f9769 |
+ "eth.dst <-> eth.src; "
|
|
|
5f9769 |
+ "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
+ "ip.ttl = 255; "
|
|
|
5f9769 |
+ "icmp4.type = 3; "
|
|
|
5f9769 |
+ "icmp4.code = 3; "
|
|
|
5f9769 |
+ "next; };";
|
|
|
5f9769 |
+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
|
|
|
5f9769 |
+ 80, ds_cstr(match), action,
|
|
|
5f9769 |
+ &op->nbrp->header_);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_put_format(match,
|
|
|
5f9769 |
+ "ip4 && ip4.dst == %s && !ip.later_frag && tcp",
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
+ action = "tcp_reset {"
|
|
|
5f9769 |
+ "eth.dst <-> eth.src; "
|
|
|
5f9769 |
+ "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
+ "next; };";
|
|
|
5f9769 |
+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
|
|
|
5f9769 |
+ 80, ds_cstr(match), action,
|
|
|
5f9769 |
+ &op->nbrp->header_);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ ds_clear(match);
|
|
|
5f9769 |
+ ds_put_format(match,
|
|
|
5f9769 |
+ "ip4 && ip4.dst == %s && !ip.later_frag",
|
|
|
5f9769 |
+ op->lrp_networks.ipv4_addrs[i].addr_s);
|
|
|
5f9769 |
+ action = "icmp4 {"
|
|
|
5f9769 |
+ "eth.dst <-> eth.src; "
|
|
|
5f9769 |
+ "ip4.dst <-> ip4.src; "
|
|
|
5f9769 |
+ "ip.ttl = 255; "
|
|
|
5f9769 |
+ "icmp4.type = 3; "
|
|
|
5f9769 |
+ "icmp4.code = 2; "
|
|
|
5f9769 |
+ "next; };";
|
|
|
5f9769 |
+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT,
|
|
|
5f9769 |
+ 70, ds_cstr(match), action,
|
|
|
5f9769 |
+ &op->nbrp->header_);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* Drop IP traffic destined to router owned IPs except if the IP is
|
|
|
5f9769 |
+ * also a SNAT IP. Those are dropped later, in stage
|
|
|
5f9769 |
+ * "lr_in_arp_resolve", if unSNAT was unsuccessful.
|
|
|
5f9769 |
+ *
|
|
|
5f9769 |
+ * Priority 60.
|
|
|
5f9769 |
+ */
|
|
|
5f9769 |
+ build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false,
|
|
|
5f9769 |
+ lflows);
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* ARP / ND handling for external IP addresses.
|
|
|
5f9769 |
+ *
|
|
|
5f9769 |
+ * DNAT and SNAT IP addresses are external IP addresses that need ARP
|
|
|
5f9769 |
+ * handling.
|
|
|
5f9769 |
+ *
|
|
|
5f9769 |
+ * These are already taken care globally, per router. The only
|
|
|
5f9769 |
+ * exception is on the l3dgw_port where we might need to use a
|
|
|
5f9769 |
+ * different ETH address.
|
|
|
5f9769 |
+ */
|
|
|
5f9769 |
+ if (op != op->od->l3dgw_port) {
|
|
|
5f9769 |
+ return;
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
|
|
|
5f9769 |
+ struct ovn_nat *nat_entry = &op->od->nat_entries[i];
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* Skip entries we failed to parse. */
|
|
|
5f9769 |
+ if (!nat_entry_is_valid(nat_entry)) {
|
|
|
5f9769 |
+ continue;
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* Skip SNAT entries for now, we handle unique SNAT IPs separately
|
|
|
5f9769 |
+ * below.
|
|
|
5f9769 |
+ */
|
|
|
5f9769 |
+ if (!strcmp(nat_entry->nb->type, "snat")) {
|
|
|
5f9769 |
+ continue;
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+ build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ /* Now handle SNAT entries too, one per unique SNAT IP. */
|
|
|
5f9769 |
+ struct shash_node *snat_snode;
|
|
|
5f9769 |
+ SHASH_FOR_EACH (snat_snode, &op->od->snat_ips) {
|
|
|
5f9769 |
+ struct ovn_snat_ip *snat_ip = snat_snode->data;
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ if (ovs_list_is_empty(&snat_ip->snat_entries)) {
|
|
|
5f9769 |
+ continue;
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+
|
|
|
5f9769 |
+ struct ovn_nat *nat_entry =
|
|
|
5f9769 |
+ CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries),
|
|
|
5f9769 |
+ struct ovn_nat, ext_addr_list_node);
|
|
|
5f9769 |
+ build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows);
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+ }
|
|
|
5f9769 |
+}
|
|
|
5f9769 |
+
|
|
|
5f9769 |
|
|
|
5f9769 |
struct lswitch_flow_build_info {
|
|
|
5f9769 |
struct hmap *datapaths;
|
|
|
5f9769 |
@@ -11404,6 +11401,8 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op,
|
|
|
5f9769 |
build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match);
|
|
|
5f9769 |
build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows,
|
|
|
5f9769 |
&lsi->match, &lsi->actions);
|
|
|
5f9769 |
+ build_lrouter_ipv4_ip_input(op, lsi->lflows,
|
|
|
5f9769 |
+ &lsi->match, &lsi->actions);
|
|
|
5f9769 |
}
|
|
|
5f9769 |
|
|
|
5f9769 |
static void
|
|
|
5f9769 |
@@ -11462,7 +11461,7 @@ build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
|
|
|
5f9769 |
build_lswitch_flows(datapaths, lflows);
|
|
|
5f9769 |
|
|
|
5f9769 |
/* Legacy lrouter build - to be migrated. */
|
|
|
5f9769 |
- build_lrouter_flows(datapaths, ports, lflows, meter_groups, lbs);
|
|
|
5f9769 |
+ build_lrouter_flows(datapaths, lflows, meter_groups, lbs);
|
|
|
5f9769 |
}
|
|
|
5f9769 |
|
|
|
5f9769 |
struct ovn_dp_group {
|
|
|
5f9769 |
--
|
|
|
5f9769 |
2.29.2
|
|
|
5f9769 |
|