[ovs-dev] [PATCH RFC v3 1/3] ovs packet: add compose RA packet support
Zongkai LI
zealokii at gmail.com
Fri Aug 12 07:58:47 UTC 2016
From: LI Zong Kai <lzklibj at cn.ibm.com>
This patch introduces methods to compose a Router Advertisement (RA) packet,
introduces flags for RA, and renames ovs_nd_opt to ovs_nd_lla_opt to specify
it's Source/Target Link-layer Address option.
The packet, composed by new introduced methods, structures against
specification in RFC4861.
---
lib/flow.c | 26 ++++-----
lib/odp-execute.c | 20 +++----
lib/packets.c | 168 +++++++++++++++++++++++++++++++++++++++++++++---------
lib/packets.h | 86 ++++++++++++++++++++++++----
4 files changed, 239 insertions(+), 61 deletions(-)
diff --git a/lib/flow.c b/lib/flow.c
index ba4f8c7..250dc7d 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -400,8 +400,8 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
while (*sizep >= 8) {
/* The minimum size of an option is 8 bytes, which also is
* the size of Ethernet link-layer options. */
- const struct ovs_nd_opt *nd_opt = *datap;
- int opt_len = nd_opt->nd_opt_len * ND_OPT_LEN;
+ const struct ovs_nd_lla_opt *nd_opt = *datap;
+ int opt_len = nd_opt->length * ND_LLA_OPT_LEN;
if (!opt_len || opt_len > *sizep) {
return;
@@ -410,17 +410,17 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
/* Store the link layer address if the appropriate option is
* provided. It is considered an error if the same link
* layer option is specified twice. */
- if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
+ if (nd_opt->type == ND_OPT_SOURCE_LINKADDR
&& opt_len == 8) {
if (OVS_LIKELY(eth_addr_is_zero(arp_buf[0]))) {
- arp_buf[0] = nd_opt->nd_opt_mac;
+ arp_buf[0] = nd_opt->lla;
} else {
goto invalid;
}
- } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
+ } else if (nd_opt->type == ND_OPT_TARGET_LINKADDR
&& opt_len == 8) {
if (OVS_LIKELY(eth_addr_is_zero(arp_buf[1]))) {
- arp_buf[1] = nd_opt->nd_opt_mac;
+ arp_buf[1] = nd_opt->lla;
} else {
goto invalid;
}
@@ -2273,7 +2273,7 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow)
(icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) {
struct in6_addr *nd_target;
- struct ovs_nd_opt *nd_opt;
+ struct ovs_nd_lla_opt *nd_opt;
l4_len += sizeof *nd_target;
nd_target = dp_packet_put_zeros(p, sizeof *nd_target);
@@ -2282,16 +2282,16 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow)
if (!eth_addr_is_zero(flow->arp_sha)) {
l4_len += 8;
nd_opt = dp_packet_put_zeros(p, 8);
- nd_opt->nd_opt_len = 1;
- nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
- nd_opt->nd_opt_mac = flow->arp_sha;
+ nd_opt->length = 1;
+ nd_opt->type = ND_OPT_SOURCE_LINKADDR;
+ nd_opt->lla = flow->arp_sha;
}
if (!eth_addr_is_zero(flow->arp_tha)) {
l4_len += 8;
nd_opt = dp_packet_put_zeros(p, 8);
- nd_opt->nd_opt_len = 1;
- nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
- nd_opt->nd_opt_mac = flow->arp_tha;
+ nd_opt->length = 1;
+ nd_opt->type = ND_OPT_TARGET_LINKADDR;
+ nd_opt->lla = flow->arp_tha;
}
}
}
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 5a43904..f791a33 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -185,7 +185,7 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
const struct ovs_key_nd *mask)
{
const struct ovs_nd_msg *ns = dp_packet_l4(packet);
- const struct ovs_nd_opt *nd_opt = dp_packet_get_nd_payload(packet);
+ const struct ovs_nd_lla_opt *nd_opt = dp_packet_get_nd_payload(packet);
if (OVS_LIKELY(ns && nd_opt)) {
int bytes_remain = dp_packet_l4_size(packet) - sizeof(*ns);
@@ -193,25 +193,25 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
struct eth_addr sll_buf = eth_addr_zero;
struct eth_addr tll_buf = eth_addr_zero;
- while (bytes_remain >= ND_OPT_LEN && nd_opt->nd_opt_len != 0) {
- if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
- && nd_opt->nd_opt_len == 1) {
- sll_buf = nd_opt->nd_opt_mac;
+ while (bytes_remain >= ND_LLA_OPT_LEN && nd_opt->length != 0) {
+ if (nd_opt->type == ND_OPT_SOURCE_LINKADDR
+ && nd_opt->length == 1) {
+ sll_buf = nd_opt->lla;
ether_addr_copy_masked(&sll_buf, key->nd_sll, mask->nd_sll);
/* A packet can only contain one SLL or TLL option */
break;
- } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
- && nd_opt->nd_opt_len == 1) {
- tll_buf = nd_opt->nd_opt_mac;
+ } else if (nd_opt->type == ND_OPT_TARGET_LINKADDR
+ && nd_opt->length == 1) {
+ tll_buf = nd_opt->lla;
ether_addr_copy_masked(&tll_buf, key->nd_tll, mask->nd_tll);
/* A packet can only contain one SLL or TLL option */
break;
}
- nd_opt += nd_opt->nd_opt_len;
- bytes_remain -= nd_opt->nd_opt_len * ND_OPT_LEN;
+ nd_opt += nd_opt->length;
+ bytes_remain -= nd_opt->length * ND_LLA_OPT_LEN;
}
packet_set_nd(packet,
diff --git a/lib/packets.c b/lib/packets.c
index e4c29d5..032736b 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -35,6 +35,7 @@
const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;
+const struct in6_addr in6addr_all_routers = IN6ADDR_ALL_ROUTERS_INIT;
struct in6_addr
flow_tnl_dst(const struct flow_tnl *tnl)
@@ -1142,7 +1143,7 @@ packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
const struct eth_addr sll, const struct eth_addr tll)
{
struct ovs_nd_msg *ns;
- struct ovs_nd_opt *nd_opt;
+ struct ovs_nd_lla_opt *nd_opt;
int bytes_remain = dp_packet_l4_size(packet);
if (OVS_UNLIKELY(bytes_remain < sizeof(*ns))) {
@@ -1159,33 +1160,33 @@ packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
target, true);
}
- while (bytes_remain >= ND_OPT_LEN && nd_opt->nd_opt_len != 0) {
- if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
- && nd_opt->nd_opt_len == 1) {
- if (!eth_addr_equals(nd_opt->nd_opt_mac, sll)) {
+ while (bytes_remain >= ND_LLA_OPT_LEN && nd_opt->length != 0) {
+ if (nd_opt->type == ND_OPT_SOURCE_LINKADDR
+ && nd_opt->length == 1) {
+ if (!eth_addr_equals(nd_opt->lla, sll)) {
ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
- *csum = recalc_csum48(*csum, nd_opt->nd_opt_mac, sll);
- nd_opt->nd_opt_mac = sll;
+ *csum = recalc_csum48(*csum, nd_opt->lla, sll);
+ nd_opt->lla = sll;
}
/* A packet can only contain one SLL or TLL option */
break;
- } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
- && nd_opt->nd_opt_len == 1) {
- if (!eth_addr_equals(nd_opt->nd_opt_mac, tll)) {
+ } else if (nd_opt->type == ND_OPT_TARGET_LINKADDR
+ && nd_opt->length == 1) {
+ if (!eth_addr_equals(nd_opt->lla, tll)) {
ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
- *csum = recalc_csum48(*csum, nd_opt->nd_opt_mac, tll);
- nd_opt->nd_opt_mac = tll;
+ *csum = recalc_csum48(*csum, nd_opt->lla, tll);
+ nd_opt->lla = tll;
}
/* A packet can only contain one SLL or TLL option */
break;
}
- nd_opt += nd_opt->nd_opt_len;
- bytes_remain -= nd_opt->nd_opt_len * ND_OPT_LEN;
+ nd_opt += nd_opt->length;
+ bytes_remain -= nd_opt->length * ND_LLA_OPT_LEN;
}
}
@@ -1356,7 +1357,7 @@ compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
struct in6_addr sn_addr;
struct eth_addr eth_dst;
struct ovs_nd_msg *ns;
- struct ovs_nd_opt *nd_opt;
+ struct ovs_nd_lla_opt *nd_opt;
uint32_t icmp_csum;
in6_addr_solicited_node(&sn_addr, ipv6_dst);
@@ -1364,15 +1365,15 @@ compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
ns = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, &sn_addr,
- 0, 0, 255, ND_MSG_LEN + ND_OPT_LEN);
+ 0, 0, 255, ND_MSG_LEN + ND_LLA_OPT_LEN);
ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
ns->icmph.icmp6_code = 0;
put_16aligned_be32(&ns->rso_flags, htonl(0));
nd_opt = &ns->options[0];
- nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
- nd_opt->nd_opt_len = 1;
+ nd_opt->type = ND_OPT_SOURCE_LINKADDR;
+ nd_opt->length = 1;
/* Copy target address to temp buffer to prevent misaligned access. */
ovs_be32 tbuf[4];
@@ -1381,8 +1382,8 @@ compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
ns->icmph.icmp6_cksum = 0;
icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
- ns->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, ns,
- ND_MSG_LEN + ND_OPT_LEN));
+ ns->icmph.icmp6_cksum = csum_finish(
+ csum_continue(icmp_csum, ns, ND_MSG_LEN + ND_LLA_OPT_LEN));
}
/* Compose an IPv6 Neighbor Discovery Neighbor Advertisement message. */
@@ -1393,20 +1394,20 @@ compose_nd_na(struct dp_packet *b,
ovs_be32 rso_flags)
{
struct ovs_nd_msg *na;
- struct ovs_nd_opt *nd_opt;
+ struct ovs_nd_lla_opt *nd_opt;
uint32_t icmp_csum;
eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst,
- 0, 0, 255, ND_MSG_LEN + ND_OPT_LEN);
+ 0, 0, 255, ND_MSG_LEN + ND_LLA_OPT_LEN);
na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT;
na->icmph.icmp6_code = 0;
put_16aligned_be32(&na->rso_flags, rso_flags);
nd_opt = &na->options[0];
- nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
- nd_opt->nd_opt_len = 1;
+ nd_opt->type = ND_OPT_TARGET_LINKADDR;
+ nd_opt->length = 1;
/* Copy target address to temp buffer to prevent misaligned access. */
ovs_be32 tbuf[4];
@@ -1415,8 +1416,123 @@ compose_nd_na(struct dp_packet *b,
na->icmph.icmp6_cksum = 0;
icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
- na->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, na,
- ND_MSG_LEN + ND_OPT_LEN));
+ na->icmph.icmp6_cksum = csum_finish(
+ csum_continue(icmp_csum, na, ND_MSG_LEN + ND_LLA_OPT_LEN));
+}
+
+/* Compose an IPv6 Neighbor Discovery Router Advertisement message without
+ * any IPv6 Neighbor Discovery options. */
+void
+compose_nd_ra(struct dp_packet *b,
+ const struct eth_addr eth_src, const struct eth_addr eth_dst,
+ const ovs_be32 ipv6_src[4], const ovs_be32 ipv6_dst[4],
+ uint8_t cur_hop_limit, uint8_t mo_flags, ovs_be16 router_lifetime,
+ ovs_be32 reachable_time, ovs_be32 retrans_timer)
+{
+ struct ovs_ra_msg *ra;
+ uint32_t icmp_csum;
+
+ eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
+ ra = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255,
+ RA_MSG_LEN);
+
+ ra->icmph.icmp6_type = ND_ROUTER_ADVERT;
+ ra->icmph.icmp6_code = 0;
+ ra->cur_hop_limit = cur_hop_limit;
+ ra->mo_flags = mo_flags;
+ ra->router_lifetime = router_lifetime;
+ ra->reachable_time = reachable_time;
+ ra->retrans_timer = retrans_timer;
+
+ ra->icmph.icmp6_cksum = 0;
+ icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
+ ra->icmph.icmp6_cksum = csum_finish(csum_continue(
+ icmp_csum, ra, RA_MSG_LEN));
+}
+
+/* Append an IPv6 Neighbor Discovery Prefix Information option to a
+ * Router Advertisement message. */
+void
+packet_put_ra_prefix_opt(struct dp_packet *b,
+ uint8_t plen, uint8_t la_flags, ovs_be32 valid_lifetime,
+ ovs_be32 preferred_lifetime, const ovs_be32 prefix[4])
+{
+ size_t prev_l4_size = dp_packet_l4_size(b);
+ struct ip6_hdr *nh = dp_packet_l3(b);
+ nh->ip6_plen = htons(prev_l4_size + ND_PREFIX_OPT_LEN);
+
+ struct ovs_ra_msg *ra = dp_packet_l4(b);
+ struct ovs_nd_prefix_opt *prefix_opt;
+ uint32_t icmp_csum;
+
+ prefix_opt = dp_packet_put_uninit(b, sizeof(struct ovs_nd_prefix_opt));
+ prefix_opt->type = ND_OPT_PREFIX_INFORMATION;
+ prefix_opt->length = 4;
+ prefix_opt->prefix_length = plen;
+ prefix_opt->la_flags = la_flags;
+ prefix_opt->valid_lifetime = valid_lifetime;
+ prefix_opt->preferred_lifetime = preferred_lifetime;
+ prefix_opt->reserved = 0;
+ packet_update_csum128(b, IPPROTO_ICMPV6, prefix_opt->prefix.be32, prefix);
+ memcpy(prefix_opt->prefix.be32, prefix, sizeof(ovs_be32[4]));
+
+ ra->icmph.icmp6_cksum = 0;
+ icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
+ ra->icmph.icmp6_cksum = csum_finish(csum_continue(
+ icmp_csum, ra, prev_l4_size + ND_PREFIX_OPT_LEN));
+}
+
+/* Append an IPv6 Neighbor Discovery MTU option to a
+ * Router Advertisement message. */
+void
+packet_put_ra_mtu_opt(struct dp_packet *b, ovs_be32 mtu)
+{
+ size_t prev_l4_size = dp_packet_l4_size(b);
+ struct ip6_hdr *nh = dp_packet_l3(b);
+ nh->ip6_plen = htons(prev_l4_size + ND_MTU_OPT_LEN);
+
+ struct ovs_ra_msg *ra = dp_packet_l4(b);
+ struct ovs_nd_mtu_opt *mtu_opt;
+ uint32_t icmp_csum;
+
+ mtu_opt = dp_packet_put_uninit(b, sizeof(struct ovs_nd_mtu_opt));
+ mtu_opt->type = ND_OPT_MTU;
+ mtu_opt->length = 1;
+ mtu_opt->reserved = 0;
+ ovs_be16 *csum = &(ra->icmph.icmp6_cksum);
+ *csum = recalc_csum32(*csum, mtu_opt->mtu, mtu);
+ mtu_opt->mtu = mtu;
+
+ ra->icmph.icmp6_cksum = 0;
+ icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
+ ra->icmph.icmp6_cksum = csum_finish(csum_continue(
+ icmp_csum, ra, prev_l4_size + ND_MTU_OPT_LEN));
+}
+
+/* Append an IPv6 Neighbor Discovery Source Link-layer Address option to a
+ * Router Advertisement message. */
+void
+packet_put_ra_sll_opt(struct dp_packet *b, const struct eth_addr lla)
+{
+ size_t prev_l4_size = dp_packet_l4_size(b);
+ struct ip6_hdr *nh = dp_packet_l3(b);
+ nh->ip6_plen = htons(prev_l4_size + ND_LLA_OPT_LEN);
+
+ struct ovs_ra_msg *ra = dp_packet_l4(b);
+ struct ovs_nd_lla_opt *lla_opt;
+ uint32_t icmp_csum;
+
+ lla_opt = dp_packet_put_uninit(b, sizeof(struct ovs_nd_lla_opt));
+ lla_opt->type = ND_OPT_SOURCE_LINKADDR;
+ lla_opt->length = 1;
+ ovs_be16 *csum = &(ra->icmph.icmp6_cksum);
+ *csum = recalc_csum48(*csum, lla_opt->lla, lla);
+ lla_opt->lla = lla;
+
+ ra->icmph.icmp6_cksum = 0;
+ icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
+ ra->icmph.icmp6_cksum = csum_finish(csum_continue(
+ icmp_csum, ra, prev_l4_size + ND_LLA_OPT_LEN));
}
uint32_t
diff --git a/lib/packets.h b/lib/packets.h
index 9b98b29..9bff2c0 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -161,6 +161,12 @@ static const struct eth_addr eth_addr_lacp OVS_UNUSED
static const struct eth_addr eth_addr_bfd OVS_UNUSED
= { { { 0x00, 0x23, 0x20, 0x00, 0x00, 0x01 } } };
+static const struct eth_addr eth_addr_ip6_all_hosts OVS_UNUSED
+ = { { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } } };
+
+static const struct eth_addr eth_addr_ip6_all_routers OVS_UNUSED
+ = { { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x02 } } };
+
static inline bool eth_addr_is_broadcast(const struct eth_addr a)
{
return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
@@ -831,15 +837,48 @@ 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
-struct ovs_nd_opt {
- uint8_t nd_opt_type; /* Values defined in icmp6.h */
- uint8_t nd_opt_len; /* in units of 8 octets (the size of this struct) */
- struct eth_addr nd_opt_mac; /* Ethernet address in the case of SLL or TLL options */
+/* Neighbor Discovery packet flags. */
+#define ND_RSO_ROUTER 0x80000000
+#define ND_RSO_SOLICITED 0x40000000
+#define ND_RSO_OVERRIDE 0x20000000
+#define ND_PREFIX_ON_LINK 0x80
+#define ND_PREFIX_AUTONOMOUS_ADDRESS 0x40
+#define ND_ROUTER_ADV_MANAGED_ADDRESS 0x80
+#define ND_ROUTER_ADV_OTHER_CONFIG 0x40
+
+/* Neighbor Discovery option: Source/Target Link-layer Address. */
+#define ND_LLA_OPT_LEN 8
+struct ovs_nd_lla_opt {
+ uint8_t type; /* Values defined in icmp6.h */
+ uint8_t length; /* in units of 8 octets (the size of this struct) */
+ struct eth_addr lla; /* Ethernet address in the case of SLL or TLL options */
+};
+BUILD_ASSERT_DECL(ND_LLA_OPT_LEN == sizeof(struct ovs_nd_lla_opt));
+
+/* Neighbor Discovery option: Prefix Information. */
+#define ND_PREFIX_OPT_LEN 32
+struct ovs_nd_prefix_opt {
+ uint8_t type; /* Values defined in icmp6.h */
+ uint8_t length;
+ uint8_t prefix_length;
+ /* on-link flag, autonomous address-configuration flag, 6-bit reserved. */
+ uint8_t la_flags;
+ ovs_be32 valid_lifetime;
+ ovs_be32 preferred_lifetime;
+ ovs_be32 reserved;
+ union ovs_16aligned_in6_addr prefix;
+};
+BUILD_ASSERT_DECL(ND_PREFIX_OPT_LEN == sizeof(struct ovs_nd_prefix_opt));
+
+/* Neighbor Discovery option: MTU. */
+#define ND_MTU_OPT_LEN 8
+struct ovs_nd_mtu_opt {
+ uint8_t type; /* Values defined in icmp6.h */
+ uint8_t length;
+ ovs_be16 reserved;
+ ovs_be32 mtu;
};
-BUILD_ASSERT_DECL(ND_OPT_LEN == sizeof(struct ovs_nd_opt));
+BUILD_ASSERT_DECL(ND_MTU_OPT_LEN == sizeof(struct ovs_nd_mtu_opt));
/* Like struct nd_msg (from ndisc.h), but whereas that struct requires 32-bit
* alignment, this one only requires 16-bit alignment. */
@@ -848,13 +887,20 @@ struct ovs_nd_msg {
struct icmp6_header icmph;
ovs_16aligned_be32 rso_flags;
union ovs_16aligned_in6_addr target;
- struct ovs_nd_opt options[0];
+ struct ovs_nd_lla_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
+#define RA_MSG_LEN 16
+struct ovs_ra_msg {
+ struct icmp6_header icmph;
+ uint8_t cur_hop_limit;
+ uint8_t mo_flags;
+ ovs_be16 router_lifetime;
+ ovs_be32 reachable_time;
+ ovs_be32 retrans_timer;
+};
+BUILD_ASSERT_DECL(RA_MSG_LEN == sizeof(struct ovs_ra_msg));
/*
* Use the same struct for MLD and MLD2, naming members as the defined fields in
@@ -910,6 +956,10 @@ extern const struct in6_addr in6addr_all_hosts;
#define IN6ADDR_ALL_HOSTS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } }
+extern const struct in6_addr in6addr_all_routers;
+#define IN6ADDR_ALL_ROUTERS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } }
+
static inline bool ipv6_addr_equals(const struct in6_addr *a,
const struct in6_addr *b)
{
@@ -1107,6 +1157,18 @@ void compose_nd_na(struct dp_packet *, const struct eth_addr eth_src,
const struct in6_addr *ipv6_src,
const struct in6_addr *ipv6_dst,
ovs_be32 rso_flags);
+void compose_nd_ra(struct dp_packet *,
+ const struct eth_addr eth_src, const struct eth_addr eth_dst,
+ const ovs_be32 ipv6_src[4], const ovs_be32 ipv6_dst[4],
+ uint8_t cur_hop_limit, uint8_t mo_flags,
+ ovs_be16 router_lifetime, ovs_be32 reachable_time,
+ ovs_be32 retrans_timer);
+void packet_put_ra_sll_opt(struct dp_packet *, const struct eth_addr lla);
+void packet_put_ra_mtu_opt(struct dp_packet *, ovs_be32 mtu);
+void packet_put_ra_prefix_opt(struct dp_packet *,
+ uint8_t plen, uint8_t la_flags,
+ ovs_be32 valid_lifetime, ovs_be32 preferred_lifetime,
+ const ovs_be32 router_prefix[4]);
uint32_t packet_csum_pseudoheader(const struct ip_header *);
void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6);
--
1.9.1
More information about the dev
mailing list