diff mbox series

[ovs-dev] packets: Un-inline functions needed by DDlog.

Message ID 20201023230728.1520592-1-blp@ovn.org
State Accepted
Headers show
Series [ovs-dev] packets: Un-inline functions needed by DDlog. | expand

Commit Message

Ben Pfaff Oct. 23, 2020, 11:07 p.m. UTC
From: Leonid Ryzhyk <lryzhyk@vmware.com>

DDlog uses these functions from Rust, but Rust can't use inline
functions (since it doesn't compile C headers but only links
against a C-compatible ABI).  Thus, move the implementations
of these functions to a .c file.

I don't think any of these functions is likely to be an
important part of a "fast path" in OVS, but if that's wrong,
then we could take another approach.

Signed-off-by: Leonid Ryzhyk <lryzhyk@vmware.com>
Co-authored-by: Ben Pfaff <blp@ovn.org>
Signed-off-by: Ben Pfaff <blp@ovn.org>
---
This is preparation for the OVN ddlog work.

 lib/packets.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/packets.h | 97 ++++++---------------------------------------------
 2 files changed, 108 insertions(+), 86 deletions(-)

Comments

Numan Siddique Oct. 26, 2020, 9:17 a.m. UTC | #1
On Sat, Oct 24, 2020 at 4:38 AM Ben Pfaff <blp@ovn.org> wrote:
>
> From: Leonid Ryzhyk <lryzhyk@vmware.com>
>
> DDlog uses these functions from Rust, but Rust can't use inline
> functions (since it doesn't compile C headers but only links
> against a C-compatible ABI).  Thus, move the implementations
> of these functions to a .c file.
>
> I don't think any of these functions is likely to be an
> important part of a "fast path" in OVS, but if that's wrong,
> then we could take another approach.
>
> Signed-off-by: Leonid Ryzhyk <lryzhyk@vmware.com>
> Co-authored-by: Ben Pfaff <blp@ovn.org>
> Signed-off-by: Ben Pfaff <blp@ovn.org>

Acked-by: Numan Siddique <numans@ovn.org>

Thanks
Numan

