Message ID | 1564122757-24465-1-git-send-email-dceara@redhat.com |
---|---|
State | Superseded |
Headers | show |
Series | [ovs-dev,v2] OVN: Fix learning of neighbors from ARP/ND packets. | expand |
On Fri, Jul 26, 2019 at 8:33 AM Dumitru Ceara <dceara@redhat.com> wrote: > > Add a restriction on the target protocol addresses to match the configured > subnets. All other ARP/ND packets are invalid in this context. > > One exception is for ARP replies that are received for route next-hops > that are only reachable via a port but can't be directly resolved > through route lookups. Such support was introduced by commit: > > 6b785fd8fe29 ("ovn-util: Allow /32 IP addresses for router ports.") > > Reported-at: https://bugzilla.redhat.com/1729846 > Reported-by: Haidong Li <haili@redhat.com> > CC: Han Zhou <zhouhan@gmail.com> > CC: Guru Shetty <guru@ovn.org> > Fixes: b068454082f5 ("ovn-northd: Support learning neighbor from ARP request.") > Signed-off-by: Dumitru Ceara <dceara@redhat.com> > --- > > v2: > - Update commit message. > - Implement the fix also for ARP replies and IPv6 ND. Hi Han, Guru, I resubmitted this patch against the ovn-org repo. The new patchwork is: https://patchwork.ozlabs.org/patch/1138261/ Thanks, Dumitru > --- > ovn/northd/ovn-northd.c | 95 +++++++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 81 insertions(+), 14 deletions(-) > > diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c > index eb6c47c..1e3ec68 100644 > --- a/ovn/northd/ovn-northd.c > +++ b/ovn/northd/ovn-northd.c > @@ -5815,10 +5815,32 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, > if (is_ipv4) { > if (out_port->lrp_networks.n_ipv4_addrs) { > lrp_addr_s = out_port->lrp_networks.ipv4_addrs[0].addr_s; > + > + /* Explicitly allow ARP replies for the next-hop. */ > + struct ds match; > + ds_init(&match); > + ds_put_format(&match, "inport == %s && arp.op == 2 && " > + "arp.spa == %s", out_port->json_key, > + route->nexthop); > + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), > + "put_arp(inport, arp.spa, arp.sha);"); > + ds_destroy(&match); > } > } else { > if (out_port->lrp_networks.n_ipv6_addrs) { > lrp_addr_s = out_port->lrp_networks.ipv6_addrs[0].addr_s; > + > + /* Explicitly allow NA for the next-hop. */ > + struct ds match; > + ds_init(&match); > + ds_put_format(&match, "inport == %s && nd_na && " > + "ip6.src == %s", out_port->json_key, > + route->nexthop); > + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), > + "put_nd(inport, nd.target, nd.tll);"); > + ds_destroy(&match); > } > } > } > @@ -6159,10 +6181,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > "ip4.dst == 0.0.0.0/8", > "drop;"); > > - /* ARP reply handling. Use ARP replies to populate the logical > - * router's ARP table. */ > - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "arp.op == 2", > - "put_arp(inport, arp.spa, arp.sha);"); > > /* Drop Ethernet local broadcast. By definition this traffic should > * not be forwarded.*/ > @@ -6175,16 +6193,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, > ds_cstr(&match), "drop;"); > > - /* ND advertisement handling. Use advertisements to populate > - * the logical router's ARP/ND table. */ > - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "nd_na", > - "put_nd(inport, nd.target, nd.tll);"); > > - /* Lean from neighbor solicitations that were not directed at > - * us. (A priority-90 flow will respond to requests to us and > - * learn the sender's mac address. */ > - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 80, "nd_ns", > - "put_nd(inport, ip6.src, nd.sll);"); > > /* Pass other traffic not already handled to the next table for > * routing. */ > @@ -6320,15 +6329,34 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_cstr(&match), ds_cstr(&actions)); > } > > + /* ARP reply handling. Use ARP replies to populate the logical > + * router's ARP table. */ > + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > + ds_clear(&match); > + ds_put_format(&match, "inport == %s && arp.spa == %s/%u && " > + "arp.tpa == %s/%u && arp.op == 2", > + op->json_key, > + op->lrp_networks.ipv4_addrs[i].network_s, > + op->lrp_networks.ipv4_addrs[i].plen, > + op->lrp_networks.ipv4_addrs[i].network_s, > + op->lrp_networks.ipv4_addrs[i].plen); > + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), > + "put_arp(inport, arp.spa, arp.sha);"); > + } > + > /* Learn from ARP requests that were not directed at us. A typical > * use case is GARP request handling. (A priority-90 flow will > * respond to request to us and learn the sender's mac address.) */ > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > ds_clear(&match); > ds_put_format(&match, > - "inport == %s && arp.spa == %s/%u && arp.op == 1", > + "inport == %s && arp.spa == %s/%u && " > + "arp.tpa == %s/%u && arp.op == 1", > op->json_key, > op->lrp_networks.ipv4_addrs[i].network_s, > + op->lrp_networks.ipv4_addrs[i].plen, > + op->lrp_networks.ipv4_addrs[i].network_s, > op->lrp_networks.ipv4_addrs[i].plen); > if (op->od->l3dgw_port && op == op->od->l3dgw_port > && op->od->l3redirect_port) { > @@ -6669,6 +6697,45 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, > ds_cstr(&match), ds_cstr(&actions)); > } > > + /* NA reply handling. Use NA replies to populate the logical > + * router's neighbor table. */ > + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > + ds_clear(&match); > + ds_put_format(&match, "inport == %s && nd_na && " > + "nd.target == %s/%u && ip6.src == %s/%u", > + op->json_key, > + op->lrp_networks.ipv6_addrs[i].network_s, > + op->lrp_networks.ipv6_addrs[i].plen, > + op->lrp_networks.ipv6_addrs[i].network_s, > + op->lrp_networks.ipv6_addrs[i].plen); > + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, > + ds_cstr(&match), > + "put_nd(inport, nd.target, nd.tll);"); > + } > + > + /* Learn from ND requests that were not directed at us. > + * (A priority-90 flow will respond to request to us and learn the > + * sender's mac address.) */ > + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > + ds_clear(&match); > + ds_put_format(&match, > + "inport == %s && nd_ns && ip6.src == %s/%u && " > + "ip6.dst == %s/%u", > + op->json_key, > + op->lrp_networks.ipv6_addrs[i].network_s, > + op->lrp_networks.ipv6_addrs[i].plen, > + op->lrp_networks.ipv6_addrs[i].network_s, > + op->lrp_networks.ipv6_addrs[i].plen); > + if (op->od->l3dgw_port && op == op->od->l3dgw_port > + && op->od->l3redirect_port) { > + ds_put_format(&match, " && is_chassis_resident(%s)", > + op->od->l3redirect_port->json_key); > + } > + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, > + ds_cstr(&match), > + "put_nd(inport, ip6.src, nd.sll);"); > + } > + > /* UDP/TCP port unreachable */ > if (!smap_get(&op->od->nbr->options, "chassis") > && !op->od->l3dgw_port) { > -- > 1.8.3.1 >
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index eb6c47c..1e3ec68 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -5815,10 +5815,32 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, if (is_ipv4) { if (out_port->lrp_networks.n_ipv4_addrs) { lrp_addr_s = out_port->lrp_networks.ipv4_addrs[0].addr_s; + + /* Explicitly allow ARP replies for the next-hop. */ + struct ds match; + ds_init(&match); + ds_put_format(&match, "inport == %s && arp.op == 2 && " + "arp.spa == %s", out_port->json_key, + route->nexthop); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_arp(inport, arp.spa, arp.sha);"); + ds_destroy(&match); } } else { if (out_port->lrp_networks.n_ipv6_addrs) { lrp_addr_s = out_port->lrp_networks.ipv6_addrs[0].addr_s; + + /* Explicitly allow NA for the next-hop. */ + struct ds match; + ds_init(&match); + ds_put_format(&match, "inport == %s && nd_na && " + "ip6.src == %s", out_port->json_key, + route->nexthop); + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_nd(inport, nd.target, nd.tll);"); + ds_destroy(&match); } } } @@ -6159,10 +6181,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "ip4.dst == 0.0.0.0/8", "drop;"); - /* ARP reply handling. Use ARP replies to populate the logical - * router's ARP table. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "arp.op == 2", - "put_arp(inport, arp.spa, arp.sha);"); /* Drop Ethernet local broadcast. By definition this traffic should * not be forwarded.*/ @@ -6175,16 +6193,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, ds_cstr(&match), "drop;"); - /* ND advertisement handling. Use advertisements to populate - * the logical router's ARP/ND table. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "nd_na", - "put_nd(inport, nd.target, nd.tll);"); - /* Lean from neighbor solicitations that were not directed at - * us. (A priority-90 flow will respond to requests to us and - * learn the sender's mac address. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 80, "nd_ns", - "put_nd(inport, ip6.src, nd.sll);"); /* Pass other traffic not already handled to the next table for * routing. */ @@ -6320,15 +6329,34 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_cstr(&match), ds_cstr(&actions)); } + /* ARP reply handling. Use ARP replies to populate the logical + * router's ARP table. */ + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + ds_clear(&match); + ds_put_format(&match, "inport == %s && arp.spa == %s/%u && " + "arp.tpa == %s/%u && arp.op == 2", + op->json_key, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_arp(inport, arp.spa, arp.sha);"); + } + /* Learn from ARP requests that were not directed at us. A typical * use case is GARP request handling. (A priority-90 flow will * respond to request to us and learn the sender's mac address.) */ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { ds_clear(&match); ds_put_format(&match, - "inport == %s && arp.spa == %s/%u && arp.op == 1", + "inport == %s && arp.spa == %s/%u && " + "arp.tpa == %s/%u && arp.op == 1", op->json_key, op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen, + op->lrp_networks.ipv4_addrs[i].network_s, op->lrp_networks.ipv4_addrs[i].plen); if (op->od->l3dgw_port && op == op->od->l3dgw_port && op->od->l3redirect_port) { @@ -6669,6 +6697,45 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_cstr(&match), ds_cstr(&actions)); } + /* NA reply handling. Use NA replies to populate the logical + * router's neighbor table. */ + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(&match); + ds_put_format(&match, "inport == %s && nd_na && " + "nd.target == %s/%u && ip6.src == %s/%u", + op->json_key, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, + ds_cstr(&match), + "put_nd(inport, nd.target, nd.tll);"); + } + + /* Learn from ND requests that were not directed at us. + * (A priority-90 flow will respond to request to us and learn the + * sender's mac address.) */ + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(&match); + ds_put_format(&match, + "inport == %s && nd_ns && ip6.src == %s/%u && " + "ip6.dst == %s/%u", + op->json_key, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen, + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen); + if (op->od->l3dgw_port && op == op->od->l3dgw_port + && op->od->l3redirect_port) { + ds_put_format(&match, " && is_chassis_resident(%s)", + op->od->l3redirect_port->json_key); + } + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 80, + ds_cstr(&match), + "put_nd(inport, ip6.src, nd.sll);"); + } + /* UDP/TCP port unreachable */ if (!smap_get(&op->od->nbr->options, "chassis") && !op->od->l3dgw_port) {
Add a restriction on the target protocol addresses to match the configured subnets. All other ARP/ND packets are invalid in this context. One exception is for ARP replies that are received for route next-hops that are only reachable via a port but can't be directly resolved through route lookups. Such support was introduced by commit: 6b785fd8fe29 ("ovn-util: Allow /32 IP addresses for router ports.") Reported-at: https://bugzilla.redhat.com/1729846 Reported-by: Haidong Li <haili@redhat.com> CC: Han Zhou <zhouhan@gmail.com> CC: Guru Shetty <guru@ovn.org> Fixes: b068454082f5 ("ovn-northd: Support learning neighbor from ARP request.") Signed-off-by: Dumitru Ceara <dceara@redhat.com> --- v2: - Update commit message. - Implement the fix also for ARP replies and IPv6 ND. --- ovn/northd/ovn-northd.c | 95 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 14 deletions(-)