#include "byte-order.h"
#include "csum.h"
#include "flow.h"
+#include "hmap.h"
#include "dynamic-string.h"
#include "ofpbuf.h"
return *dpidp != 0;
}
-/* Returns true if 'ea' is a reserved multicast address, that a bridge must
- * never forward, false otherwise. Includes some proprietary vendor protocols
- * that shouldn't be forwarded as well.
+/* 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 uint8_t ea[ETH_ADDR_LEN])
{
- struct masked_eth_addr {
- uint8_t ea[ETH_ADDR_LEN];
- uint8_t mask[ETH_ADDR_LEN];
+ struct eth_addr_node {
+ struct hmap_node hmap_node;
+ uint64_t ea64;
};
- static struct masked_eth_addr mea[] = {
- { /* STP, IEEE pause frames, and other reserved protocols. */
- {0x01, 0x08, 0xc2, 0x00, 0x00, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}},
-
- { /* VRRP IPv4. */
- {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0x00}},
-
- { /* VRRP IPv6. */
- {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0x00}},
-
- { /* HSRPv1. */
- {0x00, 0x00, 0x0c, 0x07, 0xac, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0x00}},
-
- { /* HSRPv2. */
- {0x00, 0x00, 0x0c, 0x9f, 0xf0, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xf0, 0x00}},
-
- { /* GLBP. */
- {0x00, 0x07, 0xb4, 0x00, 0x00, 0x00},
- {0xff, 0xff, 0xff, 0x00, 0x00, 0x00}},
-
- { /* Extreme Discovery Protocol. */
- {0x00, 0xE0, 0x2B, 0x00, 0x00, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xf0, 0x00}},
-
- { /* Cisco Inter Switch Link. */
- {0x01, 0x00, 0x0c, 0x00, 0x00, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ static struct eth_addr_node nodes[] = {
+ /* STP, IEEE pause frames, and other reserved protocols. */
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000000ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000001ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000002ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000003ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000004ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000005ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000006ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000007ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000008ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000009ULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000aULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000bULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000cULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000dULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000eULL },
+ { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000fULL },
+
+ /* 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 },
+ };
- { /* Cisco protocols plus others following the same pattern:
- *
- * CDP, VTP, DTP, PAgP (01-00-0c-cc-cc-cc)
- * Spanning Tree PVSTP+ (01-00-0c-cc-cc-cd)
- * STP Uplink Fast (01-00-0c-cd-cd-cd) */
- {0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc},
- {0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe}}};
+ static struct hmap addrs = HMAP_INITIALIZER(&addrs);
+ struct eth_addr_node *node;
+ uint64_t ea64;
- size_t i;
+ if (hmap_is_empty(&addrs)) {
+ for (node = nodes; node < &nodes[ARRAY_SIZE(nodes)]; node++) {
+ hmap_insert(&addrs, &node->hmap_node,
+ hash_2words(node->ea64, node->ea64 >> 32));
+ }
+ }
- for (i = 0; i < ARRAY_SIZE(mea); i++) {
- if (eth_addr_equal_except(ea, mea[i].ea, mea[i].mask)) {
+ ea64 = eth_addr_to_uint64(ea);
+ HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_2words(ea64, ea64 >> 32),
+ &addrs) {
+ if (node->ea64 == ea64) {
return true;
}
}
compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN])
{
struct eth_header *eth;
- struct rarp_header *rarp;
+ struct arp_eth_header *arp;
ofpbuf_clear(b);
ofpbuf_prealloc_tailroom(b, ETH_HEADER_LEN + VLAN_HEADER_LEN
- + RARP_HEADER_LEN);
+ + ARP_ETH_HEADER_LEN);
ofpbuf_reserve(b, VLAN_HEADER_LEN);
eth = ofpbuf_put_uninit(b, sizeof *eth);
memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN);
memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
eth->eth_type = htons(ETH_TYPE_RARP);
- rarp = ofpbuf_put_uninit(b, sizeof *rarp);
- rarp->hw_addr_space = htons(ARP_HTYPE_ETH);
- rarp->proto_addr_space = htons(ETH_TYPE_IP);
- rarp->hw_addr_length = ETH_ADDR_LEN;
- rarp->proto_addr_length = sizeof rarp->src_proto_addr;
- rarp->opcode = htons(RARP_REQUEST_REVERSE);
- memcpy(rarp->src_hw_addr, eth_src, ETH_ADDR_LEN);
- rarp->src_proto_addr = htonl(0);
- memcpy(rarp->target_hw_addr, eth_src, ETH_ADDR_LEN);
- rarp->target_proto_addr = htonl(0);
+ arp = ofpbuf_put_uninit(b, sizeof *arp);
+ arp->ar_hrd = htons(ARP_HRD_ETHERNET);
+ arp->ar_pro = htons(ARP_PRO_IP);
+ arp->ar_hln = sizeof arp->ar_sha;
+ arp->ar_pln = sizeof arp->ar_spa;
+ arp->ar_op = htons(ARP_OP_RARP);
+ memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN);
+ arp->ar_spa = htonl(0);
+ memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN);
+ arp->ar_tpa = htonl(0);
}
/* Insert VLAN header according to given TCI. Packet passed must be Ethernet
}
/* 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'. 'netmask'
- * must be a CIDR netmask (see ip_is_cidr()). */
+ * 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)
{
- assert(ip_is_cidr(netmask));
return 32 - ctz(ntohl(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()). */
+ * '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 count = 0;
const uint8_t *netmaskp = &netmask->s6_addr[0];
- assert(ipv6_is_cidr(netmask));
-
for (i=0; i<16; i++) {
if (netmaskp[i] == 0xff) {
count += 8;