From 509afdc3df6b256d44f74068ad559c9ff0afc17e Mon Sep 17 00:00:00 2001 From: Gurucharan Shetty Date: Sun, 27 Mar 2016 06:25:57 -0700 Subject: [PATCH] ovn-northd: Fix peering of routers. 1. Currently, the ovn-nb man page says that the 'peer' in a logical_router_port table should point to the name of the peer's logical router port. But the schema had declared this column as a uuid. This looks not to be the intention as peers for logical switches connected to routers is a name (and not a uuid). So this patch changes the schema to be name. 2. In the southbound database, in the port_binding table, for a logical_router_port, the peer was pointing back to itself. This was causing ovn-controller to create patch ports where the peer was wrongly pointing back to the source itself. This clearly looks to be an error. So this patch fixes the peer in southbound database to correclty point to the real peer. 3. ovn-northd.c currently skips generating logical flows to transfer packets between two peers with comment about needing 'ARP for neighboring routers'. It looked to me that since the router peer is a logical object that has to be created in OVN-NB database, we always need to statically assign the mac address. So this patch picks the mac address from the database. Signed-off-by: Gurucharan Shetty Acked-by: Ben Pfaff Acked-by: Ryan Moats --- ovn/northd/ovn-northd.8.xml | 9 +++ ovn/northd/ovn-northd.c | 28 ++++++- ovn/ovn-nb.ovsschema | 9 +-- tests/ovn.at | 155 ++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 8 deletions(-) diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml index 743c939c2..465b7c7de 100644 --- a/ovn/northd/ovn-northd.8.xml +++ b/ovn/northd/ovn-northd.8.xml @@ -746,6 +746,15 @@ icmp4 { A has actions eth.dst = E; next;.

+ +

