Guru, does it make sense for you to look at this? You understand gateways better than me.
On Wed, Feb 07, 2018 at 12:21:35PM +0800, Guoshuai Li wrote: > Support logical router port who is gateway can configure CIDR whitout IP > address, > so as to save the public network IP when connecting to the external network. > > With this configuration, the gateway's default snat functionality will not be > available and > VMs accessing the external network can only pass floatingip(snat_and_dnat). > > The modify: > > 1. Logical switch Ingress table 11: ARP reply for logical router port IPs. > - Do not reply ARP when logical router port without IP. > > 2. Logical router ingress table 5: IP Routing. > - Use floatingIp (sNat IP) for routeing source IP in static routing. > - Use floatingIp (sNat IP) for routeing source IP in direct routing. > > 3. Local router ingress table 6: ARP Resolution. > - Do not reply ARP when logical router port without IP. > > 4. Logical router ingress table 1: IP Input for IPv4. > - Do not reply ARP for the router own when logical router port without IP. > > Signed-off-by: Guoshuai Li <[email protected]> > --- > ovn/northd/ovn-northd.c | 114 > +++++++++++++++++++++++++++++++++++++++++++----- > ovn/ovn-nb.xml | 7 +++ > tests/system-ovn.at | 8 ++++ > 3 files changed, 118 insertions(+), 11 deletions(-) > > diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c > index 4d95a3d9d..c98bf2ab6 100644 > --- a/ovn/northd/ovn-northd.c > +++ b/ovn/northd/ovn-northd.c > @@ -3548,6 +3548,17 @@ build_stateful(struct ovn_datapath *od, struct hmap > *lflows) > } > } > > +/* Return to whether Port is only configured cidr. */ > +static bool > +op_is_v4_network_cidr(const struct ipv4_netaddr *ipv4_addrs) > +{ > + if ((ipv4_addrs->plen != 32) && > + (ipv4_addrs->addr == ipv4_addrs->network)) { > + return true; > + } > + return false; > +} > + > static void > build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, > struct hmap *lflows, struct hmap *mcgroups) > @@ -3679,6 +3690,10 @@ build_lswitch_flows(struct hmap *datapaths, struct > hmap *ports, > > for (size_t i = 0; i < op->n_lsp_addrs; i++) { > for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { > + if (!strcmp(op->nbsp->type, "router") && > + op_is_v4_network_cidr(&op->lsp_addrs[i].ipv4_addrs[j])) { > + continue; > + } > ds_clear(&match); > ds_put_format(&match, "arp.tpa == %s && arp.op == 1", > op->lsp_addrs[i].ipv4_addrs[j].addr_s); > @@ -4100,8 +4115,32 @@ lrport_is_enabled(const struct > nbrec_logical_router_port *lrport) > return !lrport->enabled || *lrport->enabled; > } > > +/* Returns a string of the net external_ip of the router port 'op'. > + * If one is not found, returns NULL. > + * > + * The caller must not free the returned string. */ > +static const char * > +find_lrp_external_ip(const struct ovn_port *op) > +{ > + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > + const struct ipv4_netaddr *na = &op->lrp_networks.ipv4_addrs[i]; > + for (size_t j = 0; j < op->od->nbr->n_nat; j++) { > + const struct nbrec_nat *nat = op->od->nbr->nat[j]; > + ovs_be32 external_ip; > + if (!ip_parse(nat->external_ip, &external_ip)) { > + continue; > + } > + if (!((na->network ^ external_ip) & na->mask)) { > + return nat->external_ip; > + } > + } > + } > + return NULL; > +} > + > /* Returns a string of the IP address of the router port 'op' that > - * overlaps with 'ip_s". If one is not found, returns NULL. > + * overlaps with 'ip_s". Or Returns a string of the nat external_ip > + * address of the router port 'op', If one is not found, returns NULL. > * > * The caller must not free the returned string. */ > static const char * > @@ -4118,15 +4157,27 @@ find_lrp_member_ip(const struct ovn_port *op, const > char *ip_s) > return NULL; > } > > + bool find_port = false; > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > const struct ipv4_netaddr *na = &op->lrp_networks.ipv4_addrs[i]; > > if (!((na->network ^ ip) & na->mask)) { > + find_port = true; > /* There should be only 1 interface that matches the > * supplied IP. Otherwise, it's a configuration error, > * because subnets of a router's interfaces should NOT > * overlap. */ > - return na->addr_s; > + if (na->addr != na->network) { > + return na->addr_s; > + } > + } > + } > + > + if (find_port) { > + /* Get NAT external IP addresses. */ > + const char *external_ip = find_lrp_external_ip(op); > + if (external_ip) { > + return external_ip; > } > } > } else { > @@ -4156,6 +4207,20 @@ find_lrp_member_ip(const struct ovn_port *op, const > char *ip_s) > return NULL; > } > > +static int > +op_get_v4_ip_number(const struct ovn_port *op) > +{ > + int n = 0; > + if (op->lrp_networks.n_ipv4_addrs) { > + for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > + if (!op_is_v4_network_cidr(&op->lrp_networks.ipv4_addrs[i])) { > + n++; > + } > + } > + } > + return n; > +} > + > static void > add_route(struct hmap *lflows, const struct ovn_port *op, > const char *lrp_addr_s, const char *network_s, int plen, > @@ -4296,12 +4361,19 @@ build_static_route_flow(struct hmap *lflows, struct > ovn_datapath *od, > /* There are no IP networks configured on the router's port via > * which 'route->nexthop' is theoretically reachable. But since > * 'out_port' has been specified, we honor it by trying to reach > - * 'route->nexthop' via the first IP address of 'out_port'. > + * 'route->nexthop' via the first IP address of 'out_port' or > + * nat external IP addresses of 'out_port'. > * (There are cases, e.g in GCE, where each VM gets a /32 IP > * address and the default gateway is still reachable from it.) > */ > if (is_ipv4) { > if (out_port->lrp_networks.n_ipv4_addrs) { > - lrp_addr_s = out_port->lrp_networks.ipv4_addrs[0].addr_s; > + struct lport_addresses *address = > &out_port->lrp_networks; > + for (int i = 0; i < address->n_ipv4_addrs; i++) { > + if (!op_is_v4_network_cidr(&address->ipv4_addrs[i])) > { > + lrp_addr_s = address->ipv4_addrs[i].addr_s; > + break; > + } > + } > } > } else { > if (out_port->lrp_networks.n_ipv6_addrs) { > @@ -4328,7 +4400,7 @@ build_static_route_flow(struct hmap *lflows, struct > ovn_datapath *od, > } > } > > - if (!out_port || !lrp_addr_s) { > + if (!out_port) { > /* There is no matched out port. */ > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > VLOG_WARN_RL(&rl, "No path for static route %s; next hop %s", > @@ -4336,6 +4408,14 @@ build_static_route_flow(struct hmap *lflows, struct > ovn_datapath *od, > goto free_prefix_s; > } > > + if (!lrp_addr_s) { > + /* There is no matched lrp_addr_s. */ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + VLOG_DBG_RL(&rl, "No source ip for static route %s; next hop %s", > + route->ip_prefix, route->nexthop); > + goto free_prefix_s; > + } > + > char *policy = route->policy ? route->policy : "dst-ip"; > add_route(lflows, out_port, lrp_addr_s, prefix_s, plen, route->nexthop, > policy); > @@ -4347,14 +4427,16 @@ free_prefix_s: > static void > op_put_v4_networks(struct ds *ds, const struct ovn_port *op, bool add_bcast) > { > - if (!add_bcast && op->lrp_networks.n_ipv4_addrs == 1) { > + if (!add_bcast && op_get_v4_ip_number(op) == 1) { > ds_put_format(ds, "%s", op->lrp_networks.ipv4_addrs[0].addr_s); > return; > } > > ds_put_cstr(ds, "{"); > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > - ds_put_format(ds, "%s, ", op->lrp_networks.ipv4_addrs[i].addr_s); > + if (!op_is_v4_network_cidr(&op->lrp_networks.ipv4_addrs[i])) { > + ds_put_format(ds, "%s, ", op->lrp_networks.ipv4_addrs[i].addr_s); > + } > if (add_bcast) { > ds_put_format(ds, "%s, ", > op->lrp_networks.ipv4_addrs[i].bcast_s); > } > @@ -4685,7 +4767,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap > *ports, > continue; > } > > - if (op->lrp_networks.n_ipv4_addrs) { > + if (op_get_v4_ip_number(op)) { > /* L3 admission control: drop packets that originate from an > * IPv4 address owned by the router or a broadcast address > * known to the router (priority 100). */ > @@ -4720,6 +4802,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap > *ports, > /* ARP reply. These flows reply to ARP requests for the router's own > * IP address. */ > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > + if (op_is_v4_network_cidr(&op->lrp_networks.ipv4_addrs[i])) { > + continue; > + } > ds_clear(&match); > ds_put_format(&match, > "inport == %s && arp.tpa == %s && arp.op == 1", > @@ -5660,7 +5745,14 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > } > > for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > - add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s, > + const char *lrp_addr_s = op->lrp_networks.ipv4_addrs[i].addr_s; > + if (op_is_v4_network_cidr(&op->lrp_networks.ipv4_addrs[i])) { > + lrp_addr_s = find_lrp_member_ip(op, lrp_addr_s); > + if (!lrp_addr_s) { > + continue; > + } > + } > + add_route(lflows, op, lrp_addr_s, > op->lrp_networks.ipv4_addrs[i].network_s, > op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL); > } > @@ -5709,7 +5801,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap > *ports, > * The packet is still in peer's logical pipeline. So the match > * should be on peer's outport. */ > if (op->peer && op->nbrp->peer) { > - if (op->lrp_networks.n_ipv4_addrs) { > + if (op_get_v4_ip_number(op)) { > ds_clear(&match); > ds_put_format(&match, "outport == %s && reg0 == ", > op->peer->json_key); > @@ -5846,7 +5938,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap > *ports, > continue; > } > > - if (router_port->lrp_networks.n_ipv4_addrs) { > + if (op_get_v4_ip_number(router_port)) { > ds_clear(&match); > ds_put_format(&match, "outport == %s && reg0 == ", > peer->json_key); > diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml > index b7a5b6bf2..fc9fd42ff 100644 > --- a/ovn/ovn-nb.xml > +++ b/ovn/ovn-nb.xml > @@ -1345,6 +1345,13 @@ > </p> > > <p> > + A logical router port who is gateway port also can configure CIDR, > + For example, <code>192.168.0.0/24</code>. This means that traffic > + to the external network can only pass NAT's external_ip. This > + does not make sense for normal logical router port. > + </p> > + > + <p> > A logical router port always adds a link-local IPv6 address > (fe80::/64) automatically generated from the interface's MAC > address using the modified EUI-64 format. > diff --git a/tests/system-ovn.at b/tests/system-ovn.at > index 638c0b661..5bca5e3d2 100644 > --- a/tests/system-ovn.at > +++ b/tests/system-ovn.at > @@ -1347,6 +1347,14 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl > > icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=172.16.1.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared> > ]) > > +ovn-nbctl set Logical_Router_Port alice networks=172.16.1.0/24 > + > +# North-South DNAT without gatewayIp: 'alice1' pings 'foo1' using 172.16.1.3. > +NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 172.16.1.3 | FORMAT_PING], > \ > +[0], [dnl > +3 packets transmitted, 3 received, 0% packet loss, time 0ms > +]) > + > OVS_APP_EXIT_AND_WAIT([ovn-controller]) > > as ovn-sb > -- > 2.13.2.windows.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
