Support matching IPv6 flow label.
[sliver-openvswitch.git] / lib / packets.h
index 5112110..d924492 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,7 +38,10 @@ static const uint8_t eth_addr_broadcast[ETH_ADDR_LEN] OVS_UNUSED
     = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 static const uint8_t eth_addr_stp[ETH_ADDR_LEN] OVS_UNUSED
-    = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 };
+    = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 };
+
+static const uint8_t eth_addr_lacp[ETH_ADDR_LEN] OVS_UNUSED
+    = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 };
 
 static inline bool eth_addr_is_broadcast(const uint8_t ea[6])
 {
@@ -53,17 +56,22 @@ static inline bool eth_addr_is_local(const uint8_t ea[6])
 {
     /* Local if it is either a locally administered address or a Nicira random
      * address. */
-    return !!(ea[0] & 2)
-       || (ea[0] == 0x00 && ea[1] == 0x23 && ea[2] == 0x20 && !!(ea[3] & 0x80));
+    return ea[0] & 2
+       || (ea[0] == 0x00 && ea[1] == 0x23 && ea[2] == 0x20 && ea[3] & 0x80);
 }
 static inline bool eth_addr_is_zero(const uint8_t ea[6])
 {
     return !(ea[0] | ea[1] | ea[2] | ea[3] | ea[4] | ea[5]);
 }
+static inline int eth_addr_compare_3way(const uint8_t a[ETH_ADDR_LEN],
+                                        const uint8_t b[ETH_ADDR_LEN])
+{
+    return memcmp(a, b, ETH_ADDR_LEN);
+}
 static inline bool eth_addr_equals(const uint8_t a[ETH_ADDR_LEN],
                                    const uint8_t b[ETH_ADDR_LEN])
 {
-    return !memcmp(a, b, ETH_ADDR_LEN);
+    return !eth_addr_compare_3way(a, b);
 }
 static inline uint64_t eth_addr_to_uint64(const uint8_t ea[ETH_ADDR_LEN])
 {
@@ -123,6 +131,8 @@ void compose_benign_packet(struct ofpbuf *, const char *tag,
                            uint16_t snap_type,
                            const uint8_t eth_src[ETH_ADDR_LEN]);
 
+void eth_push_vlan(struct ofpbuf *, ovs_be16 tci);
+
 /* Example:
  *
  * uint8_t mac[ETH_ADDR_LEN];
@@ -155,7 +165,7 @@ void compose_benign_packet(struct ofpbuf *, const char *tag,
 #define ETH_TYPE_ARP           0x0806
 #define ETH_TYPE_VLAN          0x8100
 #define ETH_TYPE_IPV6          0x86dd
-#define ETH_TYPE_CFM           0x8902
+#define ETH_TYPE_LACP          0x8809
 
 /* Minimum value for an Ethernet type.  Values below this are IEEE 802.2 frame
  * lengths. */
@@ -170,7 +180,7 @@ void compose_benign_packet(struct ofpbuf *, const char *tag,
 struct eth_header {
     uint8_t eth_dst[ETH_ADDR_LEN];
     uint8_t eth_src[ETH_ADDR_LEN];
-    uint16_t eth_type;
+    ovs_be16 eth_type;
 } __attribute__((packed));
 BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header));
 
@@ -191,7 +201,7 @@ BUILD_ASSERT_DECL(LLC_HEADER_LEN == sizeof(struct llc_header));
 #define SNAP_HEADER_LEN 5
 struct snap_header {
     uint8_t snap_org[3];
-    uint16_t snap_type;
+    ovs_be16 snap_type;
 } __attribute__((packed));
 BUILD_ASSERT_DECL(SNAP_HEADER_LEN == sizeof(struct snap_header));
 
@@ -213,7 +223,7 @@ BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header));
 /* Given the vlan_tci field from an 802.1Q header, in network byte order,
  * returns the VLAN ID in host byte order. */
 static inline uint16_t
-vlan_tci_to_vid(uint16_t vlan_tci)
+vlan_tci_to_vid(ovs_be16 vlan_tci)
 {
     return (ntohs(vlan_tci) & VLAN_VID_MASK) >> VLAN_VID_SHIFT;
 }
@@ -221,15 +231,15 @@ vlan_tci_to_vid(uint16_t vlan_tci)
 /* Given the vlan_tci field from an 802.1Q header, in network byte order,
  * returns the priority code point (PCP) in host byte order. */
 static inline int