+ For each logical router port with an IP address A and + a mac address of E that is reachable via a different + logical router port P, a priority-100 flow with + match outport === P && reg0 == + A has actions eth.dst = E; + next;. +

  • diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 0c869f43d..4b1d61122 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -669,7 +669,7 @@ join_logical_ports(struct northd_context *ctx, sizeof *op->od->router_ports * (op->od->n_router_ports + 1)); op->od->router_ports[op->od->n_router_ports++] = op; } else if (op->nbr && op->nbr->peer) { - op->peer = ovn_port_find(ports, op->nbr->name); + op->peer = ovn_port_find(ports, op->nbr->peer); } } } @@ -1962,7 +1962,31 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * Ethernet address in eth.dst. */ HMAP_FOR_EACH (op, key_node, ports) { if (op->nbr) { - /* XXX ARP for neighboring router */ + /* This is a logical router port. If next-hop IP address in 'reg0' + * matches ip address of this router port, then the packet is + * intended to eventually be sent to this logical port. Set the + * destination mac address using this port's mac address. + * + * The packet is still in peer's logical pipeline. So the match + * should be on peer's outport. */ + if (op->nbr->peer) { + struct ovn_port *peer = ovn_port_find(ports, op->nbr->peer); + if (!peer) { + continue; + } + + if (!peer->ip || !op->ip) { + continue; + } + char *match = xasprintf("outport == %s && reg0 == "IP_FMT, + peer->json_key, IP_ARGS(op->ip)); + char *actions = xasprintf("eth.dst = "ETH_ADDR_FMT"; " + "next;", ETH_ADDR_ARGS(op->mac)); + ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, + 100, match, actions); + free(actions); + free(match); + } } else if (op->od->n_router_ports) { for (size_t i = 0; i < op->nbs->n_addresses; i++) { struct lport_addresses laddrs; diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 9fb8cd10c..40a7a97bf 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "2.0.1", - "cksum": "660370796 4618", + "version": "2.0.2", + "cksum": "4289495412 4436", "tables": { "Logical_Switch": { "columns": { @@ -81,10 +81,7 @@ "name": {"type": "string"}, "network": {"type": "string"}, "mac": {"type": "string"}, - "peer": {"type": {"key": {"type": "uuid", - "refTable": "Logical_Router_Port", - "refType": "strong"}, - "min": 0, "max": 1}}, + "peer": {"type": {"key": "string", "min": 0, "max": 1}}, "enabled": {"type": {"key": "boolean", "min": 0, "max": 1}}, "external_ids": { "type": {"key": "string", "value": "string", diff --git a/tests/ovn.at b/tests/ovn.at index f2ceba305..22121e187 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1986,3 +1986,158 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP + +AT_SETUP([ovn -- 2 HVs, 2 LS, 1 lport/LS, 2 peer LRs]) +AT_KEYWORDS([ovnpeer]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +# Logical network: +# Two LRs - R1 and R2 that are connected to each other as peers in 20.0.0.0/24 +# network. R1 has a switchs ls1 (191.168.1.0/24) connected to it. +# R2 has ls2 (172.16.1.0/24) connected to it. + +ovn-nbctl create Logical_Router name=R1 +ovn-nbctl create Logical_Router name=R2 + +ovn-nbctl lswitch-add ls1 +ovn-nbctl lswitch-add ls2 + +# Connect ls1 to R1 +ovn-nbctl -- --id=@lrp create Logical_Router_port name=ls1 \ +network=192.168.1.1/24 mac=\"00:00:00:01:02:03\" -- add Logical_Router R1 \ +ports @lrp -- lport-add ls1 rp-ls1 + +ovn-nbctl set Logical_port rp-ls1 type=router options:router-port=ls1 \ +addresses=\"00:00:00:01:02:03\" + +# Connect ls2 to R2 +ovn-nbctl -- --id=@lrp create Logical_Router_port name=ls2 \ +network=172.16.1.1/24 mac=\"00:00:00:01:02:04\" -- add Logical_Router R2 \ +ports @lrp -- lport-add ls2 rp-ls2 + +ovn-nbctl set Logical_port rp-ls2 type=router options:router-port=ls2 \ +addresses=\"00:00:00:01:02:04\" + +# Connect R1 to R2 +lrp1_uuid=`ovn-nbctl -- --id=@lrp create Logical_Router_port name=R1_R2 \ +network="20.0.0.1/24" mac=\"00:00:00:02:03:04\" \ +-- add Logical_Router R1 ports @lrp` + +lrp2_uuid=`ovn-nbctl -- --id=@lrp create Logical_Router_port name=R2_R1 \ +network="20.0.0.2/24" mac=\"00:00:00:02:03:05\" \ +-- add Logical_Router R2 ports @lrp` + +ovn-nbctl set logical_router_port $lrp1_uuid peer="R2_R1" +ovn-nbctl set logical_router_port $lrp2_uuid peer="R1_R2" + +ovn-nbctl set Logical_Router R1 default_gw="20.0.0.2" +ovn-nbctl set Logical_Router R2 default_gw="20.0.0.1" + +# Create logical port ls1-lp1 in ls1 +ovn-nbctl lport-add ls1 ls1-lp1 \ +-- lport-set-addresses ls1-lp1 "f0:00:00:01:02:03 192.168.1.2" + +# Create logical port ls2-lp1 in ls2 +ovn-nbctl lport-add ls2 ls2-lp1 \ +-- lport-set-addresses ls2-lp1 "f0:00:00:01:02:04 172.16.1.2" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +ovn_populate_arp + +# Allow some time for ovn-northd and ovn-controller to catch up. +# XXX This should be more systematic. +sleep 1 + +# Send ip packets between the two ports. +ip_to_hex() { + printf "%02x%02x%02x%02x" "$@" +} +trim_zeros() { + sed 's/\(00\)\{1,\}$//' +} + +# Packet to send. +src_mac="f00000010203" +dst_mac="000000010203" +src_ip=`ip_to_hex 192 168 1 2` +dst_ip=`ip_to_hex 172 16 1 2` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet + + +echo "---------NB dump-----" +ovn-nbctl show +echo "---------------------" +ovn-nbctl list logical_router +echo "---------------------" +ovn-nbctl list logical_router_port +echo "---------------------" + +echo "---------SB dump-----" +ovn-sbctl list datapath_binding +echo "---------------------" +ovn-sbctl list port_binding +echo "---------------------" + +echo "------ hv1 dump ----------" +as hv1 ovs-ofctl dump-flows br-int +echo "------ hv2 dump ----------" +as hv2 ovs-ofctl dump-flows br-int + +# Packet to Expect +src_mac="000000010204" +dst_mac="f00000010204" +expected=${dst_mac}${src_mac}08004500001c000000003e110200${src_ip}${dst_ip}0035111100080000 + +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv2/vif1-tx.pcap | trim_zeros > received.packets +echo $expected | trim_zeros > expout +AT_CHECK([cat received.packets], [0], [expout]) + +for sim in hv1 hv2; do + as $sim + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) + OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +done + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as main +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +AT_CLEANUP -- 2.20.1