#include "tun-metadata.h"
#include "unaligned.h"
#include "util.h"
+#include "timeval.h"
struct dp_packet;
+struct conn;
struct ds;
/* Purely internal to OVS userspace. These flags should never be exposed to
return tnl->ip_dst || ipv6_addr_is_set(&tnl->ipv6_dst);
}
+static inline bool
+flow_tnl_src_is_set(const struct flow_tnl *tnl)
+{
+ return tnl->ip_src || ipv6_addr_is_set(&tnl->ipv6_src);
+}
+
struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl);
struct in6_addr flow_tnl_src(const struct flow_tnl *tnl);
uint32_t ct_mark; /* Connection mark. */
ovs_u128 ct_label; /* Connection label. */
union flow_in_port in_port; /* Input port. */
+ struct conn *conn; /* Cached conntrack connection. */
+ bool reply; /* True if reply direction. */
+ bool icmp_related; /* True if ICMP related. */
);
PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1,
memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata.opts));
}
+static inline void
+pkt_metadata_init_conn(struct pkt_metadata *md)
+{
+ md->conn = NULL;
+}
+
static inline void
pkt_metadata_init(struct pkt_metadata *md, odp_port_t port)
{
md->tunnel.ip_dst = 0;
md->tunnel.ipv6_dst = in6addr_any;
md->in_port.odp_port = port;
+ md->conn = NULL;
}
/* This function prefetches the cachelines touched by pkt_metadata_init()
- * For performance reasons the two functions should be kept in sync. */
+ * and pkt_metadata_init_tnl(). For performance reasons the two functions
+ * should be kept in sync. */
static inline void
pkt_metadata_prefetch_init(struct pkt_metadata *md)
{
* be initialized later in pkt_metadata_init(). */
OVS_PREFETCH(md->cacheline0);
+ /* Prefetch cacheline1 as members of this cacheline will be zeroed out
+ * in pkt_metadata_init_tnl(). */
+ OVS_PREFETCH(md->cacheline1);
+
/* Prefetch cachline2 as ip_dst & ipv6_dst fields will be initialized. */
OVS_PREFETCH(md->cacheline2);
}
|| ((a.be16[2] ^ b.be16[2]) & mask.be16[2]));
}
-static inline 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]));
-}
+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));
}
-static inline 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_from_uint64(uint64_t x, struct eth_addr *ea);
static inline struct eth_addr eth_addr_invert(const struct eth_addr src)
{
return dst;
}
-static inline void eth_addr_mark_random(struct eth_addr *ea)
-{
- ea->ea[0] &= ~1; /* Unicast. */
- ea->ea[0] |= 2; /* Private. */
-}
+void eth_addr_mark_random(struct eth_addr *ea);
static inline void eth_addr_random(struct eth_addr *ea)
{
#define ETH_TYPE_MPLS 0x8847
#define ETH_TYPE_MPLS_MCAST 0x8848
#define ETH_TYPE_NSH 0x894f
+#define ETH_TYPE_ERSPAN1 0x88be /* version 1 type II */
+#define ETH_TYPE_ERSPAN2 0x22eb /* version 2 type III */
static inline bool eth_type_mpls(ovs_be16 eth_type)
{
return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT;
}
+/* Set label in mpls lse. */
+static inline void
+flow_set_mpls_lse_label(ovs_be32 *mpls_lse, uint32_t label)
+{
+ *mpls_lse &= ~htonl(MPLS_LABEL_MASK);
+ *mpls_lse |= htonl(label << MPLS_LABEL_SHIFT);
+}
+
+/* Set TC in mpls lse. */
+static inline void
+flow_set_mpls_lse_tc(ovs_be32 *mpls_lse, uint8_t tc)
+{
+ *mpls_lse &= ~htonl(MPLS_TC_MASK);
+ *mpls_lse |= htonl((tc & 0x7) << MPLS_TC_SHIFT);
+}
+
+/* Set BOS in mpls lse. */
+static inline void
+flow_set_mpls_lse_bos(ovs_be32 *mpls_lse, uint8_t bos)
+{
+ *mpls_lse &= ~htonl(MPLS_BOS_MASK);
+ *mpls_lse |= htonl((bos & 0x1) << MPLS_BOS_SHIFT);
+}
+
/* Set TTL in mpls lse. */
static inline void
flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl)
#define IP_ECN_ECT_0 0x02
#define IP_ECN_CE 0x03
#define IP_ECN_MASK 0x03
+#define IP_DSCP_CS6 0xc0
#define IP_DSCP_MASK 0xfc
static inline int
};
BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
+/* ICMPV4 */
+#define ICMP_ERROR_DATA_L4_LEN 8
+
#define IGMP_HEADER_LEN 8
struct igmp_header {
uint8_t igmp_type;
};
BUILD_ASSERT_DECL(IGMPV3_HEADER_LEN == sizeof(struct igmpv3_header));
+#define IGMPV3_QUERY_HEADER_LEN 12
+struct igmpv3_query_header {
+ uint8_t type;
+ uint8_t max_resp;
+ ovs_be16 csum;
+ ovs_16aligned_be32 group;
+ uint8_t srs_qrv;
+ uint8_t qqic;
+ ovs_be16 nsrcs;
+};
+BUILD_ASSERT_DECL(
+ IGMPV3_QUERY_HEADER_LEN == sizeof(struct igmpv3_query_header
+));
+
#define IGMPV3_RECORD_LEN 8
struct igmpv3_record {
uint8_t type;
ovs_16aligned_be32 be32[4];
};
-/* Like struct in6_hdr, but whereas that struct requires 32-bit alignment, this
+/* Like struct ip6_hdr, but whereas that struct requires 32-bit alignment, this
* one only requires 16-bit alignment. */
struct ovs_16aligned_ip6_hdr {
union {
};
BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
-#define ICMP6_ERROR_HEADER_LEN 8
-struct icmp6_error_header {
+#define ICMP6_DATA_HEADER_LEN 8
+struct icmp6_data_header {
struct icmp6_header icmp6_base;
- ovs_be32 icmp6_error_ext;
+ union {
+ ovs_16aligned_be32 be32[1];
+ ovs_be16 be16[2];
+ uint8_t u8[4];
+ } icmp6_data;
};
-BUILD_ASSERT_DECL(ICMP6_ERROR_HEADER_LEN == sizeof(struct icmp6_error_header));
+BUILD_ASSERT_DECL(ICMP6_DATA_HEADER_LEN == sizeof(struct icmp6_data_header));
uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *);
-uint16_t packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *,
+ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *,
const void *, uint8_t, uint16_t);
/* Neighbor Discovery option field.
};
BUILD_ASSERT_DECL(ND_PREFIX_OPT_LEN == sizeof(struct ovs_nd_prefix_opt));
-#define ND_PREFIX_ON_LINK 0x80
-#define ND_PREFIX_AUTONOMOUS_ADDRESS 0x40
-
/* Neighbor Discovery option: MTU. */
#define ND_MTU_OPT_LEN 8
#define ND_MTU_DEFAULT 0
}
}
-static inline 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);
-}
+void in6_addr_solicited_node(struct in6_addr *addr,
+ const struct in6_addr *ip6);
-/*
- * Generates ipv6 EUI64 address from the given eth addr
- * and prefix and stores it in 'lla'
- */
-static inline void
-in6_generate_eui64(struct eth_addr ea, 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];
-}
+void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix,
+ struct in6_addr *lla);
-/*
- * 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 =
- (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];
-}
+void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla);
/* 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
-}
+bool in6_is_lla(struct in6_addr *addr);
-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];
-}
+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)
{
#define GRE_FLAGS 0x00F8
#define GRE_VERSION 0x0007
+/*
+ * ERSPAN protocol header and metadata
+ *
+ * Version 1 (Type II) header (8 octets [42:49])
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ver | VLAN | COS | En|T| Session ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Index |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *
+ * ERSPAN Version 2 (Type III) header (12 octets [42:49])
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ver | VLAN | COS |BSO|T| Session ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Timestamp |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SGT |P| FT | Hw ID |D|Gra|O|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+/* ERSPAN has fixed 8-byte GRE header */
+#define ERSPAN_GREHDR_LEN 8
+#define ERSPAN_HDR(gre_base_hdr) \
+ ((struct erspan_base_hdr *)((char *)gre_base_hdr + ERSPAN_GREHDR_LEN))
+
+#define ERSPAN_V1_MDSIZE 4
+#define ERSPAN_V2_MDSIZE 8
+
+#define ERSPAN_SID_MASK 0x03ff /* 10-bit Session ID. */
+#define ERSPAN_IDX_MASK 0xfffff /* v1 Index */
+#define ERSPAN_HWID_MASK 0x03f0
+#define ERSPAN_DIR_MASK 0x0008
+
+struct erspan_base_hdr {
+#ifdef WORDS_BIGENDIAN
+ uint8_t ver:4,
+ vlan_upper:4;
+ uint8_t vlan:8;
+ uint8_t cos:3,
+ en:2,
+ t:1,
+ session_id_upper:2;
+ uint8_t session_id:8;
+#else
+ uint8_t vlan_upper:4,
+ ver:4;
+ uint8_t vlan:8;
+ uint8_t session_id_upper:2,
+ t:1,
+ en:2,
+ cos:3;
+ uint8_t session_id:8;
+#endif
+};
+
+struct erspan_md2 {
+ ovs_16aligned_be32 timestamp;
+ ovs_be16 sgt;
+#ifdef WORDS_BIGENDIAN
+ uint8_t p:1,
+ ft:5,
+ hwid_upper:2;
+ uint8_t hwid:4,
+ dir:1,
+ gra:2,
+ o:1;
+#else
+ uint8_t hwid_upper:2,
+ ft:5,
+ p:1;
+ uint8_t o:1,
+ gra:2,
+ dir:1,
+ hwid:4;
+#endif
+};
+
+struct erspan_metadata {
+ int version;
+ union {
+ ovs_be32 index; /* Version 1 (type II)*/
+ struct erspan_md2 md2; /* Version 2 (type III) */
+ } u;
+};
+
+static inline uint16_t get_sid(const struct erspan_base_hdr *ershdr)
+{
+ return (ershdr->session_id_upper << 8) + ershdr->session_id;
+}
+
+static inline void set_sid(struct erspan_base_hdr *ershdr, uint16_t id)
+{
+ ershdr->session_id = id & 0xff;
+ ershdr->session_id_upper = (id >> 8) &0x3;
+}
+
+static inline uint8_t get_hwid(const struct erspan_md2 *md2)
+{
+ return (md2->hwid_upper << 4) + md2->hwid;
+}
+
+static inline void set_hwid(struct erspan_md2 *md2, uint8_t hwid)
+{
+ md2->hwid = hwid & 0xf;
+ md2->hwid_upper = (hwid >> 4) & 0x3;
+}
+
+/* ERSPAN timestamp granularity
+ * 00b --> granularity = 100 microseconds
+ * 01b --> granularity = 100 nanoseconds
+ * 10b --> granularity = IEEE 1588
+ * Here we only support 100 microseconds.
+ */
+enum erspan_ts_gra {
+ ERSPAN_100US,
+ ERSPAN_100NS,
+ ERSPAN_IEEE1588,
+};
+
+static inline ovs_be32 get_erspan_ts(enum erspan_ts_gra gra)
+{
+ ovs_be32 ts = 0;
+
+ switch (gra) {
+ case ERSPAN_100US:
+ ts = htonl((uint32_t)(time_wall_usec() / 100));
+ break;
+ case ERSPAN_100NS:
+ /* fall back */
+ case ERSPAN_IEEE1588:
+ /* fall back */
+ default:
+ OVS_NOT_REACHED();
+ break;
+ }
+ return ts;
+}
+
+/*
+ * GTP-U protocol header and metadata
+ * See:
+ * User Plane Protocol and Architectural Analysis on 3GPP 5G System
+ * draft-hmm-dmm-5g-uplane-analysis-00
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ver |P|R|E|S|N| Message Type| Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Tunnel Endpoint Identifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Sequence Number | N-PDU Number | Next-Ext-Hdr |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * GTP-U Flags:
+ * P: Protocol Type (Set to '1')
+ * R: Reserved Bit (Set to '0')
+ * E: Extension Header Flag (Set to '1' if extension header exists)
+ * S: Sequence Number Flag (Set to '1' if sequence number exists)
+ * N: N-PDU Number Flag (Set to '1' if N-PDU number exists)
+ *
+ * GTP-U Message Type:
+ * Indicates the type of GTP-U message.
+ *
+ * GTP-U Length:
+ * Indicates the length in octets of the payload.
+ *
+ * User payload is transmitted in G-PDU packets.
+ */
+
+#define GTPU_VER_MASK 0xe0
+#define GTPU_P_MASK 0x10
+#define GTPU_E_MASK 0x04
+#define GTPU_S_MASK 0x02
+
+/* GTP-U UDP port. */
+#define GTPU_DST_PORT 2152
+
+/* Default GTP-U flags: Ver = 1 and P = 1. */
+#define GTPU_FLAGS_DEFAULT 0x30
+
+/* GTP-U message type for normal user plane PDU. */
+#define GTPU_MSGTYPE_REQ 1 /* Echo Request. */
+#define GTPU_MSGTYPE_REPL 2 /* Echo Reply. */
+#define GTPU_MSGTYPE_GPDU 255 /* User Payload. */
+
+struct gtpu_metadata {
+ uint8_t flags;
+ uint8_t msgtype;
+};
+BUILD_ASSERT_DECL(sizeof(struct gtpu_metadata) == 2);
+
+struct gtpuhdr {
+ struct gtpu_metadata md;
+ ovs_be16 len;
+ ovs_16aligned_be32 teid;
+};
+BUILD_ASSERT_DECL(sizeof(struct gtpuhdr) == 8);
+
+struct gtpuhdr_opt {
+ ovs_be16 seqno;
+ uint8_t pdu_number;
+ uint8_t next_ext_type;
+};
+BUILD_ASSERT_DECL(sizeof(struct gtpuhdr_opt) == 4);
+
/* VXLAN protocol header */
struct vxlanhdr {
union {
int ipv6_count_cidr_bits(const struct in6_addr *netmask);
bool ipv6_is_cidr(const struct in6_addr *netmask);
-enum port_flags {
- PORT_OPTIONAL,
- PORT_REQUIRED,
- PORT_FORBIDDEN,
-};
-
-char *ipv46_parse(const char *s, enum port_flags flags,
- struct sockaddr_storage *ss)
- OVS_WARN_UNUSED_RESULT;
-
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);
void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
void packet_set_nd(struct dp_packet *, const struct in6_addr *target,
const struct eth_addr sll, const struct eth_addr tll);
-
+void packet_set_nd_ext(struct dp_packet *packet,
+ const ovs_16aligned_be32 rso_flags,
+ const uint8_t opt_type);
+void packet_set_igmp3_query(struct dp_packet *, uint8_t max_resp,
+ ovs_be32 group, bool srs, uint8_t qrv,
+ uint8_t qqic);
void packet_format_tcp_flags(struct ds *, uint16_t);
const char *packet_tcp_flag_to_string(uint32_t flag);
+void *compose_ipv6(struct dp_packet *packet, uint8_t proto,
+ const struct in6_addr *src, const struct in6_addr *dst,
+ uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size);
void compose_arp__(struct dp_packet *);
void compose_arp(struct dp_packet *, uint16_t arp_op,
const struct eth_addr arp_sha,