diff mbox

[ovs-dev,v4,1/6] packets: add compose_nd_ra

Message ID 20170323060333.5615-1-nusiddiq@redhat.com
State Superseded
Headers show

Commit Message

Numan Siddique March 23, 2017, 6:03 a.m. UTC
From: Zong Kai LI <zealokii@gmail.com>

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>
---
 lib/packets.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/packets.h | 59 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)

Comments

Numan Siddique March 23, 2017, 6:13 a.m. UTC | #1
Please ignore this patch. The updated one is here -
https://mail.openvswitch.org/pipermail/ovs-dev/2017-March/330135.html

Thanks
Numan


On Thu, Mar 23, 2017 at 11:33 AM, <nusiddiq@redhat.com> wrote:

> From: Zong Kai LI <zealokii@gmail.com>
>
> 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>
> ---
>  lib/packets.c | 88 ++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++
>  lib/packets.h | 59 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 147 insertions(+)
>
> diff --git a/lib/packets.c b/lib/packets.c
> index 94e7d87..dbe5105 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)
> @@ -1428,6 +1429,93 @@ 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_with_sll_mtu_opts(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)
> +{
> +    struct ovs_ra_msg *ra;
> +    struct ovs_nd_mtu_opt *mtu_opt;
> +    struct ovs_nd_opt *lla_opt;
> +    uint32_t icmp_csum;
> +
> +    /* 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);
> +    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;
> +
> +    lla_opt = &ra->options[0];
> +    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. */
> +        mtu_opt = (struct ovs_nd_mtu_opt *)(lla_opt + 1);
> +        mtu_opt->type = ND_OPT_MTU;
> +        mtu_opt->len = 1;
> +        mtu_opt->reserved = 0;
> +        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, 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;
> +    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->len = 4;
> +    prefix_opt->prefix_len = plen;
> +    prefix_opt->la_flags = la_flags;
> +    prefix_opt->valid_lifetime = valid_lifetime;
> +    prefix_opt->preferred_lifetime = preferred_lifetime;
> +    prefix_opt->reserved = 0;
> +    memcpy(prefix_opt->prefix.be32, prefix.be32, 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));
> +}
> +
>  uint32_t
>  packet_csum_pseudoheader(const struct ip_header *ip)
>  {
> diff --git a/lib/packets.h b/lib/packets.h
> index a5a483b..b285185 100644
> --- a/lib/packets.h
> +++ b/lib/packets.h
> @@ -858,6 +858,33 @@ struct ovs_nd_opt {
>  };
>  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;       /* The length of Prefix Information Option shoulud
> be 4. */
> +    uint8_t prefix_len;
> +    uint8_t  la_flags;  /* ND_PREFIX_ON_LINK and
> ND_PREFIX_AUTONOMOUS_ADDRESS flags. */
> +    ovs_be32 valid_lifetime;
> +    ovs_be32 preferred_lifetime;
> +    ovs_be32 reserved;  /* Always should be 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;       /* The length of MTU Option shoulud be 1. */
> +    ovs_be16 reserved;  /* Always should be 0. */
> +    ovs_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
> @@ -869,10 +896,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
> @@ -927,6 +970,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)
>  {
> @@ -1131,6 +1178,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_with_sll_mtu_opts(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);
>
> --
> 2.9.3
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox

Patch

diff --git a/lib/packets.c b/lib/packets.c
index 94e7d87..dbe5105 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)
@@ -1428,6 +1429,93 @@  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_with_sll_mtu_opts(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)
+{
+    struct ovs_ra_msg *ra;
+    struct ovs_nd_mtu_opt *mtu_opt;
+    struct ovs_nd_opt *lla_opt;
+    uint32_t icmp_csum;
+
+    /* 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);
+    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;
+
+    lla_opt = &ra->options[0];
+    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. */
+        mtu_opt = (struct ovs_nd_mtu_opt *)(lla_opt + 1);
+        mtu_opt->type = ND_OPT_MTU;
+        mtu_opt->len = 1;
+        mtu_opt->reserved = 0;
+        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, 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;
+    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->len = 4;
+    prefix_opt->prefix_len = plen;
+    prefix_opt->la_flags = la_flags;
+    prefix_opt->valid_lifetime = valid_lifetime;
+    prefix_opt->preferred_lifetime = preferred_lifetime;
+    prefix_opt->reserved = 0;
+    memcpy(prefix_opt->prefix.be32, prefix.be32, 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));
+}
+
 uint32_t
 packet_csum_pseudoheader(const struct ip_header *ip)
 {
diff --git a/lib/packets.h b/lib/packets.h
index a5a483b..b285185 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -858,6 +858,33 @@  struct ovs_nd_opt {
 };
 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;       /* The length of Prefix Information Option shoulud be 4. */
+    uint8_t prefix_len;
+    uint8_t  la_flags;  /* ND_PREFIX_ON_LINK and ND_PREFIX_AUTONOMOUS_ADDRESS flags. */
+    ovs_be32 valid_lifetime;
+    ovs_be32 preferred_lifetime;
+    ovs_be32 reserved;  /* Always should be 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;       /* The length of MTU Option shoulud be 1. */
+    ovs_be16 reserved;  /* Always should be 0. */
+    ovs_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
@@ -869,10 +896,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
@@ -927,6 +970,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)
 {
@@ -1131,6 +1178,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_with_sll_mtu_opts(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);