/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2008, 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.
#include <inttypes.h>
#include <sys/types.h>
-#include <netinet/in.h>
#include <stdint.h>
#include <string.h>
#include "compiler.h"
-#include "geneve.h"
+#include "openvswitch/geneve.h"
+#include "openvswitch/packets.h"
#include "openvswitch/types.h"
#include "odp-netlink.h"
#include "random.h"
struct dp_packet;
struct ds;
-/* Tunnel information used in flow key and metadata. */
-struct flow_tnl {
- ovs_be32 ip_dst;
- ovs_be32 ip_src;
- ovs_be64 tun_id;
- uint16_t flags;
- uint8_t ip_tos;
- uint8_t ip_ttl;
- ovs_be16 tp_src;
- ovs_be16 tp_dst;
- ovs_be16 gbp_id;
- uint8_t gbp_flags;
- uint8_t pad1[5]; /* Pad to 64 bits. */
- struct tun_metadata metadata;
-};
-
-/* Some flags are exposed through OpenFlow while others are used only
- * internally. */
-
-/* Public flags */
-#define FLOW_TNL_F_OAM (1 << 0)
-
-#define FLOW_TNL_PUB_F_MASK ((1 << 1) - 1)
-
-/* Private flags */
-#define FLOW_TNL_F_DONT_FRAGMENT (1 << 1)
-#define FLOW_TNL_F_CSUM (1 << 2)
-#define FLOW_TNL_F_KEY (1 << 3)
-
-#define FLOW_TNL_F_MASK ((1 << 4) - 1)
-
/* Purely internal to OVS userspace. These flags should never be exposed to
* the outside world and so aren't included in the flags mask. */
/* 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)
+{
+ return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst);
+}
+
+struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl);
+struct in6_addr flow_tnl_src(const struct flow_tnl *tnl);
+
/* Returns an offset to 'src' covering all the meaningful fields in 'src'. */
static inline size_t
flow_tnl_size(const struct flow_tnl *src)
{
- if (!src->ip_dst) {
- /* Covers ip_dst only. */
+ if (!flow_tnl_dst_is_set(src)) {
+ /* Covers ip_dst and ipv6_dst only. */
return offsetof(struct flow_tnl, ip_src);
}
if (src->flags & FLOW_TNL_F_UDPIF) {
return a_size == flow_tnl_size(b) && !memcmp(a, b, a_size);
}
-/* Unfortunately, a "struct flow" sometimes has to handle OpenFlow port
- * numbers and other times datapath (dpif) port numbers. This union allows
- * access to both. */
-union flow_in_port {
- odp_port_t odp_port;
- ofp_port_t ofp_port;
-};
-
/* Datapath packet metadata */
struct pkt_metadata {
uint32_t recirc_id; /* Recirculation id carried with the
* be uninitialized. */
};
+static inline void
+pkt_metadata_init_tnl(struct pkt_metadata *md)
+{
+ /* Zero up through the tunnel metadata options. The length and table
+ * are before this and as long as they are empty, the options won't
+ * be looked at. */
+ memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts));
+}
+
static inline void
pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
{
* looked at. */
memset(md, 0, offsetof(struct pkt_metadata, in_port));
md->tunnel.ip_dst = 0;
+ md->tunnel.ipv6_dst = in6addr_any;
md->in_port.odp_port = port;
}
+/* This function prefetches the cachelines touched by pkt_metadata_init()
+ * For performance reasons the two functions should be kept in sync. */
+static inline void
+pkt_metadata_prefetch_init(struct pkt_metadata *md)
+{
+ ovs_prefetch_range(md, offsetof(struct pkt_metadata, tunnel.ip_src));
+}
+
bool dpid_from_string(const char *s, uint64_t *dpidp);
#define ETH_ADDR_LEN 6
#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:
*
&((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
}
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_ECN_MASK 0x03
#define IP_DSCP_MASK 0xfc
+static inline int
+IP_ECN_is_ce(uint8_t dsfield)
+{
+ return (dsfield & IP_ECN_MASK) == IP_ECN_CE;
+}
+
#define IP_VERSION 4
#define IP_DONT_FRAGMENT 0x4000 /* Don't fragment. */
ovs_16aligned_be32 ip_src;
ovs_16aligned_be32 ip_dst;
};
-
BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header));
+/* ICMPv4 types. */
+#define ICMP4_ECHO_REPLY 0
+#define ICMP4_DST_UNREACH 3
+#define ICMP4_SOURCEQUENCH 4
+#define ICMP4_REDIRECT 5
+#define ICMP4_ECHO_REQUEST 8
+#define ICMP4_TIME_EXCEEDED 11
+#define ICMP4_PARAM_PROB 12
+#define ICMP4_TIMESTAMP 13
+#define ICMP4_TIMESTAMPREPLY 14
+#define ICMP4_INFOREQUEST 15
+#define ICMP4_INFOREPLY 16
+
#define ICMP_HEADER_LEN 8
struct icmp_header {
uint8_t icmp_type;
BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header));
/* Connection states */
-#define CS_NEW 0x01
-#define CS_ESTABLISHED 0x02
-#define CS_RELATED 0x04
-#define CS_INVALID 0x20
-#define CS_REPLY_DIR 0x40
-#define CS_TRACKED 0x80
+enum {
+ CS_NEW_BIT = 0,
+ CS_ESTABLISHED_BIT = 1,
+ CS_RELATED_BIT = 2,
+ CS_REPLY_DIR_BIT = 3,
+ CS_INVALID_BIT = 4,
+ CS_TRACKED_BIT = 5,
+ CS_SRC_NAT_BIT = 6,
+ CS_DST_NAT_BIT = 7,
+};
+
+enum {
+ CS_NEW = (1 << CS_NEW_BIT),
+ CS_ESTABLISHED = (1 << CS_ESTABLISHED_BIT),
+ CS_RELATED = (1 << CS_RELATED_BIT),
+ CS_REPLY_DIR = (1 << CS_REPLY_DIR_BIT),
+ CS_INVALID = (1 << CS_INVALID_BIT),
+ CS_TRACKED = (1 << CS_TRACKED_BIT),
+ CS_SRC_NAT = (1 << CS_SRC_NAT_BIT),
+ CS_DST_NAT = (1 << CS_DST_NAT_BIT),
+};
/* Undefined connection state bits. */
#define CS_SUPPORTED_MASK (CS_NEW | CS_ESTABLISHED | CS_RELATED \
- | CS_INVALID | CS_REPLY_DIR | CS_TRACKED)
+ | CS_INVALID | CS_REPLY_DIR | CS_TRACKED \
+ | CS_SRC_NAT | CS_DST_NAT)
#define CS_UNSUPPORTED_MASK (~(uint32_t)CS_SUPPORTED_MASK)
#define ARP_HRD_ETHERNET 1
};
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 {
};
BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
+uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *);
+
/* Neighbor Discovery option field.
* ND options are always a multiple of 8 bytes in size. */
#define ND_OPT_LEN 8
#define ND_MSG_LEN 24
struct ovs_nd_msg {
struct icmp6_header icmph;
- ovs_16aligned_be32 rco_flags;
+ ovs_16aligned_be32 rso_flags;
union ovs_16aligned_in6_addr target;
struct ovs_nd_opt options[0];
};
BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg));
+#define ND_RSO_ROUTER 0x80000000
+#define ND_RSO_SOLICITED 0x40000000
+#define ND_RSO_OVERRIDE 0x20000000
+
/*
* Use the same struct for MLD and MLD2, naming members as the defined fields in
* in the corresponding version of the protocol, though they are reserved in the
#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);
}
return ip->s6_addr[0] == 0xff;
}
+static inline struct in6_addr
+in6_addr_mapped_ipv4(ovs_be32 ip4)
+{
+ struct in6_addr ip6 = { .s6_addr = { [10] = 0xff, [11] = 0xff } };
+ memcpy(&ip6.s6_addr[12], &ip4, 4);
+ return ip6;
+}
+
static inline void
-in6_addr_set_mapped_ipv4(struct in6_addr *addr, ovs_be32 ip4)
+in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4)
{
- union ovs_16aligned_in6_addr *taddr = (void *) addr;
- memset(taddr->be16, 0, sizeof(taddr->be16));
- taddr->be16[5] = OVS_BE16_MAX;
- put_16aligned_be32(&taddr->be32[3], ip4);
+ *ip6 = in6_addr_mapped_ipv4(ip4);
}
static inline ovs_be32
}
}
+static inline void
+in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6)
+{
+ union ovs_16aligned_in6_addr *taddr = (void *) 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 link local address from the given eth addr
+ * with prefix 'fe80::/64' and stores it in 'lla'
+ */
+static inline void
+in6_generate_lla(struct eth_addr ea, struct in6_addr *lla)
+{
+ union ovs_16aligned_in6_addr *taddr = (void *) 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. */
+static inline 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
+}
+
+static inline 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];
+}
+
static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
{
return dl_type == htons(ETH_TYPE_IP)
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
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_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,
unsigned int oui, uint16_t snap_type, size_t size);
void packet_set_ipv4(struct dp_packet *, ovs_be32 src, ovs_be32 dst, uint8_t tos,
uint8_t ttl);
-void packet_set_ipv6(struct dp_packet *, uint8_t proto, const ovs_be32 src[4],
+void packet_set_ipv6(struct dp_packet *, const ovs_be32 src[4],
const ovs_be32 dst[4], uint8_t tc,
ovs_be32 fl, uint8_t hlmit);
void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
void packet_format_tcp_flags(struct ds *, uint16_t);
const char *packet_tcp_flag_to_string(uint32_t flag);
+void compose_arp__(struct dp_packet *);
void compose_arp(struct dp_packet *, uint16_t arp_op,
const struct eth_addr arp_sha,
const struct eth_addr arp_tha, bool broadcast,
ovs_be32 arp_spa, ovs_be32 arp_tpa);
+void compose_nd_ns(struct dp_packet *, const struct eth_addr eth_src,
+ const struct in6_addr *ipv6_src,
+ const struct in6_addr *ipv6_dst);
+void compose_nd_na(struct dp_packet *, const struct eth_addr eth_src,
+ const struct eth_addr eth_dst,
+ const struct in6_addr *ipv6_src,
+ const struct in6_addr *ipv6_dst,
+ ovs_be32 rso_flags);
uint32_t packet_csum_pseudoheader(const struct ip_header *);
+void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6);
#endif /* packets.h */