-vlan_tci_to_pcp(uint16_t vlan_tci)
+vlan_tci_to_pcp(ovs_be16 vlan_tci)
 {
     return (ntohs(vlan_tci) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT;
 }
 
 #define VLAN_HEADER_LEN 4
 struct vlan_header {
-    uint16_t vlan_tci;          /* Lowest 12 bits are VLAN ID. */
-    uint16_t vlan_next_type;
+    ovs_be16 vlan_tci;          /* Lowest 12 bits are VLAN ID. */
+    ovs_be16 vlan_next_type;
 };
 BUILD_ASSERT_DECL(VLAN_HEADER_LEN == sizeof(struct vlan_header));
 
@@ -237,29 +247,12 @@ BUILD_ASSERT_DECL(VLAN_HEADER_LEN == sizeof(struct vlan_header));
 struct vlan_eth_header {
     uint8_t veth_dst[ETH_ADDR_LEN];
     uint8_t veth_src[ETH_ADDR_LEN];
-    uint16_t veth_type;         /* Always htons(ETH_TYPE_VLAN). */
-    uint16_t veth_tci;          /* Lowest 12 bits are VLAN ID. */
-    uint16_t veth_next_type;
+    ovs_be16 veth_type;         /* Always htons(ETH_TYPE_VLAN). */
+    ovs_be16 veth_tci;          /* Lowest 12 bits are VLAN ID. */
+    ovs_be16 veth_next_type;
 } __attribute__((packed));
 BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
 
-/* A 'ccm' represents a Continuity Check Message from the 802.1ag specification.
- * Continuity Check Messages are broadcast periodically so that hosts can
- * determine who they have connectivity to. */
-#define CCM_LEN 74
-#define CCM_MAID_LEN 48
-struct ccm {
-    uint8_t  mdlevel_version; /* MD Level and Version */
-    uint8_t  opcode;
-    uint8_t  flags;
-    uint8_t  tlv_offset;
-    uint32_t seq;
-    uint16_t mpid;
-    uint8_t  maid[CCM_MAID_LEN];
-    uint8_t  zero[16]; /* Defined by ITU-T Y.1731 should be zero */
-} __attribute__((packed));
-BUILD_ASSERT_DECL(CCM_LEN == sizeof(struct ccm));
-
 /* The "(void) (ip)[0]" below has no effect on the value, since it's the first
  * argument of a comma expression, but it makes sure that 'ip' is a pointer.
  * This is useful since a common mistake is to pass an integer instead of a
@@ -271,6 +264,25 @@ BUILD_ASSERT_DECL(CCM_LEN == sizeof(struct ccm));
         ((uint8_t *) ip)[2],                    \
         ((uint8_t *) ip)[3]
 
+/* Example:
+ *
+ * char *string = "1 33.44.55.66 2";
+ * ovs_be32 ip;
+ * int a, b;
+ *
+ * if (sscanf(string, "%d"IP_SCAN_FMT"%d",
+ *     &a, IP_SCAN_ARGS(&ip), &b) == 1 + IP_SCAN_COUNT + 1) {
+ *     ...
+ * }
+ */
+#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_SCAN_COUNT 4
+
 /* 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
@@ -279,6 +291,13 @@ 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);
+}
+int ip_count_cidr_bits(ovs_be32 netmask);
+void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *);
 
 #define IP_VER(ip_ihl_ver) ((ip_ihl_ver) >> 4)
 #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
@@ -300,14 +319,14 @@ ip_is_cidr(ovs_be32 netmask)
 struct ip_header {
     uint8_t ip_ihl_ver;
     uint8_t ip_tos;
-    uint16_t ip_tot_len;
-    uint16_t ip_id;
-    uint16_t ip_frag_off;
+    ovs_be16 ip_tot_len;
+    ovs_be16 ip_id;
+    ovs_be16 ip_frag_off;
     uint8_t ip_ttl;
     uint8_t ip_proto;
-    uint16_t ip_csum;
-    uint32_t ip_src;
-    uint32_t ip_dst;
+    ovs_be16 ip_csum;
+    ovs_be32 ip_src;
+    ovs_be32 ip_dst;
 };
 BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header));
 
@@ -315,16 +334,16 @@ BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header));
 struct icmp_header {
     uint8_t icmp_type;
     uint8_t icmp_code;
-    uint16_t icmp_csum;
+    ovs_be16 icmp_csum;
 };
 BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
 
 #define UDP_HEADER_LEN 8
 struct udp_header {
-    uint16_t udp_src;
-    uint16_t udp_dst;
-    uint16_t udp_len;
-    uint16_t udp_csum;
+    ovs_be16 udp_src;
+    ovs_be16 udp_dst;
+    ovs_be16 udp_len;
+    ovs_be16 udp_csum;
 };
 BUILD_ASSERT_DECL(UDP_HEADER_LEN == sizeof(struct udp_header));
 
@@ -335,19 +354,19 @@ BUILD_ASSERT_DECL(UDP_HEADER_LEN == sizeof(struct udp_header));
 #define TCP_ACK 0x10
 #define TCP_URG 0x20
 
-#define TCP_FLAGS(tcp_ctl) (htons(tcp_ctl) & 0x003f)
-#define TCP_OFFSET(tcp_ctl) (htons(tcp_ctl) >> 12)
+#define TCP_FLAGS(tcp_ctl) (ntohs(tcp_ctl) & 0x003f)
+#define TCP_OFFSET(tcp_ctl) (ntohs(tcp_ctl) >> 12)
 
 #define TCP_HEADER_LEN 20
 struct tcp_header {
-    uint16_t tcp_src;
-    uint16_t tcp_dst;
-    uint32_t tcp_seq;
-    uint32_t tcp_ack;
-    uint16_t tcp_ctl;
-    uint16_t tcp_winsz;
-    uint16_t tcp_csum;
-    uint16_t tcp_urg;
+    ovs_be16 tcp_src;
+    ovs_be16 tcp_dst;
+    ovs_be32 tcp_seq;
+    ovs_be32 tcp_ack;
+    ovs_be16 tcp_ctl;
+    ovs_be16 tcp_winsz;
+    ovs_be16 tcp_csum;
+    ovs_be16 tcp_urg;
 };
 BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header));
 
@@ -359,20 +378,37 @@ BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header));
 #define ARP_ETH_HEADER_LEN 28
 struct arp_eth_header {
     /* Generic members. */
-    uint16_t ar_hrd;           /* Hardware type. */
-    uint16_t ar_pro;           /* Protocol type. */
+    ovs_be16 ar_hrd;           /* Hardware type. */
+    ovs_be16 ar_pro;           /* Protocol type. */
     uint8_t ar_hln;            /* Hardware address length. */
     uint8_t ar_pln;            /* Protocol address length. */
-    uint16_t ar_op;            /* Opcode. */
+    ovs_be16 ar_op;            /* Opcode. */
 
     /* Ethernet+IPv4 specific members. */
     uint8_t ar_sha[ETH_ADDR_LEN]; /* Sender hardware address. */
-    uint32_t ar_spa;           /* Sender protocol address. */
+    ovs_be32 ar_spa;           /* Sender protocol address. */
     uint8_t ar_tha[ETH_ADDR_LEN]; /* Target hardware address. */
-    uint32_t ar_tpa;           /* Target protocol address. */
+    ovs_be32 ar_tpa;           /* Target protocol address. */
 } __attribute__((packed));
 BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct arp_eth_header));
 
+/* 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 (sscanf(string, "%d"IPV6_SCAN_FMT"%d", &a, ipv6_s, &b) == 3
+ *     && 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 } } }
@@ -397,10 +433,19 @@ static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) {
 
 void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
 void print_ipv6_addr(struct ds *string, const struct in6_addr *addr);
+void print_ipv6_masked(struct ds *string, const struct in6_addr *addr,
+                       const struct in6_addr *mask);
 struct in6_addr ipv6_addr_bitand(const struct in6_addr *src,
                                  const struct in6_addr *mask);
 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);
 
+void *eth_compose(struct ofpbuf *, const uint8_t eth_dst[ETH_ADDR_LEN],
+                  const uint8_t eth_src[ETH_ADDR_LEN], uint16_t eth_type,
+                  size_t size);
+void *snap_compose(struct ofpbuf *, const uint8_t eth_dst[ETH_ADDR_LEN],
+                   const uint8_t eth_src[ETH_ADDR_LEN],
+                   unsigned int oui, uint16_t snap_type, size_t size);
+
 #endif /* packets.h */