Split network address types and parsing/formatting functions out of the monolithic packets.[ch] into a new netaddr.[ch] module:
- netaddr.h: Ethernet address constants, inline helpers, IPv4/IPv6 address parsing/formatting declarations, format macros (IP_FMT, ETH_ADDR_FMT, etc.), and the ovs_16aligned_in6_addr type. - netaddr.c: 36 address functions moved from packets.c, including ip_parse(), ipv6_parse(), ipv6_string_mapped(), eth_addr_from_string(), eth_addr_is_reserved(), ip_format_masked(), ipv6_format_addr(), and all IPv6 address math (bitand, create_mask, count_cidr_bits, etc.). packets.h now includes netaddr.h, so all existing consumers see no change. packets.[ch] retains packet header structs, protocol constants, dp_packet manipulation, and tunnel-related functions. The users that will move to the utilities library (smap, socket-util and the stream modules) now include netaddr.h instead of packets.h. stream.c needed nothing from packets.h or flow.h except timeval.h, which it got through them, so it now includes timeval.h directly. This is a preparatory refactoring for the upcoming library split: netaddr.[ch] will move into the utilities library while packets.[ch] stays in the main libopenvswitch, cleanly resolving the logical isolation concern without inlining address functions into headers. Signed-off-by: Timothy Redaelli <[email protected]> --- lib/automake.mk | 2 + lib/netaddr.c | 668 ++++++++++++++++++++++++++++++++++++++++++++++ lib/netaddr.h | 429 +++++++++++++++++++++++++++++ lib/packets.c | 641 -------------------------------------------- lib/packets.h | 390 +-------------------------- lib/smap.c | 2 +- lib/socket-util.c | 2 +- lib/stream-ssl.c | 2 +- lib/stream-tcp.c | 2 +- lib/stream-unix.c | 2 +- lib/stream.c | 3 +- 11 files changed, 1106 insertions(+), 1037 deletions(-) create mode 100644 lib/netaddr.c create mode 100644 lib/netaddr.h diff --git a/lib/automake.mk b/lib/automake.mk index 2dfca79da..7107780f7 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -251,6 +251,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/ovsdb-types.h \ lib/ox-stat.c \ lib/ox-stat.h \ + lib/netaddr.c \ + lib/netaddr.h \ lib/packets.c \ lib/packets.h \ lib/pcap-file.c \ diff --git a/lib/netaddr.c b/lib/netaddr.c new file mode 100644 index 000000000..b9dbb08ad --- /dev/null +++ b/lib/netaddr.c @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> +#include "netaddr.h" +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <stdlib.h> +#include "byte-order.h" +#include "openvswitch/hmap.h" +#include "openvswitch/dynamic-string.h" +#include "ovs-thread.h" +#include "hash.h" + +const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT; +const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT; +const struct in6_addr in6addr_all_routers = IN6ADDR_ALL_ROUTERS_INIT; +const struct in6_addr in6addr_v4mapped_any = IN6ADDR_V4MAPPED_ANY_INIT; + +uint64_t +eth_addr_to_uint64(const struct eth_addr ea) +{ + return (((uint64_t) ntohs(ea.be16[0]) << 32) + | ((uint64_t) ntohs(ea.be16[1]) << 16) + | ntohs(ea.be16[2])); +} + +void +eth_addr_from_uint64(uint64_t x, struct eth_addr *ea) +{ + ea->be16[0] = htons(x >> 32); + ea->be16[1] = htons((x & 0xFFFF0000) >> 16); + ea->be16[2] = htons(x & 0xFFFF); +} + +void +eth_addr_mark_random(struct eth_addr *ea) +{ + ea->ea[0] &= ~1; /* Unicast. */ + ea->ea[0] |= 2; /* Private. */ +} + +/* Returns true if 'ea' is a reserved address, that a bridge must never + * forward, false otherwise. + * + * If you change this function's behavior, please update corresponding + * documentation in vswitch.xml at the same time. */ +bool +eth_addr_is_reserved(const struct eth_addr ea) +{ + struct eth_addr_node { + struct hmap_node hmap_node; + const uint64_t ea64; + }; + + static struct eth_addr_node nodes[] = { + /* STP, IEEE pause frames, and other reserved protocols. */ + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000000ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000001ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000002ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000003ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000004ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000005ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000006ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000007ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000008ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000009ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000aULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000bULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000cULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000dULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000eULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000fULL }, + + /* Extreme protocols. */ + { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000000ULL }, /* EDP. */ + { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000004ULL }, /* EAPS. */ + { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000006ULL }, /* EAPS. */ + + /* Cisco protocols. */ + { HMAP_NODE_NULL_INITIALIZER, 0x01000c000000ULL }, /* ISL. */ + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccccULL }, /* PAgP, UDLD, CDP, + * DTP, VTP. */ + { HMAP_NODE_NULL_INITIALIZER, 0x01000ccccccdULL }, /* PVST+. */ + { HMAP_NODE_NULL_INITIALIZER, 0x01000ccdcdcdULL }, /* STP Uplink Fast, + * FlexLink. */ + + /* Cisco CFM. */ + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc0ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc1ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc2ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc3ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc4ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc5ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc6ULL }, + { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc7ULL }, + }; + + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + struct eth_addr_node *node; + static struct hmap addrs; + uint64_t ea64; + + if (ovsthread_once_start(&once)) { + hmap_init(&addrs); + for (node = nodes; node < &nodes[ARRAY_SIZE(nodes)]; node++) { + hmap_insert(&addrs, &node->hmap_node, hash_uint64(node->ea64)); + } + ovsthread_once_done(&once); + } + + ea64 = eth_addr_to_uint64(ea); + HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_uint64(ea64), &addrs) { + if (node->ea64 == ea64) { + return true; + } + } + return false; +} + +/* Attempts to parse 's' as an Ethernet address. If successful, stores the + * address in 'ea' and returns true, otherwise zeros 'ea' and returns + * false. This function checks trailing characters. */ +bool +eth_addr_from_string(const char *s, struct eth_addr *ea) +{ + int n = 0; + if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*ea), &n) + && !s[n]) { + return true; + } else { + *ea = eth_addr_zero; + return false; + } +} + +void +eth_format_masked(const struct eth_addr eth, + const struct eth_addr *mask, struct ds *s) +{ + ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth)); + if (mask && !eth_mask_is_exact(*mask)) { + ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(*mask)); + } +} + +void +in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6) +{ + union ovs_16aligned_in6_addr *taddr = + (union ovs_16aligned_in6_addr *) addr; + memset(taddr->be16, 0, sizeof(taddr->be16)); + taddr->be16[0] = htons(0xff02); + taddr->be16[5] = htons(0x1); + taddr->be16[6] = htons(0xff00); + memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3); +} + +/* + * Generates ipv6 EUI64 address from the given eth addr + * and prefix and stores it in 'lla' + */ +void +in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, + struct in6_addr *lla) +{ + union ovs_16aligned_in6_addr *taddr = + (union ovs_16aligned_in6_addr *) lla; + union ovs_16aligned_in6_addr *prefix_taddr = + (union ovs_16aligned_in6_addr *) prefix; + taddr->be16[0] = prefix_taddr->be16[0]; + taddr->be16[1] = prefix_taddr->be16[1]; + taddr->be16[2] = prefix_taddr->be16[2]; + taddr->be16[3] = prefix_taddr->be16[3]; + taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]); + taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff); + taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]); + taddr->be16[7] = ea.be16[2]; +} + +/* Generates ipv6 link local address from the given eth addr + * with prefix 'fe80::/64' and stores it in 'lla'. */ +void +in6_generate_lla(struct eth_addr ea, struct in6_addr *lla) +{ + union ovs_16aligned_in6_addr *taddr = + (union ovs_16aligned_in6_addr *) lla; + memset(taddr->be16, 0, sizeof(taddr->be16)); + taddr->be16[0] = htons(0xfe80); + taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]); + taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff); + taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]); + taddr->be16[7] = ea.be16[2]; +} + +/* Returns true if 'addr' is a link local address. Otherwise, false. */ +bool +in6_is_lla(struct in6_addr *addr) +{ +#ifdef s6_addr32 + return addr->s6_addr32[0] == htonl(0xfe800000) && !(addr->s6_addr32[1]); +#else + return addr->s6_addr[0] == 0xfe && addr->s6_addr[1] == 0x80 && + !(addr->s6_addr[2] | addr->s6_addr[3] | addr->s6_addr[4] | + addr->s6_addr[5] | addr->s6_addr[6] | addr->s6_addr[7]); +#endif +} + +void +ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6) +{ + eth->ea[0] = 0x33; + eth->ea[1] = 0x33; + eth->ea[2] = ip6->s6_addr[12]; + eth->ea[3] = ip6->s6_addr[13]; + eth->ea[4] = ip6->s6_addr[14]; + eth->ea[5] = ip6->s6_addr[15]; +} + +/* Given the IP netmask 'netmask', returns the number of bits of the IP address + * that it specifies, that is, the number of 1-bits in 'netmask'. + * + * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will + * still be in the valid range but isn't otherwise meaningful. */ +int +ip_count_cidr_bits(ovs_be32 netmask) +{ + return 32 - ctz32(ntohl(netmask)); +} + +void +ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s) +{ + ds_put_format(s, IP_FMT, IP_ARGS(ip)); + if (mask != OVS_BE32_MAX) { + if (ip_is_cidr(mask)) { + ds_put_format(s, "/%d", ip_count_cidr_bits(mask)); + } else { + ds_put_format(s, "/"IP_FMT, IP_ARGS(mask)); + } + } +} + +/* Parses string 's', which must be an IP address. Stores the IP address into + * '*ip'. Returns true if successful, otherwise false. */ +bool +ip_parse(const char *s, ovs_be32 *ip) +{ + return inet_pton(AF_INET, s, ip) == 1; +} + +/* Parses string 's', which must be an IP address with a port number + * with ":" as a separator (e.g.: 192.168.1.2:80). + * Stores the IP address into '*ip' and port number to '*port'. + * + * Returns NULL if successful, otherwise an error message that the caller must + * free(). */ +char * OVS_WARN_UNUSED_RESULT +ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) +{ + int n = 0; + if (ovs_scan(s, IP_PORT_SCAN_FMT"%n", IP_PORT_SCAN_ARGS(ip, port), &n) + && !s[n]) { + return NULL; + } + + return xasprintf("%s: invalid IP address or port number", s); +} + +/* Parses string 's', which must be an IP address with an optional netmask or + * CIDR prefix length. Stores the IP address into '*ip', netmask into '*mask', + * (255.255.255.255, if 's' lacks a netmask), and number of scanned characters + * into '*n'. + * + * Returns NULL if successful, otherwise an error message that the caller must + * free(). */ +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: IPv4 network prefix bits not between 0 and " + "32, inclusive", 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; +} + +/* This function is similar to ip_parse_masked_len(), but doesn't return the + * number of scanned characters and expects 's' to end after the ip/(optional) + * mask. + * + * Returns NULL if successful, otherwise an error message that the caller must + * free(). */ +char * OVS_WARN_UNUSED_RESULT +ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) +{ + int n = 0; + + char *error = ip_parse_masked_len(s, &n, ip, mask); + if (!error && s[n]) { + return xasprintf("%s: invalid IP address", s); + } + return error; +} + +/* Similar to ip_parse_masked_len(), but the mask, if present, must be a CIDR + * mask and is returned as a prefix len in '*plen'. */ +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; +} + +/* Similar to ip_parse_cidr_len(), but doesn't return the number of scanned + * characters and expects 's' to be NULL terminated at the end of the + * ip/(optional) cidr. */ +char * OVS_WARN_UNUSED_RESULT +ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) +{ + int n = 0; + + char *error = ip_parse_cidr_len(s, &n, ip, plen); + if (!error && s[n]) { + return xasprintf("%s: invalid IP address", s); + } + return error; +} + +/* Parses string 's', which must be an IPv6 address. Stores the IPv6 address + * into '*ip'. Returns true if successful, otherwise false. */ +bool +ipv6_parse(const char *s, struct in6_addr *ip) +{ + return inet_pton(AF_INET6, s, ip) == 1; +} + +/* Parses string 's', which must be an IPv6 address with an optional netmask or + * CIDR prefix length. Stores the IPv6 address into '*ip' and the netmask into + * '*mask' (if 's' does not contain a netmask, all-one-bits is assumed), and + * number of scanned characters into '*n'. + * + * Returns NULL if successful, otherwise an error message that the caller must + * free(). */ +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, inclusive", 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); +} + +/* This function is similar to ipv6_parse_masked_len(), but doesn't return the + * number of scanned characters and expects 's' to end following the + * ipv6/(optional) mask. */ +char * OVS_WARN_UNUSED_RESULT +ipv6_parse_masked(const char *s, struct in6_addr *ip, struct in6_addr *mask) +{ + int n = 0; + + char *error = ipv6_parse_masked_len(s, &n, ip, mask); + if (!error && s[n]) { + return xasprintf("%s: invalid IPv6 address", s); + } + return error; +} + +/* Similar to ipv6_parse_masked_len(), but the mask, if present, must be a CIDR + * mask and is returned as a prefix length in '*plen'. */ +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; +} + +/* Similar to ipv6_parse_cidr_len(), but doesn't return the number of scanned + * characters and expects 's' to end after the ipv6/(optional) cidr. */ +char * OVS_WARN_UNUSED_RESULT +ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen) +{ + int n = 0; + + char *error = ipv6_parse_cidr_len(s, &n, ip, plen); + if (!error && s[n]) { + return xasprintf("%s: invalid IPv6 address", s); + } + return error; +} + +/* Stores the string representation of the IPv6 address 'addr' into the + * character array 'addr_str', which must be at least INET6_ADDRSTRLEN + * bytes long. */ +void +ipv6_format_addr(const struct in6_addr *addr, struct ds *s) +{ + char *dst; + + ds_reserve(s, s->length + INET6_ADDRSTRLEN); + + dst = s->string + s->length; + inet_ntop(AF_INET6, addr, dst, INET6_ADDRSTRLEN); + s->length += strlen(dst); +} + +/* Same as print_ipv6_addr, but optionally encloses the address in square + * brackets. */ +void +ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *s, + bool bracket) +{ + if (bracket) { + ds_put_char(s, '['); + } + ipv6_format_addr(addr, s); + if (bracket) { + ds_put_char(s, ']'); + } +} + +void +ipv6_format_mapped(const struct in6_addr *addr, struct ds *s) +{ + if (IN6_IS_ADDR_V4MAPPED(addr)) { + ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } else { + ipv6_format_addr(addr, s); + } +} + +void +ipv6_format_masked(const struct in6_addr *addr, const struct in6_addr *mask, + struct ds *s) +{ + ipv6_format_addr(addr, s); + if (mask && !ipv6_mask_is_exact(mask)) { + if (ipv6_is_cidr(mask)) { + int cidr_bits = ipv6_count_cidr_bits(mask); + ds_put_format(s, "/%d", cidr_bits); + } else { + ds_put_char(s, '/'); + ipv6_format_addr(mask, s); + } + } +} + +/* Stores the string representation of the IPv6 address 'addr' into the + * character array 'addr_str', which must be at least INET6_ADDRSTRLEN + * bytes long. If addr is IPv4-mapped, store an IPv4 dotted-decimal string. */ +const char * +ipv6_string_mapped(char *addr_str, const struct in6_addr *addr) +{ + ovs_be32 ip; + ip = in6_addr_get_mapped_ipv4(addr); + if (ip) { + return inet_ntop(AF_INET, &ip, addr_str, INET6_ADDRSTRLEN); + } else { + return inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); + } +} + +#ifdef s6_addr32 +#define s6_addrX s6_addr32 +#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 4; VAR++) +#else +#define s6_addrX s6_addr +#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 16; VAR++) +#endif + +struct in6_addr +ipv6_addr_bitand(const struct in6_addr *a, const struct in6_addr *b) +{ + struct in6_addr dst; + IPV6_FOR_EACH (i) { + dst.s6_addrX[i] = a->s6_addrX[i] & b->s6_addrX[i]; + } + return dst; +} + +struct in6_addr +ipv6_addr_bitxor(const struct in6_addr *a, const struct in6_addr *b) +{ + struct in6_addr dst; + IPV6_FOR_EACH (i) { + dst.s6_addrX[i] = a->s6_addrX[i] ^ b->s6_addrX[i]; + } + return dst; +} + +bool +ipv6_is_zero(const struct in6_addr *a) +{ + IPV6_FOR_EACH (i) { + if (a->s6_addrX[i]) { + return false; + } + } + return true; +} + +/* Returns an in6_addr consisting of 'mask' high-order 1-bits and 128-N + * low-order 0-bits. */ +struct in6_addr +ipv6_create_mask(int mask) +{ + struct in6_addr netmask; + uint8_t *netmaskp = &netmask.s6_addr[0]; + + memset(&netmask, 0, sizeof netmask); + while (mask > 8) { + *netmaskp = 0xff; + netmaskp++; + mask -= 8; + } + + if (mask) { + *netmaskp = 0xff << (8 - mask); + } + + return netmask; +} + +/* Given the IPv6 netmask 'netmask', returns the number of bits of the IPv6 + * address that it specifies, that is, the number of 1-bits in 'netmask'. + * 'netmask' must be a CIDR netmask (see ipv6_is_cidr()). + * + * If 'netmask' is not a CIDR netmask (see ipv6_is_cidr()), the return value + * will still be in the valid range but isn't otherwise meaningful. */ +int +ipv6_count_cidr_bits(const struct in6_addr *netmask) +{ + int i; + int count = 0; + const uint8_t *netmaskp = &netmask->s6_addr[0]; + + for (i = 0; i < 16; i++) { + if (netmaskp[i] == 0xff) { + count += 8; + } else { + uint8_t nm; + + for (nm = netmaskp[i]; nm; nm <<= 1) { + count++; + } + break; + } + + } + + return count; +} + +/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N + * high-order 1-bits and 128-N low-order 0-bits. */ +bool +ipv6_is_cidr(const struct in6_addr *netmask) +{ + const uint8_t *netmaskp = &netmask->s6_addr[0]; + int i; + + for (i = 0; i < 16; i++) { + if (netmaskp[i] != 0xff) { + uint8_t x = ~netmaskp[i]; + if (x & (x + 1)) { + return false; + } + while (++i < 16) { + if (netmaskp[i]) { + return false; + } + } + } + } + + return true; +} + +bool +ipv6_addr_equals_masked(const struct in6_addr *a, const struct in6_addr *b, + int plen) +{ + struct in6_addr mask; + struct in6_addr ma; + struct in6_addr mb; + + if (plen == 128) { + return ipv6_addr_equals(a, b); + } + + mask = ipv6_create_mask(plen); + ma = ipv6_addr_bitand(a, &mask); + mb = ipv6_addr_bitand(b, &mask); + + return ipv6_addr_equals(&ma, &mb); +} diff --git a/lib/netaddr.h b/lib/netaddr.h new file mode 100644 index 000000000..d9469e2b5 --- /dev/null +++ b/lib/netaddr.h @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, + * 2017 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NETADDR_H +#define NETADDR_H 1 + +#include <inttypes.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdint.h> +#include <string.h> +#include "compiler.h" +#include "openvswitch/types.h" +#include "random.h" +#include "unaligned.h" +#include "util.h" + +struct ds; + +/* Ethernet address. */ + +#define ETH_ADDR_LEN 6 + +static const struct eth_addr eth_addr_broadcast OVS_UNUSED + = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); + +static const struct eth_addr eth_addr_exact OVS_UNUSED + = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); + +static const struct eth_addr eth_addr_zero OVS_UNUSED + = ETH_ADDR_C(00,00,00,00,00,00); +static const struct eth_addr64 eth_addr64_zero OVS_UNUSED + = ETH_ADDR64_C(00,00,00,00,00,00,00,00); + +static const struct eth_addr eth_addr_stp OVS_UNUSED + = ETH_ADDR_C(01,80,c2,00,00,00); + +static const struct eth_addr eth_addr_lacp OVS_UNUSED + = ETH_ADDR_C(01,80,c2,00,00,02); + +static const struct eth_addr eth_addr_bfd OVS_UNUSED + = ETH_ADDR_C(00,23,20,00,00,01); + +static inline bool eth_addr_is_broadcast(const struct eth_addr a) +{ + return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); +} + +static inline bool eth_addr_is_multicast(const struct eth_addr a) +{ + return a.ea[0] & 1; +} + +static inline bool eth_addr_is_local(const struct eth_addr a) +{ + /* Local if it is either a locally administered address or a Nicira random + * address. */ + return a.ea[0] & 2 + || (a.be16[0] == htons(0x0023) + && (a.be16[1] & htons(0xff80)) == htons(0x2080)); +} +static inline bool eth_addr_is_zero(const struct eth_addr a) +{ + return !(a.be16[0] | a.be16[1] | a.be16[2]); +} +static inline bool eth_addr64_is_zero(const struct eth_addr64 a) +{ + return !(a.be16[0] | a.be16[1] | a.be16[2] | a.be16[3]); +} + +static inline int eth_mask_is_exact(const struct eth_addr a) +{ + return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); +} + +static inline int eth_addr_compare_3way(const struct eth_addr a, + const struct eth_addr b) +{ + return memcmp(&a, &b, sizeof a); +} +static inline int eth_addr64_compare_3way(const struct eth_addr64 a, + const struct eth_addr64 b) +{ + return memcmp(&a, &b, sizeof a); +} + +static inline bool eth_addr_equals(const struct eth_addr a, + const struct eth_addr b) +{ + return !eth_addr_compare_3way(a, b); +} +static inline bool eth_addr64_equals(const struct eth_addr64 a, + const struct eth_addr64 b) +{ + return !eth_addr64_compare_3way(a, b); +} + +static inline bool eth_addr_equal_except(const struct eth_addr a, + const struct eth_addr b, + const struct eth_addr mask) +{ + return !(((a.be16[0] ^ b.be16[0]) & mask.be16[0]) + || ((a.be16[1] ^ b.be16[1]) & mask.be16[1]) + || ((a.be16[2] ^ b.be16[2]) & mask.be16[2])); +} + +uint64_t eth_addr_to_uint64(const struct eth_addr ea); + +static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea, + uint16_t vlan) +{ + return (((uint64_t) vlan << 48) | eth_addr_to_uint64(ea)); +} + +void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea); + +static inline struct eth_addr eth_addr_invert(const struct eth_addr src) +{ + struct eth_addr dst; + + for (int i = 0; i < ARRAY_SIZE(src.be16); i++) { + dst.be16[i] = ~src.be16[i]; + } + + return dst; +} + +void eth_addr_mark_random(struct eth_addr *ea); + +static inline void eth_addr_random(struct eth_addr *ea) +{ + random_bytes((uint8_t *) ea, sizeof *ea); + eth_addr_mark_random(ea); +} + +static inline void eth_addr_nicira_random(struct eth_addr *ea) +{ + eth_addr_random(ea); + + /* Set the OUI to the Nicira one. */ + ea->ea[0] = 0x00; + ea->ea[1] = 0x23; + ea->ea[2] = 0x20; + + /* Set the top bit to indicate random Nicira address. */ + ea->ea[3] |= 0x80; +} + +bool eth_addr_is_reserved(const struct eth_addr); +bool eth_addr_from_string(const char *, struct eth_addr *); + +void eth_format_masked(const struct eth_addr ea, + const struct eth_addr *mask, struct ds *s); + +/* Example: + * + * struct eth_addr mac; + * [...] + * printf("The Ethernet address is "ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(mac)); + * + */ +#define ETH_ADDR_FMT \ + "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 +#define ETH_ADDR_ARGS(EA) ETH_ADDR_BYTES_ARGS((EA).ea) +#define ETH_ADDR_BYTES_ARGS(EAB) \ + (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], (EAB)[4], (EAB)[5] +#define ETH_ADDR_STRLEN 17 + +/* Example: + * + * struct eth_addr64 eui64; + * [...] + * printf("The EUI-64 address is "ETH_ADDR64_FMT"\n", ETH_ADDR64_ARGS(mac)); + * + */ +#define ETH_ADDR64_FMT \ + "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":" \ + "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 +#define ETH_ADDR64_ARGS(EA) ETH_ADDR64_BYTES_ARGS((EA).ea64) +#define ETH_ADDR64_BYTES_ARGS(EAB) \ + (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], \ + (EAB)[4], (EAB)[5], (EAB)[6], (EAB)[7] +#define ETH_ADDR64_STRLEN 23 + +/* Example: + * + * char *string = "1 00:11:22:33:44:55 2"; + * struct eth_addr mac; + * int a, b; + * + * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d", + * &a, ETH_ADDR_SCAN_ARGS(mac), &b)) { + * ... + * } + */ +#define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8 +#define ETH_ADDR_SCAN_ARGS(EA) \ + &(EA).ea[0], &(EA).ea[1], &(EA).ea[2], \ + &(EA).ea[3], &(EA).ea[4], &(EA).ea[5] + +/* IPv4 address. */ + +#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32 +#define IP_ARGS(ip) \ + ntohl(ip) >> 24, \ + (ntohl(ip) >> 16) & 0xff, \ + (ntohl(ip) >> 8) & 0xff, \ + ntohl(ip) & 0xff + +/* Example: + * + * char *string = "1 33.44.55.66 2"; + * ovs_be32 ip; + * int a, b; + * + * if (ovs_scan(string, "%d"IP_SCAN_FMT"%d", &a, IP_SCAN_ARGS(&ip), &b)) { + * ... + * } + */ +#define IP_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8 +#define IP_SCAN_ARGS(ip) \ + ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ + &((uint8_t *) ip)[1], \ + &((uint8_t *) ip)[2], \ + &((uint8_t *) ip)[3] + +#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16 +#define IP_PORT_SCAN_ARGS(ip, port) \ + ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ + &((uint8_t *) ip)[1], \ + &((uint8_t *) ip)[2], \ + &((uint8_t *) ip)[3], \ + ((void) (ovs_be16) *(port), (uint16_t *) port) + +/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N + * high-order 1-bits and 32-N low-order 0-bits. */ +static inline bool +ip_is_cidr(ovs_be32 netmask) +{ + uint32_t x = ~ntohl(netmask); + return !(x & (x + 1)); +} +static inline bool +ip_is_multicast(ovs_be32 ip) +{ + return (ip & htonl(0xf0000000)) == htonl(0xe0000000); +} +static inline bool +ip_is_local_multicast(ovs_be32 ip) +{ + return (ip & htonl(0xffffff00)) == htonl(0xe0000000); +} +int ip_count_cidr_bits(ovs_be32 netmask); +void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *); +bool ip_parse(const char *s, ovs_be32 *ip); +char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) + OVS_WARN_UNUSED_RESULT; +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; + +/* IPv6 address. */ + +/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on + * most implementations, this one only requires 16-bit alignment. */ +union ovs_16aligned_in6_addr { + ovs_be16 be16[8]; + ovs_16aligned_be32 be32[4]; +}; +BUILD_ASSERT_DECL(sizeof(union ovs_16aligned_in6_addr) + == sizeof(struct in6_addr)); + +/* Example: + * + * char *string = "1 ::1 2"; + * char ipv6_s[IPV6_SCAN_LEN + 1]; + * struct in6_addr ipv6; + * + * if (ovs_scan(string, "%d"IPV6_SCAN_FMT"%d", &a, ipv6_s, &b) + * && inet_pton(AF_INET6, ipv6_s, &ipv6) == 1) { + * ... + * } + */ +#define IPV6_SCAN_FMT "%46[0123456789abcdefABCDEF:.]" +#define IPV6_SCAN_LEN 46 + +extern const struct in6_addr in6addr_exact; +#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } } + +extern const struct in6_addr in6addr_all_hosts; +#define IN6ADDR_ALL_HOSTS_INIT \ + { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } } + +extern const struct in6_addr in6addr_all_routers; +#define IN6ADDR_ALL_ROUTERS_INIT \ + { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } } + +extern const struct in6_addr in6addr_v4mapped_any; +#define IN6ADDR_V4MAPPED_ANY_INIT \ + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } } + +static inline bool ipv6_addr_equals(const struct in6_addr *a, + const struct in6_addr *b) +{ +#ifdef IN6_ARE_ADDR_EQUAL + return IN6_ARE_ADDR_EQUAL(a, b); +#else + return !memcmp(a, b, sizeof(*a)); +#endif +} + +/* Checks the IPv6 address in 'mask' for all zeroes. */ +static inline bool ipv6_mask_is_any(const struct in6_addr *mask) { + return ipv6_addr_equals(mask, &in6addr_any); +} + +static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) { + return ipv6_addr_equals(mask, &in6addr_exact); +} + +static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) { + return ipv6_addr_equals(addr, &in6addr_all_hosts); +} + +static inline bool ipv6_addr_is_set(const struct in6_addr *addr) { + return !ipv6_addr_equals(addr, &in6addr_any); +} + +static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) { + return ip->s6_addr[0] == 0xff; +} + +static inline struct in6_addr +in6_addr_mapped_ipv4(ovs_be32 ip4) +{ + struct in6_addr ip6; + memset(&ip6, 0, sizeof(ip6)); + ip6.s6_addr[10] = 0xff, ip6.s6_addr[11] = 0xff; + memcpy(&ip6.s6_addr[12], &ip4, 4); + return ip6; +} + +static inline void +in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4) +{ + *ip6 = in6_addr_mapped_ipv4(ip4); +} + +static inline ovs_be32 +in6_addr_get_mapped_ipv4(const struct in6_addr *addr) +{ + union ovs_16aligned_in6_addr *taddr = + (union ovs_16aligned_in6_addr *) addr; + if (IN6_IS_ADDR_V4MAPPED(addr)) { + return get_16aligned_be32(&taddr->be32[3]); + } else { + return INADDR_ANY; + } +} + +void in6_addr_solicited_node(struct in6_addr *addr, + const struct in6_addr *ip6); + +void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, + struct in6_addr *lla); + +void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla); + +/* Returns true if 'addr' is a link local address. Otherwise, false. */ +bool in6_is_lla(struct in6_addr *addr); + +void ipv6_multicast_to_ethernet(struct eth_addr *eth, + const struct in6_addr *ip6); + +void ipv6_format_addr(const struct in6_addr *addr, struct ds *); +void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *, + bool bracket); +void ipv6_format_mapped(const struct in6_addr *addr, struct ds *); +void ipv6_format_masked(const struct in6_addr *addr, + const struct in6_addr *mask, struct ds *); +const char * ipv6_string_mapped(char *addr_str, const struct in6_addr *addr); +struct in6_addr ipv6_addr_bitand(const struct in6_addr *src, + const struct in6_addr *mask); +struct in6_addr ipv6_addr_bitxor(const struct in6_addr *a, + const struct in6_addr *b); +bool ipv6_is_zero(const struct in6_addr *a); +struct in6_addr ipv6_create_mask(int mask); +int ipv6_count_cidr_bits(const struct in6_addr *netmask); +bool ipv6_is_cidr(const struct in6_addr *netmask); +bool ipv6_addr_equals_masked(const struct in6_addr *a, + const struct in6_addr *b, int plen); + +bool ipv6_parse(const char *s, struct in6_addr *ip); +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; + +#endif /* netaddr.h */ diff --git a/lib/packets.c b/lib/packets.c index 80c41e4b6..b239afb0c 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -36,11 +36,6 @@ #include "dp-packet-gso.h" #include "unaligned.h" -const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT; -const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT; -const struct in6_addr in6addr_all_routers = IN6ADDR_ALL_ROUTERS_INIT; -const struct in6_addr in6addr_v4mapped_any = IN6ADDR_V4MAPPED_ANY_INIT; - struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl) { @@ -77,123 +72,6 @@ dpid_from_string(const char *s, uint64_t *dpidp) return *dpidp != 0; } -uint64_t -eth_addr_to_uint64(const struct eth_addr ea) -{ - return (((uint64_t) ntohs(ea.be16[0]) << 32) - | ((uint64_t) ntohs(ea.be16[1]) << 16) - | ntohs(ea.be16[2])); -} - -void -eth_addr_from_uint64(uint64_t x, struct eth_addr *ea) -{ - ea->be16[0] = htons(x >> 32); - ea->be16[1] = htons((x & 0xFFFF0000) >> 16); - ea->be16[2] = htons(x & 0xFFFF); -} - -void -eth_addr_mark_random(struct eth_addr *ea) -{ - ea->ea[0] &= ~1; /* Unicast. */ - ea->ea[0] |= 2; /* Private. */ -} - -/* Returns true if 'ea' is a reserved address, that a bridge must never - * forward, false otherwise. - * - * If you change this function's behavior, please update corresponding - * documentation in vswitch.xml at the same time. */ -bool -eth_addr_is_reserved(const struct eth_addr ea) -{ - struct eth_addr_node { - struct hmap_node hmap_node; - const uint64_t ea64; - }; - - static struct eth_addr_node nodes[] = { - /* STP, IEEE pause frames, and other reserved protocols. */ - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000000ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000001ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000002ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000003ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000004ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000005ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000006ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000007ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000008ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000009ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000aULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000bULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000cULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000dULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000eULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000fULL }, - - /* Extreme protocols. */ - { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000000ULL }, /* EDP. */ - { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000004ULL }, /* EAPS. */ - { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000006ULL }, /* EAPS. */ - - /* Cisco protocols. */ - { HMAP_NODE_NULL_INITIALIZER, 0x01000c000000ULL }, /* ISL. */ - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccccULL }, /* PAgP, UDLD, CDP, - * DTP, VTP. */ - { HMAP_NODE_NULL_INITIALIZER, 0x01000ccccccdULL }, /* PVST+. */ - { HMAP_NODE_NULL_INITIALIZER, 0x01000ccdcdcdULL }, /* STP Uplink Fast, - * FlexLink. */ - - /* Cisco CFM. */ - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc0ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc1ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc2ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc3ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc4ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc5ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc6ULL }, - { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc7ULL }, - }; - - static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; - struct eth_addr_node *node; - static struct hmap addrs; - uint64_t ea64; - - if (ovsthread_once_start(&once)) { - hmap_init(&addrs); - for (node = nodes; node < &nodes[ARRAY_SIZE(nodes)]; node++) { - hmap_insert(&addrs, &node->hmap_node, hash_uint64(node->ea64)); - } - ovsthread_once_done(&once); - } - - ea64 = eth_addr_to_uint64(ea); - HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_uint64(ea64), &addrs) { - if (node->ea64 == ea64) { - return true; - } - } - return false; -} - -/* Attempts to parse 's' as an Ethernet address. If successful, stores the - * address in 'ea' and returns true, otherwise zeros 'ea' and returns - * false. This function checks trailing characters. */ -bool -eth_addr_from_string(const char *s, struct eth_addr *ea) -{ - int n = 0; - if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*ea), &n) - && !s[n]) { - return true; - } else { - *ea = eth_addr_zero; - return false; - } -} - /* Fills 'b' with a Reverse ARP packet with Ethernet source address 'eth_src'. * This function is used by Open vSwitch to compose packets in cases where * context is important but content doesn't (or shouldn't) matter. @@ -583,525 +461,6 @@ eth_from_hex(const char *hex, struct dp_packet **packetp) return NULL; } - -void -eth_format_masked(const struct eth_addr eth, - const struct eth_addr *mask, struct ds *s) -{ - ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth)); - if (mask && !eth_mask_is_exact(*mask)) { - ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(*mask)); - } -} - -void -in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6) -{ - union ovs_16aligned_in6_addr *taddr = - (union ovs_16aligned_in6_addr *) addr; - memset(taddr->be16, 0, sizeof(taddr->be16)); - taddr->be16[0] = htons(0xff02); - taddr->be16[5] = htons(0x1); - taddr->be16[6] = htons(0xff00); - memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3); -} - -/* - * Generates ipv6 EUI64 address from the given eth addr - * and prefix and stores it in 'lla' - */ -void -in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, - struct in6_addr *lla) -{ - union ovs_16aligned_in6_addr *taddr = - (union ovs_16aligned_in6_addr *) lla; - union ovs_16aligned_in6_addr *prefix_taddr = - (union ovs_16aligned_in6_addr *) prefix; - taddr->be16[0] = prefix_taddr->be16[0]; - taddr->be16[1] = prefix_taddr->be16[1]; - taddr->be16[2] = prefix_taddr->be16[2]; - taddr->be16[3] = prefix_taddr->be16[3]; - taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]); - taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff); - taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]); - taddr->be16[7] = ea.be16[2]; -} - -/* Generates ipv6 link local address from the given eth addr - * with prefix 'fe80::/64' and stores it in 'lla'. */ -void -in6_generate_lla(struct eth_addr ea, struct in6_addr *lla) -{ - union ovs_16aligned_in6_addr *taddr = - (union ovs_16aligned_in6_addr *) lla; - memset(taddr->be16, 0, sizeof(taddr->be16)); - taddr->be16[0] = htons(0xfe80); - taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]); - taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff); - taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]); - taddr->be16[7] = ea.be16[2]; -} - -/* Returns true if 'addr' is a link local address. Otherwise, false. */ -bool -in6_is_lla(struct in6_addr *addr) -{ -#ifdef s6_addr32 - return addr->s6_addr32[0] == htonl(0xfe800000) && !(addr->s6_addr32[1]); -#else - return addr->s6_addr[0] == 0xfe && addr->s6_addr[1] == 0x80 && - !(addr->s6_addr[2] | addr->s6_addr[3] | addr->s6_addr[4] | - addr->s6_addr[5] | addr->s6_addr[6] | addr->s6_addr[7]); -#endif -} - -void -ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6) -{ - eth->ea[0] = 0x33; - eth->ea[1] = 0x33; - eth->ea[2] = ip6->s6_addr[12]; - eth->ea[3] = ip6->s6_addr[13]; - eth->ea[4] = ip6->s6_addr[14]; - eth->ea[5] = ip6->s6_addr[15]; -} - -/* Given the IP netmask 'netmask', returns the number of bits of the IP address - * that it specifies, that is, the number of 1-bits in 'netmask'. - * - * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will - * still be in the valid range but isn't otherwise meaningful. */ -int -ip_count_cidr_bits(ovs_be32 netmask) -{ - return 32 - ctz32(ntohl(netmask)); -} - -void -ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s) -{ - ds_put_format(s, IP_FMT, IP_ARGS(ip)); - if (mask != OVS_BE32_MAX) { - if (ip_is_cidr(mask)) { - ds_put_format(s, "/%d", ip_count_cidr_bits(mask)); - } else { - ds_put_format(s, "/"IP_FMT, IP_ARGS(mask)); - } - } -} - -/* Parses string 's', which must be an IP address. Stores the IP address into - * '*ip'. Returns true if successful, otherwise false. */ -bool -ip_parse(const char *s, ovs_be32 *ip) -{ - return inet_pton(AF_INET, s, ip) == 1; -} - -/* Parses string 's', which must be an IP address with a port number - * with ":" as a separator (e.g.: 192.168.1.2:80). - * Stores the IP address into '*ip' and port number to '*port'. - * - * Returns NULL if successful, otherwise an error message that the caller must - * free(). */ -char * OVS_WARN_UNUSED_RESULT -ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) -{ - int n = 0; - if (ovs_scan(s, IP_PORT_SCAN_FMT"%n", IP_PORT_SCAN_ARGS(ip, port), &n) - && !s[n]) { - return NULL; - } - - return xasprintf("%s: invalid IP address or port number", s); -} - -/* Parses string 's', which must be an IP address with an optional netmask or - * CIDR prefix length. Stores the IP address into '*ip', netmask into '*mask', - * (255.255.255.255, if 's' lacks a netmask), and number of scanned characters - * into '*n'. - * - * Returns NULL if successful, otherwise an error message that the caller must - * free(). */ -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: IPv4 network prefix bits not between 0 and " - "32, inclusive", 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; -} - -/* This function is similar to ip_parse_masked_len(), but doesn't return the - * number of scanned characters and expects 's' to end after the ip/(optional) - * mask. - * - * Returns NULL if successful, otherwise an error message that the caller must - * free(). */ -char * OVS_WARN_UNUSED_RESULT -ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask) -{ - int n = 0; - - char *error = ip_parse_masked_len(s, &n, ip, mask); - if (!error && s[n]) { - return xasprintf("%s: invalid IP address", s); - } - return error; -} - -/* Similar to ip_parse_masked_len(), but the mask, if present, must be a CIDR - * mask and is returned as a prefix len in '*plen'. */ -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; -} - -/* Similar to ip_parse_cidr_len(), but doesn't return the number of scanned - * characters and expects 's' to be NULL terminated at the end of the - * ip/(optional) cidr. */ -char * OVS_WARN_UNUSED_RESULT -ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen) -{ - int n = 0; - - char *error = ip_parse_cidr_len(s, &n, ip, plen); - if (!error && s[n]) { - return xasprintf("%s: invalid IP address", s); - } - return error; -} - -/* Parses string 's', which must be an IPv6 address. Stores the IPv6 address - * into '*ip'. Returns true if successful, otherwise false. */ -bool -ipv6_parse(const char *s, struct in6_addr *ip) -{ - return inet_pton(AF_INET6, s, ip) == 1; -} - -/* Parses string 's', which must be an IPv6 address with an optional netmask or - * CIDR prefix length. Stores the IPv6 address into '*ip' and the netmask into - * '*mask' (if 's' does not contain a netmask, all-one-bits is assumed), and - * number of scanned characters into '*n'. - * - * Returns NULL if successful, otherwise an error message that the caller must - * free(). */ -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, inclusive", 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); -} - -/* This function is similar to ipv6_parse_masked_len(), but doesn't return the - * number of scanned characters and expects 's' to end following the - * ipv6/(optional) mask. */ -char * OVS_WARN_UNUSED_RESULT -ipv6_parse_masked(const char *s, struct in6_addr *ip, struct in6_addr *mask) -{ - int n = 0; - - char *error = ipv6_parse_masked_len(s, &n, ip, mask); - if (!error && s[n]) { - return xasprintf("%s: invalid IPv6 address", s); - } - return error; -} - -/* Similar to ipv6_parse_masked_len(), but the mask, if present, must be a CIDR - * mask and is returned as a prefix length in '*plen'. */ -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; -} - -/* Similar to ipv6_parse_cidr_len(), but doesn't return the number of scanned - * characters and expects 's' to end after the ipv6/(optional) cidr. */ -char * OVS_WARN_UNUSED_RESULT -ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen) -{ - int n = 0; - - char *error = ipv6_parse_cidr_len(s, &n, ip, plen); - if (!error && s[n]) { - return xasprintf("%s: invalid IPv6 address", s); - } - return error; -} - -/* Stores the string representation of the IPv6 address 'addr' into the - * character array 'addr_str', which must be at least INET6_ADDRSTRLEN - * bytes long. */ -void -ipv6_format_addr(const struct in6_addr *addr, struct ds *s) -{ - char *dst; - - ds_reserve(s, s->length + INET6_ADDRSTRLEN); - - dst = s->string + s->length; - inet_ntop(AF_INET6, addr, dst, INET6_ADDRSTRLEN); - s->length += strlen(dst); -} - -/* Same as print_ipv6_addr, but optionally encloses the address in square - * brackets. */ -void -ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *s, - bool bracket) -{ - if (bracket) { - ds_put_char(s, '['); - } - ipv6_format_addr(addr, s); - if (bracket) { - ds_put_char(s, ']'); - } -} - -void -ipv6_format_mapped(const struct in6_addr *addr, struct ds *s) -{ - if (IN6_IS_ADDR_V4MAPPED(addr)) { - ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } else { - ipv6_format_addr(addr, s); - } -} - -void -ipv6_format_masked(const struct in6_addr *addr, const struct in6_addr *mask, - struct ds *s) -{ - ipv6_format_addr(addr, s); - if (mask && !ipv6_mask_is_exact(mask)) { - if (ipv6_is_cidr(mask)) { - int cidr_bits = ipv6_count_cidr_bits(mask); - ds_put_format(s, "/%d", cidr_bits); - } else { - ds_put_char(s, '/'); - ipv6_format_addr(mask, s); - } - } -} - -/* Stores the string representation of the IPv6 address 'addr' into the - * character array 'addr_str', which must be at least INET6_ADDRSTRLEN - * bytes long. If addr is IPv4-mapped, store an IPv4 dotted-decimal string. */ -const char * -ipv6_string_mapped(char *addr_str, const struct in6_addr *addr) -{ - ovs_be32 ip; - ip = in6_addr_get_mapped_ipv4(addr); - if (ip) { - return inet_ntop(AF_INET, &ip, addr_str, INET6_ADDRSTRLEN); - } else { - return inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); - } -} - -#ifdef s6_addr32 -#define s6_addrX s6_addr32 -#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 4; VAR++) -#else -#define s6_addrX s6_addr -#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 16; VAR++) -#endif - -struct in6_addr -ipv6_addr_bitand(const struct in6_addr *a, const struct in6_addr *b) -{ - struct in6_addr dst; - IPV6_FOR_EACH (i) { - dst.s6_addrX[i] = a->s6_addrX[i] & b->s6_addrX[i]; - } - return dst; -} - -struct in6_addr -ipv6_addr_bitxor(const struct in6_addr *a, const struct in6_addr *b) -{ - struct in6_addr dst; - IPV6_FOR_EACH (i) { - dst.s6_addrX[i] = a->s6_addrX[i] ^ b->s6_addrX[i]; - } - return dst; -} - -bool -ipv6_is_zero(const struct in6_addr *a) -{ - IPV6_FOR_EACH (i) { - if (a->s6_addrX[i]) { - return false; - } - } - return true; -} - -/* Returns an in6_addr consisting of 'mask' high-order 1-bits and 128-N - * low-order 0-bits. */ -struct in6_addr -ipv6_create_mask(int mask) -{ - struct in6_addr netmask; - uint8_t *netmaskp = &netmask.s6_addr[0]; - - memset(&netmask, 0, sizeof netmask); - while (mask > 8) { - *netmaskp = 0xff; - netmaskp++; - mask -= 8; - } - - if (mask) { - *netmaskp = 0xff << (8 - mask); - } - - return netmask; -} - -/* Given the IPv6 netmask 'netmask', returns the number of bits of the IPv6 - * address that it specifies, that is, the number of 1-bits in 'netmask'. - * 'netmask' must be a CIDR netmask (see ipv6_is_cidr()). - * - * If 'netmask' is not a CIDR netmask (see ipv6_is_cidr()), the return value - * will still be in the valid range but isn't otherwise meaningful. */ -int -ipv6_count_cidr_bits(const struct in6_addr *netmask) -{ - int i; - int count = 0; - const uint8_t *netmaskp = &netmask->s6_addr[0]; - - for (i=0; i<16; i++) { - if (netmaskp[i] == 0xff) { - count += 8; - } else { - uint8_t nm; - - for(nm = netmaskp[i]; nm; nm <<= 1) { - count++; - } - break; - } - - } - - return count; -} - -/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N - * high-order 1-bits and 128-N low-order 0-bits. */ -bool -ipv6_is_cidr(const struct in6_addr *netmask) -{ - const uint8_t *netmaskp = &netmask->s6_addr[0]; - int i; - - for (i=0; i<16; i++) { - if (netmaskp[i] != 0xff) { - uint8_t x = ~netmaskp[i]; - if (x & (x + 1)) { - return false; - } - while (++i < 16) { - if (netmaskp[i]) { - return false; - } - } - } - } - - return true; -} - -bool -ipv6_addr_equals_masked(const struct in6_addr *a, const struct in6_addr *b, - int plen) -{ - struct in6_addr mask; - struct in6_addr ma; - struct in6_addr mb; - - if (plen == 128) { - return ipv6_addr_equals(a, b); - } - - mask = ipv6_create_mask(plen); - ma = ipv6_addr_bitand(a, &mask); - mb = ipv6_addr_bitand(b, &mask); - - return ipv6_addr_equals(&ma, &mb); -} - /* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst', * 'eth_src' and 'eth_type' parameters. A payload of 'size' bytes is allocated * in 'b' and returned. This payload may be populated with appropriate diff --git a/lib/packets.h b/lib/packets.h index ea0bda840..7d91ae90e 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -22,16 +22,13 @@ #include <stdint.h> #include <string.h> #include "compiler.h" +#include "netaddr.h" #include "openvswitch/geneve.h" #include "openvswitch/packets.h" -#include "openvswitch/types.h" #include "openvswitch/nsh.h" #include "odp-netlink.h" -#include "random.h" #include "hash.h" #include "tun-metadata.h" -#include "unaligned.h" -#include "util.h" #include "timeval.h" struct dp_packet; @@ -44,8 +41,6 @@ struct ds; /* Tunnel information is in userspace datapath format. */ #define FLOW_TNL_F_UDPIF (1 << 4) -static inline bool ipv6_addr_is_set(const struct in6_addr *addr); - static inline bool flow_tnl_dst_is_set(const struct flow_tnl *tnl) { @@ -202,149 +197,18 @@ pkt_metadata_prefetch_init(struct pkt_metadata *md) bool dpid_from_string(const char *s, uint64_t *dpidp); -#define ETH_ADDR_LEN 6 - -static const struct eth_addr eth_addr_broadcast OVS_UNUSED - = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); - -static const struct eth_addr eth_addr_exact OVS_UNUSED - = ETH_ADDR_C(ff,ff,ff,ff,ff,ff); - -static const struct eth_addr eth_addr_zero OVS_UNUSED - = ETH_ADDR_C(00,00,00,00,00,00); -static const struct eth_addr64 eth_addr64_zero OVS_UNUSED - = ETH_ADDR64_C(00,00,00,00,00,00,00,00); - -static const struct eth_addr eth_addr_stp OVS_UNUSED - = ETH_ADDR_C(01,80,c2,00,00,00); - -static const struct eth_addr eth_addr_lacp OVS_UNUSED - = ETH_ADDR_C(01,80,c2,00,00,02); - -static const struct eth_addr eth_addr_bfd OVS_UNUSED - = ETH_ADDR_C(00,23,20,00,00,01); - -static inline bool eth_addr_is_broadcast(const struct eth_addr a) -{ - return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); -} - -static inline bool eth_addr_is_multicast(const struct eth_addr a) -{ - return a.ea[0] & 1; -} - -static inline bool eth_addr_is_local(const struct eth_addr a) -{ - /* Local if it is either a locally administered address or a Nicira random - * address. */ - return a.ea[0] & 2 - || (a.be16[0] == htons(0x0023) - && (a.be16[1] & htons(0xff80)) == htons(0x2080)); -} -static inline bool eth_addr_is_zero(const struct eth_addr a) -{ - return !(a.be16[0] | a.be16[1] | a.be16[2]); -} -static inline bool eth_addr64_is_zero(const struct eth_addr64 a) -{ - return !(a.be16[0] | a.be16[1] | a.be16[2] | a.be16[3]); -} - -static inline int eth_mask_is_exact(const struct eth_addr a) -{ - return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff); -} - -static inline int eth_addr_compare_3way(const struct eth_addr a, - const struct eth_addr b) -{ - return memcmp(&a, &b, sizeof a); -} -static inline int eth_addr64_compare_3way(const struct eth_addr64 a, - const struct eth_addr64 b) -{ - return memcmp(&a, &b, sizeof a); -} - -static inline bool eth_addr_equals(const struct eth_addr a, - const struct eth_addr b) -{ - return !eth_addr_compare_3way(a, b); -} -static inline bool eth_addr64_equals(const struct eth_addr64 a, - const struct eth_addr64 b) -{ - return !eth_addr64_compare_3way(a, b); -} - -static inline bool eth_addr_equal_except(const struct eth_addr a, - const struct eth_addr b, - const struct eth_addr mask) -{ - return !(((a.be16[0] ^ b.be16[0]) & mask.be16[0]) - || ((a.be16[1] ^ b.be16[1]) & mask.be16[1]) - || ((a.be16[2] ^ b.be16[2]) & mask.be16[2])); -} - -uint64_t eth_addr_to_uint64(const struct eth_addr ea); - -static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea, - uint16_t vlan) -{ - return (((uint64_t)vlan << 48) | eth_addr_to_uint64(ea)); -} - -void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea); - -static inline struct eth_addr eth_addr_invert(const struct eth_addr src) -{ - struct eth_addr dst; - - for (int i = 0; i < ARRAY_SIZE(src.be16); i++) { - dst.be16[i] = ~src.be16[i]; - } - - return dst; -} - -void eth_addr_mark_random(struct eth_addr *ea); - -static inline void eth_addr_random(struct eth_addr *ea) -{ - random_bytes((uint8_t *)ea, sizeof *ea); - eth_addr_mark_random(ea); -} - -static inline void eth_addr_nicira_random(struct eth_addr *ea) -{ - eth_addr_random(ea); - - /* Set the OUI to the Nicira one. */ - ea->ea[0] = 0x00; - ea->ea[1] = 0x23; - ea->ea[2] = 0x20; - - /* Set the top bit to indicate random Nicira address. */ - ea->ea[3] |= 0x80; -} static inline uint32_t hash_mac(const struct eth_addr ea, const uint16_t vlan, const uint32_t basis) { return hash_uint64_basis(eth_addr_vlan_to_uint64(ea, vlan), basis); } -bool eth_addr_is_reserved(const struct eth_addr); -bool eth_addr_from_string(const char *, struct eth_addr *); - void compose_rarp(struct dp_packet *, const struct eth_addr); void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci); void eth_pop_vlan(struct dp_packet *); const char *eth_from_hex(const char *hex, struct dp_packet **packetp); -void eth_format_masked(const struct eth_addr ea, - const struct eth_addr *mask, struct ds *s); void set_mpls_lse(struct dp_packet *, ovs_be32 label); void push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse); @@ -359,51 +223,6 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse, bool l3_encap); -/* Example: - * - * struct eth_addr mac; - * [...] - * printf("The Ethernet address is "ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(mac)); - * - */ -#define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 -#define ETH_ADDR_ARGS(EA) ETH_ADDR_BYTES_ARGS((EA).ea) -#define ETH_ADDR_BYTES_ARGS(EAB) \ - (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], (EAB)[4], (EAB)[5] -#define ETH_ADDR_STRLEN 17 - -/* Example: - * - * struct eth_addr64 eui64; - * [...] - * printf("The EUI-64 address is "ETH_ADDR64_FMT"\n", ETH_ADDR64_ARGS(mac)); - * - */ -#define ETH_ADDR64_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":" \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 -#define ETH_ADDR64_ARGS(EA) ETH_ADDR64_BYTES_ARGS((EA).ea64) -#define ETH_ADDR64_BYTES_ARGS(EAB) \ - (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], \ - (EAB)[4], (EAB)[5], (EAB)[6], (EAB)[7] -#define ETH_ADDR64_STRLEN 23 - -/* Example: - * - * char *string = "1 00:11:22:33:44:55 2"; - * struct eth_addr mac; - * int a, b; - * - * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d", - * &a, ETH_ADDR_SCAN_ARGS(mac), &b)) { - * ... - * } - */ -#define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8 -#define ETH_ADDR_SCAN_ARGS(EA) \ - &(EA).ea[0], &(EA).ea[1], &(EA).ea[2], &(EA).ea[3], &(EA).ea[4], &(EA).ea[5] - #define ETH_TYPE_IP 0x0800 #define ETH_TYPE_ARP 0x0806 #define ETH_TYPE_TEB 0x6558 @@ -625,71 +444,6 @@ mpls_lse_to_bos(ovs_be32 mpls_lse) return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0; } -#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32 -#define IP_ARGS(ip) \ - ntohl(ip) >> 24, \ - (ntohl(ip) >> 16) & 0xff, \ - (ntohl(ip) >> 8) & 0xff, \ - ntohl(ip) & 0xff - -/* Example: - * - * char *string = "1 33.44.55.66 2"; - * ovs_be32 ip; - * int a, b; - * - * if (ovs_scan(string, "%d"IP_SCAN_FMT"%d", &a, IP_SCAN_ARGS(&ip), &b)) { - * ... - * } - */ -#define IP_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8 -#define IP_SCAN_ARGS(ip) \ - ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ - &((uint8_t *) ip)[1], \ - &((uint8_t *) ip)[2], \ - &((uint8_t *) ip)[3] - -#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16 -#define IP_PORT_SCAN_ARGS(ip, port) \ - ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]), \ - &((uint8_t *) ip)[1], \ - &((uint8_t *) ip)[2], \ - &((uint8_t *) ip)[3], \ - ((void) (ovs_be16) *(port), (uint16_t *) port) - -/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N - * high-order 1-bits and 32-N low-order 0-bits. */ -static inline bool -ip_is_cidr(ovs_be32 netmask) -{ - uint32_t x = ~ntohl(netmask); - return !(x & (x + 1)); -} -static inline bool -ip_is_multicast(ovs_be32 ip) -{ - return (ip & htonl(0xf0000000)) == htonl(0xe0000000); -} -static inline bool -ip_is_local_multicast(ovs_be32 ip) -{ - return (ip & htonl(0xffffff00)) == htonl(0xe0000000); -} -int ip_count_cidr_bits(ovs_be32 netmask); -void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *); -bool ip_parse(const char *s, ovs_be32 *ip); -char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) - OVS_WARN_UNUSED_RESULT; -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) #define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl)) @@ -973,15 +727,6 @@ BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct arp_eth_header)); #define IPV6_HEADER_LEN 40 -/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on - * most implementations, this one only requires 16-bit alignment. */ -union ovs_16aligned_in6_addr { - ovs_be16 be16[8]; - ovs_16aligned_be32 be32[4]; -}; -BUILD_ASSERT_DECL(sizeof(union ovs_16aligned_in6_addr) - == sizeof(struct in6_addr)); - /* Like struct ip6_hdr, but whereas that struct requires 32-bit alignment, this * one only requires 16-bit alignment. */ struct ovs_16aligned_ip6_hdr { @@ -1148,110 +893,6 @@ BUILD_ASSERT_DECL(MLD2_RECORD_LEN == sizeof(struct mld2_record)); /* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */ #define IPV6_LABEL_MASK 0x000fffff -/* Example: - * - * char *string = "1 ::1 2"; - * char ipv6_s[IPV6_SCAN_LEN + 1]; - * struct in6_addr ipv6; - * - * if (ovs_scan(string, "%d"IPV6_SCAN_FMT"%d", &a, ipv6_s, &b) - * && inet_pton(AF_INET6, ipv6_s, &ipv6) == 1) { - * ... - * } - */ -#define IPV6_SCAN_FMT "%46[0123456789abcdefABCDEF:.]" -#define IPV6_SCAN_LEN 46 - -extern const struct in6_addr in6addr_exact; -#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } } - -extern const struct in6_addr in6addr_all_hosts; -#define IN6ADDR_ALL_HOSTS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } } - -extern const struct in6_addr in6addr_all_routers; -#define IN6ADDR_ALL_ROUTERS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } } - -extern const struct in6_addr in6addr_v4mapped_any; -#define IN6ADDR_V4MAPPED_ANY_INIT \ - { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } } - -static inline bool ipv6_addr_equals(const struct in6_addr *a, - const struct in6_addr *b) -{ -#ifdef IN6_ARE_ADDR_EQUAL - return IN6_ARE_ADDR_EQUAL(a, b); -#else - return !memcmp(a, b, sizeof(*a)); -#endif -} - -/* Checks the IPv6 address in 'mask' for all zeroes. */ -static inline bool ipv6_mask_is_any(const struct in6_addr *mask) { - return ipv6_addr_equals(mask, &in6addr_any); -} - -static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) { - return ipv6_addr_equals(mask, &in6addr_exact); -} - -static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) { - return ipv6_addr_equals(addr, &in6addr_all_hosts); -} - -static inline bool ipv6_addr_is_set(const struct in6_addr *addr) { - return !ipv6_addr_equals(addr, &in6addr_any); -} - -static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) { - return ip->s6_addr[0] == 0xff; -} - -static inline struct in6_addr -in6_addr_mapped_ipv4(ovs_be32 ip4) -{ - struct in6_addr ip6; - memset(&ip6, 0, sizeof(ip6)); - ip6.s6_addr[10] = 0xff, ip6.s6_addr[11] = 0xff; - memcpy(&ip6.s6_addr[12], &ip4, 4); - return ip6; -} - -static inline void -in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4) -{ - *ip6 = in6_addr_mapped_ipv4(ip4); -} - -static inline ovs_be32 -in6_addr_get_mapped_ipv4(const struct in6_addr *addr) -{ - union ovs_16aligned_in6_addr *taddr = - (union ovs_16aligned_in6_addr *) addr; - if (IN6_IS_ADDR_V4MAPPED(addr)) { - return get_16aligned_be32(&taddr->be32[3]); - } else { - return INADDR_ANY; - } -} - -void in6_addr_solicited_node(struct in6_addr *addr, - const struct in6_addr *ip6); - -void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, - struct in6_addr *lla); - -void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla); - -/* Returns true if 'addr' is a link local address. Otherwise, false. */ -bool in6_is_lla(struct in6_addr *addr); - -void ipv6_multicast_to_ethernet(struct eth_addr *eth, - const struct in6_addr *ip6); - static inline bool dl_type_is_ip_any(ovs_be16 dl_type) { return dl_type == htons(ETH_TYPE_IP) @@ -1598,35 +1239,6 @@ enum packet_type { }; -void ipv6_format_addr(const struct in6_addr *addr, struct ds *); -void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *, - bool bracket); -void ipv6_format_mapped(const struct in6_addr *addr, struct ds *); -void ipv6_format_masked(const struct in6_addr *addr, - const struct in6_addr *mask, struct ds *); -const char * ipv6_string_mapped(char *addr_str, const struct in6_addr *addr); -struct in6_addr ipv6_addr_bitand(const struct in6_addr *src, - const struct in6_addr *mask); -struct in6_addr ipv6_addr_bitxor(const struct in6_addr *a, - const struct in6_addr *b); -bool ipv6_is_zero(const struct in6_addr *a); -struct in6_addr ipv6_create_mask(int mask); -int ipv6_count_cidr_bits(const struct in6_addr *netmask); -bool ipv6_is_cidr(const struct in6_addr *netmask); -bool ipv6_addr_equals_masked(const struct in6_addr *a, - const struct in6_addr *b, int plen); - -bool ipv6_parse(const char *s, struct in6_addr *ip); -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, size_t size); diff --git a/lib/smap.c b/lib/smap.c index 248a8ee1e..8543179fc 100644 --- a/lib/smap.c +++ b/lib/smap.c @@ -19,7 +19,7 @@ #include "hash.h" #include "openvswitch/json.h" -#include "packets.h" +#include "netaddr.h" #include "util.h" #include "uuid.h" diff --git a/lib/socket-util.c b/lib/socket-util.c index 6afd01ed6..6d183a6ba 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -37,7 +37,7 @@ #include <unistd.h> #include "openvswitch/dynamic-string.h" #include "ovs-thread.h" -#include "packets.h" +#include "netaddr.h" #include "openvswitch/poll-loop.h" #include "util.h" #include "openvswitch/vlog.h" diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c index 4a35a9525..c39beaac3 100644 --- a/lib/stream-ssl.c +++ b/lib/stream-ssl.c @@ -38,7 +38,7 @@ #include "entropy.h" #include "openvswitch/ofpbuf.h" #include "openflow/openflow.h" -#include "packets.h" +#include "netaddr.h" #include "openvswitch/poll-loop.h" #include "openvswitch/shash.h" #include "socket-util.h" diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c index e8dc2bfaa..fa85c6788 100644 --- a/lib/stream-tcp.c +++ b/lib/stream-tcp.c @@ -26,7 +26,7 @@ #include <sys/socket.h> #include <unistd.h> #include "openvswitch/dynamic-string.h" -#include "packets.h" +#include "netaddr.h" #include "socket-util.h" #include "util.h" #include "stream-provider.h" diff --git a/lib/stream-unix.c b/lib/stream-unix.c index 0d9342bc6..4c71f3825 100644 --- a/lib/stream-unix.c +++ b/lib/stream-unix.c @@ -27,7 +27,7 @@ #include <string.h> #include <unistd.h> #include "ovs-atomic.h" -#include "packets.h" +#include "netaddr.h" #include "openvswitch/poll-loop.h" #include "socket-util.h" #include "dirs.h" diff --git a/lib/stream.c b/lib/stream.c index 0d7e5261c..213d214c2 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -25,7 +25,6 @@ #include <string.h> #include "coverage.h" #include "fatal-signal.h" -#include "flow.h" #include "jsonrpc.h" #include "openflow/nicira-ext.h" #include "openflow/openflow.h" @@ -35,10 +34,10 @@ #include "openvswitch/vlog.h" #include "ovs-replay.h" #include "ovs-thread.h" -#include "packets.h" #include "openvswitch/poll-loop.h" #include "random.h" #include "socket-util.h" +#include "timeval.h" #include "util.h" VLOG_DEFINE_THIS_MODULE(stream); -- 2.56.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