> ---
> This is preparation for the OVN ddlog work.
>
>  lib/packets.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/packets.h | 97 ++++++---------------------------------------------
>  2 files changed, 108 insertions(+), 86 deletions(-)
>
> diff --git a/lib/packets.c b/lib/packets.c
> index 9d7cc502419d..4a7643c5dd3a 100644
> --- a/lib/packets.c
> +++ b/lib/packets.c
> @@ -75,6 +75,29 @@ dpid_from_string(const char *s, uint64_t *dpidp)
>      return *dpidp != 0;
>  }
>
> +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]));
> +}
> +
> +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_mark_random(struct eth_addr *ea)
> +{
> +    ea->ea[0] &= ~1;                /* Unicast. */
> +    ea->ea[0] |= 2;                 /* Private. */
> +}
> +
>  /* Returns true if 'ea' is a reserved address, that a bridge must never
>   * forward, false otherwise.
>   *
> @@ -524,6 +547,79 @@ eth_format_masked(const struct eth_addr eth,
>      }
>  }
>
> +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);
> +}
> +
> +/*
> + * Generates ipv6 EUI64 address from the given eth addr
> + * and prefix and stores it in 'lla'
> + */
> +void
> +in6_generate_eui64(struct eth_addr ea, const 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];
> +}
> +
> +/* Generates ipv6 link local address from the given eth addr
> + * with prefix 'fe80::/64' and stores it in 'lla'. */
> +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];
> +}
> +
> +/* Returns true if 'addr' is a link local address.  Otherwise, false. */
> +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
> +}
> +
> +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];
> +}
> +
>  /* Given the IP netmask 'netmask', returns the number of bits of the IP address
>   * that it specifies, that is, the number of 1-bits in 'netmask'.
>   *
> @@ -957,6 +1053,7 @@ eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
>      void *data;
>      struct eth_header *eth;
>
> +
>      dp_packet_clear(b);
>
>      /* The magic 2 here ensures that the L3 header (when it is added later)
> diff --git a/lib/packets.h b/lib/packets.h
> index 395bc869eb00..481bc22fa1fe 100644
> --- a/lib/packets.h
> +++ b/lib/packets.h
> @@ -281,12 +281,7 @@ static inline bool eth_addr_equal_except(const struct eth_addr a,
>               || ((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)
> @@ -294,12 +289,7 @@ static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea,
>      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)
>  {
> @@ -312,11 +302,7 @@ 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)
>  {
> @@ -1211,80 +1197,19 @@ in6_addr_get_mapped_ipv4(const struct in6_addr *addr)
>      }
>  }
>
> -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)
>  {
> --
> 2.26.2
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Ben Pfaff Oct. 26, 2020, 5:56 p.m. UTC | #2
On Mon, Oct 26, 2020 at 02:47:15PM +0530, Numan Siddique wrote:
> On Sat, Oct 24, 2020 at 4:38 AM Ben Pfaff <blp@ovn.org> wrote:
> >
> > From: Leonid Ryzhyk <lryzhyk@vmware.com>
> >
> > DDlog uses these functions from Rust, but Rust can't use inline
> > functions (since it doesn't compile C headers but only links
> > against a C-compatible ABI).  Thus, move the implementations
> > of these functions to a .c file.
> >
> > I don't think any of these functions is likely to be an
> > important part of a "fast path" in OVS, but if that's wrong,
> > then we could take another approach.
> >
> > Signed-off-by: Leonid Ryzhyk <lryzhyk@vmware.com>
> > Co-authored-by: Ben Pfaff <blp@ovn.org>
> > Signed-off-by: Ben Pfaff <blp@ovn.org>
> 
> Acked-by: Numan Siddique <numans@ovn.org>

Thanks!  Applied to master.
diff mbox series

Patch

diff --git a/lib/packets.c b/lib/packets.c
index 9d7cc502419d..4a7643c5dd3a 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -75,6 +75,29 @@  dpid_from_string(const char *s, uint64_t *dpidp)
     return *dpidp != 0;
 }
 
+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]));
+}
+
+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_mark_random(struct eth_addr *ea)
+{
+    ea->ea[0] &= ~1;                /* Unicast. */
+    ea->ea[0] |= 2;                 /* Private. */
+}
+
 /* Returns true if 'ea' is a reserved address, that a bridge must never
  * forward, false otherwise.
  *
@@ -524,6 +547,79 @@  eth_format_masked(const struct eth_addr eth,
     }
 }
 
+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);
+}
+
+/*
+ * Generates ipv6 EUI64 address from the given eth addr
+ * and prefix and stores it in 'lla'
+ */
+void
+in6_generate_eui64(struct eth_addr ea, const 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];
+}
+
+/* Generates ipv6 link local address from the given eth addr
+ * with prefix 'fe80::/64' and stores it in 'lla'. */
+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];
+}
+
+/* Returns true if 'addr' is a link local address.  Otherwise, false. */
+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
+}
+
+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];
+}
+
 /* Given the IP netmask 'netmask', returns the number of bits of the IP address
  * that it specifies, that is, the number of 1-bits in 'netmask'.
  *
@@ -957,6 +1053,7 @@  eth_compose(struct dp_packet *b, const struct eth_addr eth_dst,
     void *data;
     struct eth_header *eth;
 
+
     dp_packet_clear(b);
 
     /* The magic 2 here ensures that the L3 header (when it is added later)
diff --git a/lib/packets.h b/lib/packets.h
index 395bc869eb00..481bc22fa1fe 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -281,12 +281,7 @@  static inline bool eth_addr_equal_except(const struct eth_addr a,
              || ((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)
@@ -294,12 +289,7 @@  static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea,
     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)
 {
@@ -312,11 +302,7 @@  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)
 {
@@ -1211,80 +1197,19 @@  in6_addr_get_mapped_ipv4(const struct in6_addr *addr)
     }
 }
 
-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)
 {