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