ofp-print: Do not display flow mod cookie if it is UINT64_MAX
[openvswitch] / lib / packets.c
index bbf4934401b52c75ace8ac51d1f0865828333e94..16f4fe63afe254f93e2678c4771013c9b7ac3566 100644 (file)
@@ -24,6 +24,7 @@
 #include "byte-order.h"
 #include "csum.h"
 #include "flow.h"
+#include "hmap.h"
 #include "dynamic-string.h"
 #include "ofpbuf.h"
 
@@ -43,65 +44,77 @@ dpid_from_string(const char *s, uint64_t *dpidp)
     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;
         }
     }
@@ -130,27 +143,27 @@ void
 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
@@ -246,12 +259,13 @@ eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
 }
 
 /* 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));
 }
 
@@ -349,7 +363,10 @@ ipv6_create_mask(int mask)
 
 /* 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)
 {
@@ -357,8 +374,6 @@ 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;