From patchwork Fri Jan 29 15:57:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 575678 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (unknown [IPv6:2600:3c00::f03c:91ff:fe6e:bdf7]) by ozlabs.org (Postfix) with ESMTP id D4E9A140B9C for ; Sat, 30 Jan 2016 02:57:43 +1100 (AEDT) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 86EB910D17; Fri, 29 Jan 2016 07:57:41 -0800 (PST) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 9AFD010D0B for ; Fri, 29 Jan 2016 07:57:39 -0800 (PST) Received: from bar4.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id 334F0162233 for ; Fri, 29 Jan 2016 08:57:39 -0700 (MST) X-ASG-Debug-ID: 1454083057-03dc217d9cbfa1f0001-byXFYA Received: from mx1-pf2.cudamail.com ([192.168.24.2]) by bar4.cudamail.com with ESMTP id AMaMuFjwQ3R21qiJ (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 29 Jan 2016 08:57:38 -0700 (MST) X-Barracuda-Envelope-From: nusiddiq@redhat.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.24.2 Received: from unknown (HELO mx1.redhat.com) (209.132.183.28) by mx1-pf2.cudamail.com with ESMTPS (DHE-RSA-AES256-SHA encrypted); 29 Jan 2016 15:57:37 -0000 Received-SPF: pass (mx1-pf2.cudamail.com: SPF record at _spf1.redhat.com designates 209.132.183.28 as permitted sender) X-Barracuda-Apparent-Source-IP: 209.132.183.28 X-Barracuda-RBL-IP: 209.132.183.28 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 80F00A789 for ; Fri, 29 Jan 2016 15:57:36 +0000 (UTC) Received: from nusiddiq.blr.redhat.com (dhcp-0-76.blr.redhat.com [10.70.1.76]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0TFvYhZ009463 for ; Fri, 29 Jan 2016 10:57:35 -0500 X-CudaMail-Envelope-Sender: nusiddiq@redhat.com From: Numan Siddique X-CudaMail-MID: CM-E2-128029547 X-CudaMail-DTE: 012916 X-CudaMail-Originating-IP: 209.132.183.28 Organization: Red Hat X-ASG-Orig-Subj: [##CM-E2-128029547##][PATCHv1 1/4] ovn-northd: Support Logical_Port.addresses to store multiple ips in each set To: dev@openvswitch.org In-Reply-To: <56AB8B92.9010004@redhat.com> Message-ID: <56AB8BED.4070203@redhat.com> Date: Fri, 29 Jan 2016 21:27:33 +0530 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-GBUdb-Analysis: 0, 209.132.183.28, Ugly c=0.303425 p=-0.368421 Source Normal X-MessageSniffer-Rules: 0-0-0-30891-c X-Barracuda-Connect: UNKNOWN[192.168.24.2] X-Barracuda-Start-Time: 1454083058 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.60 X-Barracuda-Spam-Status: No, SCORE=0.60 using per-user scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=4.0 tests=BSF_SC5_MJ1963, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.26567 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 Subject: [ovs-dev] [PATCHv1 1/4] ovn-northd: Support Logical_Port.addresses to store multiple ips in each set X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@openvswitch.org Sender: "dev" If a logical port has two ipv4 addresses and one ipv6 address it will be stored as ["MAC IPv41 IPv42 IPv61"] instead of ["MAC IPv41", "MAC IPv42", "MAC IPv61"]. Signed-off-by: Numan Siddique --- lib/packets.c | 102 ++++++++++++++++++++++++++++++++++ lib/packets.h | 10 ++++ ovn/northd/ovn-northd.c | 142 ++++++++++++++++++++++++++++++++++++++++++------ ovn/ovn-nb.xml | 58 +++++++++++++++----- 4 files changed, 280 insertions(+), 32 deletions(-) diff --git a/lib/packets.c b/lib/packets.c index d82341d..b338846 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -455,6 +455,34 @@ ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) return NULL; } +/* + * This function is similar to ip_parse_masked(), with an extra parameter + * `n` added to return the number of scanned characters. + */ +char * OVS_WARN_UNUSED_RESULT +ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip, + ovs_be32 *mask) +{ + int prefix; + + if (ovs_scan_len(s, n, IP_SCAN_FMT"/"IP_SCAN_FMT, + IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask))) { + /* OK. */ + } else if (ovs_scan_len(s, n, IP_SCAN_FMT"/%d", + IP_SCAN_ARGS(ip), &prefix)) { + if (prefix <= 0 || prefix > 32) { + return xasprintf("%s: network prefix bits not between 0 and " + "32", s); + } + *mask = be32_prefix_mask(prefix); + } else if (ovs_scan_len(s, n, IP_SCAN_FMT, IP_SCAN_ARGS(ip))) { + *mask = OVS_BE32_MAX; + } else { + return xasprintf("%s: invalid IP address", s); + } + return NULL; +} + /* Similar to ip_parse_masked(), but the mask, if present, must be a CIDR mask * and is returned as a prefix length in '*plen'. */ char * OVS_WARN_UNUSED_RESULT @@ -475,6 +503,26 @@ ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) return NULL; } +/* Similar to ip_parse_cidr(), with an extra parameter `n` added to return + * the number of scanned characters. */ +char * OVS_WARN_UNUSED_RESULT +ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, unsigned int *plen) +{ + ovs_be32 mask; + char *error; + + error = ip_parse_masked_len(s, n, ip, &mask); + if (error) { + return error; + } + + if (!ip_is_cidr(mask)) { + return xasprintf("%s: CIDR network required", s); + } + *plen = ip_count_cidr_bits(mask); + return NULL; +} + /* Parses string 's', which must be an IPv6 address. Stores the IPv6 address * into '*ip'. Returns true if successful, otherwise false. */ bool @@ -519,6 +567,39 @@ ipv6_parse_masked(const char *s, struct in6_addr *ip, struct in6_addr *mask) return xasprintf("%s: invalid IPv6 address", s); } +/* + * This function is similar to ipv6_parse_masked(), with an extra parameter + * `n` added to return the number of scanned characters. + */ +char * OVS_WARN_UNUSED_RESULT +ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ip, + struct in6_addr *mask) +{ + char ipv6_s[IPV6_SCAN_LEN + 1]; + int prefix; + + if (ovs_scan_len(s, n, " "IPV6_SCAN_FMT, ipv6_s) + && ipv6_parse(ipv6_s, ip)) { + if (ovs_scan_len(s, n, "/%d", &prefix)) { + if (prefix <= 0 || prefix > 128) { + return xasprintf("%s: IPv6 network prefix bits not between 0 " + "and 128", s); + } + *mask = ipv6_create_mask(prefix); + } else if (ovs_scan_len(s, n, "/"IPV6_SCAN_FMT, ipv6_s)) { + if (!ipv6_parse(ipv6_s, mask)) { + return xasprintf("%s: Invalid IPv6 mask", s); + } + /* OK. */ + } else { + /* OK. No mask */ + *mask = in6addr_exact; + } + return NULL; + } + return xasprintf("%s: invalid IPv6 address", s); +} + /* Similar to ipv6_parse_masked(), but the mask, if present, must be a CIDR * mask and is returned as a prefix length in '*plen'. */ char * OVS_WARN_UNUSED_RESULT @@ -539,6 +620,27 @@ ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen) return NULL; } +/* Similar to ipv6_parse_cidr(), with an extra parameter `n` added to return + * the number of scanned characters. */ +char * OVS_WARN_UNUSED_RESULT +ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip, + unsigned int *plen) +{ + struct in6_addr mask; + char *error; + + error = ipv6_parse_masked_len(s, n, ip, &mask); + if (error) { + return error; + } + + if (!ipv6_is_cidr(&mask)) { + return xasprintf("%s: IPv6 CIDR network required", s); + } + *plen = ipv6_count_cidr_bits(&mask); + return NULL; +} + /* Stores the string representation of the IPv6 address 'addr' into the * character array 'addr_str', which must be at least INET6_ADDRSTRLEN * bytes long. */ diff --git a/lib/packets.h b/lib/packets.h index 834e8a4..31a4e92 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -586,6 +586,11 @@ char *ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) OVS_WARN_UNUSED_RESULT; char *ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) OVS_WARN_UNUSED_RESULT; +char *ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip, ovs_be32 *mask) + OVS_WARN_UNUSED_RESULT; +char *ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, + unsigned int *plen) + OVS_WARN_UNUSED_RESULT; #define IP_VER(ip_ihl_ver) ((ip_ihl_ver) >> 4) #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15) @@ -1033,6 +1038,11 @@ char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6, struct in6_addr *mask); char *ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen) OVS_WARN_UNUSED_RESULT; +char *ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ipv6, + struct in6_addr *mask); +char *ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip, + unsigned int *plen) + OVS_WARN_UNUSED_RESULT; void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst, const struct eth_addr eth_src, uint16_t eth_type, diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 4f03287..f20f3b1 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -914,6 +914,96 @@ ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow) } } +struct ipv4_netaddr { + ovs_be32 addr; + unsigned int plen; +}; + +struct ipv6_netaddr { + struct in6_addr addr; + unsigned int plen; +}; + +struct lport_addresses { + struct eth_addr ea; + size_t n_ipv4_addrs; + struct ipv4_netaddr *ipv4_addrs; + size_t n_ipv6_addrs; + struct ipv6_netaddr *ipv6_addrs; +}; + +/* + * Extracts the mac, ipv4 and ipv6 addresses from the input + * param 'address' which should be of the format + * 'MAC [IPV41 IPV42 ...IPV61 IPV62 .." + */ +static struct lport_addresses * +extract_lport_addresses(char *address) +{ + struct lport_addresses *laddrs; + int n = 0; + char *p = address; + laddrs = xzalloc(sizeof (*laddrs)); + if (!ovs_scan_len(p, &n, ETH_ADDR_SCAN_FMT, + ETH_ADDR_SCAN_ARGS(laddrs->ea))) { + free(laddrs); + return NULL; + } + + ovs_be32 ip4; + unsigned int plen; + int n1 = n; + int i = 0; + char *error; + while (!(error = ip_parse_cidr_len(p, &n1, &ip4, &plen))) { + laddrs->n_ipv4_addrs++; + } + + if (error) { + free(error); + } + + struct in6_addr ip6; + while (!(error = ipv6_parse_cidr_len(p, &n1, &ip6, &plen))) { + laddrs->n_ipv6_addrs++; + } + + if (error) { + free(error); + } + + n1 = n; + if (laddrs->n_ipv4_addrs) { + laddrs->ipv4_addrs = xcalloc(laddrs->n_ipv4_addrs, + sizeof (struct ipv4_netaddr)); + i = 0; + while (!(error = ip_parse_cidr_len(p, &n1, &laddrs->ipv4_addrs[i].addr, + &laddrs->ipv4_addrs[i].plen))) { + i++; + } + + if (error) { + free(error); + } + } + + if (laddrs->n_ipv6_addrs) { + laddrs->ipv6_addrs = xcalloc(laddrs->n_ipv6_addrs, + sizeof (struct ipv6_netaddr)); + i = 0; + while (!(error = ipv6_parse_cidr_len( + p, &n1, &laddrs->ipv6_addrs[i].addr, + &laddrs->ipv6_addrs[i].plen))) { + i++; + } + + if (error) { + free(error); + } + } + return laddrs; +} + /* Appends port security constraints on L2 address field 'eth_addr_field' * (e.g. "eth.src" or "eth.dst") to 'match'. 'port_security', with * 'n_port_security' elements, is the collection of port_security constraints @@ -1194,14 +1284,15 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, } for (size_t i = 0; i < op->nbs->n_addresses; i++) { - struct eth_addr ea; - ovs_be32 ip; - - if (ovs_scan(op->nbs->addresses[i], - ETH_ADDR_SCAN_FMT" "IP_SCAN_FMT, - ETH_ADDR_SCAN_ARGS(ea), IP_SCAN_ARGS(&ip))) { + struct lport_addresses *laddrs = extract_lport_addresses( + op->nbs->addresses[i]); + if (!laddrs) { + continue; + } + for (size_t j = 0; j < laddrs->n_ipv4_addrs; j++) { char *match = xasprintf( - "arp.tpa == "IP_FMT" && arp.op == 1", IP_ARGS(ip)); + "arp.tpa == "IP_FMT" && arp.op == 1", + IP_ARGS(laddrs->ipv4_addrs[j].addr)); char *actions = xasprintf( "eth.dst = eth.src; " "eth.src = "ETH_ADDR_FMT"; " @@ -1213,14 +1304,22 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "outport = inport; " "inport = \"\"; /* Allow sending out inport. */ " "output;", - ETH_ADDR_ARGS(ea), - ETH_ADDR_ARGS(ea), - IP_ARGS(ip)); + ETH_ADDR_ARGS(laddrs->ea), + ETH_ADDR_ARGS(laddrs->ea), + IP_ARGS(laddrs->ipv4_addrs[j].addr)); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 150, match, actions); free(match); free(actions); } + + if (laddrs->ipv4_addrs) { + free(laddrs->ipv4_addrs); + } + if (laddrs->ipv6_addrs) { + free(laddrs->ipv6_addrs); + } + free(laddrs); } } @@ -1541,12 +1640,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* XXX ARP for neighboring router */ } else if (op->od->n_router_ports) { for (size_t i = 0; i < op->nbs->n_addresses; i++) { - struct eth_addr ea; - ovs_be32 ip; - - if (ovs_scan(op->nbs->addresses[i], - ETH_ADDR_SCAN_FMT" "IP_SCAN_FMT, - ETH_ADDR_SCAN_ARGS(ea), IP_SCAN_ARGS(&ip))) { + struct lport_addresses *laddrs = extract_lport_addresses( + op->nbs->addresses[i]); + if (!laddrs) { + continue; + } + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { + ovs_be32 ip = laddrs->ipv4_addrs[k].addr; for (size_t j = 0; j < op->od->n_router_ports; j++) { /* Get the Logical_Router_Port that the Logical_Port is * connected to, as 'peer'. */ @@ -1574,7 +1674,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "outport = %s; " "output;", ETH_ADDR_ARGS(peer->mac), - ETH_ADDR_ARGS(ea), + ETH_ADDR_ARGS(laddrs->ea), peer->json_key); ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP, 200, match, actions); @@ -1583,6 +1683,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, break; } } + + if (laddrs->ipv4_addrs) { + free(laddrs->ipv4_addrs); + } + if (laddrs->ipv6_addrs) { + free(laddrs->ipv6_addrs); + } + free(laddrs); } } } diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index 4e414ce..b4768d0 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -254,12 +254,12 @@

-
xx:xx:xx:xx:xx:xx
+
Ethernet address followed by zero or more IPv4 or IPv6 addresses (or both)

- An Ethernet address owned by the logical port. Like a physical - Ethernet NIC, a logical port ordinarily has a single fixed - Ethernet address. + An Ethernet address defined is owned by the logical port. + Like a physical Ethernet NIC, a logical port ordinarily has + a single fixed Ethernet address.

@@ -269,27 +269,55 @@ if a MAC learning process had learned that MAC address on the port.

-
-
xx:xx:xx:xx:xx:xx a.b.c.d
-

- This form has all the effects of the previous form. It also - indicates that the logical port owns the given IPv4 address. + If IPv4 or IPv6 address(es) (or both) are defined, it indicates + that the logical port owns the given IP addresses.

- The OVN logical switch uses this information to synthesize - responses to ARP requests without traversing the physical - network. The OVN logical router connected to the logical switch, - if any, uses this information to avoid issuing ARP requests for - logical switch ports. + If IPv4 address(es) are defined, the OVN logical switch uses this + information to synthesize responses to ARP requests without + traversing the physical network. The OVN logical router connected + to the logical switch, if any, uses this information to avoid + issuing ARP requests for logical switch ports.

Note that the order here is important. The Ethernet address must - be listed before the IP address. + be listed before the IP address(es) if defined. If both IPv4 and + IPv6 addresses are defined, then IPv4 addresses should be listed + before IPv6 address(es). +

+ +

+ Examples:

+ +
+
80:fa:5b:06:72:b7
+
+ This indicates that the logical port owns the above mac address. +
+ +
80:fa:5b:06:72:b7 10.0.0.4 20.0.0.4
+
+ This indicates that the logical port owns the mac address and two + IPv4 addresses. +
+ +
80:fa:5b:06:72:b7 fdaa:15f2:72cf:0:f816:3eff:fe20:3f41
+
+ This indicates that the logical port owns the mac address and + 1IPv6 address. +
+ +
80:fa:5b:06:72:b7 10.0.0.4 fdaa:15f2:72cf:0:f816:3eff:fe20:3f41
+
+ This indicates that the logical port owns the mac address and + 1 IPv4 address and 1 IPv6 address. +
+
unknown