mirror of
https://github.com/openvswitch/ovs
synced 2025-09-02 15:25:22 +00:00
packets: add compose_nd_ra
This patch introduces methods to compose a Router Advertisement (RA) packet, introduces flags for RA. RA packet composed structures against specification in RFC4861. Caller can use compse_nd_ra_with_sll_mtu_opts to compose a RA packet with Source Link-layer Address Option and MTU Option. Caller can use packet_put_ra_prefix_opt to append a Prefix Information Option to a RA packet. Signed-off-by: Zongkai LI <zealokii@gmail.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
@@ -325,6 +325,7 @@ Yuanhan Liu yuanhan.liu@linux.intel.com
|
||||
ZhengLingyun konghuarukhr@163.com
|
||||
Zoltán Balogh zoltan.balogh@ericsson.com
|
||||
Zoltan Kiss zoltan.kiss@citrix.com
|
||||
Zongkai LI zealokii@gmail.com
|
||||
Zhi Yong Wu zwu.kernel@gmail.com
|
||||
Zang MingJie zealot0630@gmail.com
|
||||
nickcooper-zhangtonghao nickcooper-zhangtonghao@opencloud.tech
|
||||
|
@@ -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)
|
||||
@@ -1432,6 +1433,86 @@ compose_nd_na(struct dp_packet *b,
|
||||
ND_MSG_LEN + ND_OPT_LEN));
|
||||
}
|
||||
|
||||
/* Compose an IPv6 Neighbor Discovery Router Advertisement message with
|
||||
* Source Link-layer Address Option and MTU Option.
|
||||
* Caller can call packet_put_ra_prefix_opt to append Prefix Information
|
||||
* Options to composed messags in 'b'. */
|
||||
void
|
||||
compose_nd_ra(struct dp_packet *b,
|
||||
const struct eth_addr eth_src, const struct eth_addr eth_dst,
|
||||
const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst,
|
||||
uint8_t cur_hop_limit, uint8_t mo_flags,
|
||||
ovs_be16 router_lt, ovs_be32 reachable_time,
|
||||
ovs_be32 retrans_timer, ovs_be32 mtu)
|
||||
{
|
||||
/* Don't compose Router Advertisement packet with MTU Option if mtu
|
||||
* value is 0. */
|
||||
bool with_mtu = mtu != 0;
|
||||
size_t mtu_opt_len = with_mtu ? ND_MTU_OPT_LEN : 0;
|
||||
|
||||
eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
|
||||
|
||||
struct ovs_ra_msg *ra = compose_ipv6(
|
||||
b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255,
|
||||
RA_MSG_LEN + ND_OPT_LEN + mtu_opt_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_lt;
|
||||
ra->reachable_time = reachable_time;
|
||||
ra->retrans_timer = retrans_timer;
|
||||
|
||||
struct ovs_nd_opt *lla_opt = ra->options;
|
||||
lla_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
lla_opt->nd_opt_len = 1;
|
||||
lla_opt->nd_opt_mac = eth_src;
|
||||
|
||||
if (with_mtu) {
|
||||
/* ovs_nd_mtu_opt has the same size with ovs_nd_opt. */
|
||||
struct ovs_nd_mtu_opt *mtu_opt
|
||||
= (struct ovs_nd_mtu_opt *)(lla_opt + 1);
|
||||
mtu_opt->type = ND_OPT_MTU;
|
||||
mtu_opt->len = 1;
|
||||
mtu_opt->reserved = 0;
|
||||
put_16aligned_be32(&mtu_opt->mtu, mtu);
|
||||
}
|
||||
|
||||
ra->icmph.icmp6_cksum = 0;
|
||||
uint32_t icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
|
||||
ra->icmph.icmp6_cksum = csum_finish(csum_continue(
|
||||
icmp_csum, ra, RA_MSG_LEN + ND_OPT_LEN + mtu_opt_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_be128 prefix)
|
||||
{
|
||||
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 = dp_packet_put_uninit(b, sizeof *b);
|
||||
prefix_opt->type = ND_OPT_PREFIX_INFORMATION;
|
||||
prefix_opt->len = 4;
|
||||
prefix_opt->prefix_len = plen;
|
||||
prefix_opt->la_flags = la_flags;
|
||||
put_16aligned_be32(&prefix_opt->valid_lifetime, valid_lifetime);
|
||||
put_16aligned_be32(&prefix_opt->preferred_lifetime, preferred_lifetime);
|
||||
put_16aligned_be32(&prefix_opt->reserved, 0);
|
||||
memcpy(prefix_opt->prefix.be32, prefix.be32, sizeof(ovs_be32[4]));
|
||||
|
||||
ra->icmph.icmp6_cksum = 0;
|
||||
uint32_t 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));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
packet_csum_pseudoheader(const struct ip_header *ip)
|
||||
{
|
||||
|
@@ -897,12 +897,39 @@ uint16_t packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *,
|
||||
* 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 */
|
||||
uint8_t nd_opt_type; /* One of ND_OPT_*. */
|
||||
uint8_t nd_opt_len;
|
||||
struct eth_addr nd_opt_mac;
|
||||
};
|
||||
BUILD_ASSERT_DECL(ND_OPT_LEN == sizeof(struct ovs_nd_opt));
|
||||
|
||||
/* Neighbor Discovery option: Prefix Information. */
|
||||
#define ND_PREFIX_OPT_LEN 32
|
||||
struct ovs_nd_prefix_opt {
|
||||
uint8_t type; /* ND_OPT_PREFIX_INFORMATION. */
|
||||
uint8_t len; /* Always 4. */
|
||||
uint8_t prefix_len;
|
||||
uint8_t la_flags; /* ND_PREFIX_* flags. */
|
||||
ovs_16aligned_be32 valid_lifetime;
|
||||
ovs_16aligned_be32 preferred_lifetime;
|
||||
ovs_16aligned_be32 reserved; /* Always 0. */
|
||||
union ovs_16aligned_in6_addr prefix;
|
||||
};
|
||||
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
|
||||
struct ovs_nd_mtu_opt {
|
||||
uint8_t type; /* ND_OPT_MTU */
|
||||
uint8_t len; /* Always 1. */
|
||||
ovs_be16 reserved; /* Always 0. */
|
||||
ovs_16aligned_be32 mtu;
|
||||
};
|
||||
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. */
|
||||
#define ND_MSG_LEN 24
|
||||
@@ -914,10 +941,26 @@ struct ovs_nd_msg {
|
||||
};
|
||||
BUILD_ASSERT_DECL(ND_MSG_LEN == sizeof(struct ovs_nd_msg));
|
||||
|
||||
/* Neighbor Discovery packet flags. */
|
||||
#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; /* ND_RA_MANAGED_ADDRESS and ND_RA_OTHER_CONFIG flags. */
|
||||
ovs_be16 router_lifetime;
|
||||
ovs_be32 reachable_time;
|
||||
ovs_be32 retrans_timer;
|
||||
struct ovs_nd_opt options[0];
|
||||
};
|
||||
BUILD_ASSERT_DECL(RA_MSG_LEN == sizeof(struct ovs_ra_msg));
|
||||
|
||||
#define ND_RA_MANAGED_ADDRESS 0x80
|
||||
#define ND_RA_OTHER_CONFIG 0x40
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -972,6 +1015,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)
|
||||
{
|
||||
@@ -1234,6 +1281,19 @@ 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 struct in6_addr *ipv6_src,
|
||||
const struct in6_addr *ipv6_dst,
|
||||
uint8_t cur_hop_limit, uint8_t mo_flags,
|
||||
ovs_be16 router_lt, ovs_be32 reachable_time,
|
||||
ovs_be32 retrans_timer, 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_be128 router_prefix);
|
||||
uint32_t packet_csum_pseudoheader(const struct ip_header *);
|
||||
void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6);
|
||||
|
||||
|
Reference in New Issue
Block a user