--- /dev/null
+diff --git a/acinclude.m4 b/acinclude.m4
+index 11c7787..07dd647 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -134,10 +134,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
+ AC_MSG_RESULT([$kversion])
+
+ if test "$version" -ge 4; then
+- if test "$version" = 4 && test "$patchlevel" -le 3; then
++ if test "$version" = 4 && test "$patchlevel" -le 4; then
+ : # Linux 4.x
+ else
+- AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 4.3.x is not supported (please refer to the FAQ for advice)])
++ AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 4.4.x is not supported (please refer to the FAQ for advice)])
+ fi
+ elif test "$version" = 3; then
+ : # Linux 3.x
+diff --git a/datapath/actions.c b/datapath/actions.c
+index 20413c9..719c43d 100644
+--- a/datapath/actions.c
++++ b/datapath/actions.c
+@@ -706,7 +706,8 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
+ skb_dst_set_noref(skb, &ovs_dst);
+ IPCB(skb)->frag_max_size = mru;
+
+- ip_do_fragment(skb->sk, skb, ovs_vport_output);
++ ip_do_fragment(NET_ARG(dev_net(ovs_dst.dev))
++ skb->sk, skb, ovs_vport_output);
+ refdst_drop(orig_dst);
+ } else if (ethertype == htons(ETH_P_IPV6)) {
+ const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
+@@ -727,7 +728,8 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
+ skb_dst_set_noref(skb, &ovs_rt.dst);
+ IP6CB(skb)->frag_max_size = mru;
+
+- v6ops->fragment(skb->sk, skb, ovs_vport_output);
++ v6ops->fragment(NET_ARG(dev_net(ovs_rt.dst.dev))
++ skb->sk, skb, ovs_vport_output);
+ refdst_drop(orig_dst);
+ } else {
+ WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
+diff --git a/datapath/conntrack.c b/datapath/conntrack.c
+index 795ed91..3b9bfba 100644
+--- a/datapath/conntrack.c
++++ b/datapath/conntrack.c
+@@ -323,7 +323,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
+ int err;
+
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+- err = ip_defrag(skb, user);
++ err = ip_defrag(NET_ARG(net) skb, user);
+ if (err)
+ return err;
+
+@@ -374,7 +374,7 @@ ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone,
+ {
+ struct nf_conntrack_tuple tuple;
+
+- if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, &tuple))
++ if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, NET_ARG(net) &tuple))
+ return NULL;
+ return __nf_ct_expect_find(net, zone, &tuple);
+ }
+diff --git a/datapath/datapath.c b/datapath/datapath.c
+index e3d3c8c..a4157f4 100644
+--- a/datapath/datapath.c
++++ b/datapath/datapath.c
+@@ -96,8 +96,12 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
+ static void ovs_notify(struct genl_family *family, struct genl_multicast_group *grp,
+ struct sk_buff *skb, struct genl_info *info)
+ {
+- genl_notify(family, skb, genl_info_net(info),
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++ genl_notify(family, skb, info, GROUP_ID(grp), GFP_KERNEL);
++#else
++ genl_notify(family, skb, genl_info_net(info),
+ info->snd_portid, GROUP_ID(grp), info->nlhdr, GFP_KERNEL);
++#endif
+ }
+
+ /**
+diff --git a/datapath/linux/compat/include/linux/netfilter_ipv6.h b/datapath/linux/compat/include/linux/netfilter_ipv6.h
+index 3939e14..b724623 100644
+--- a/datapath/linux/compat/include/linux/netfilter_ipv6.h
++++ b/datapath/linux/compat/include/linux/netfilter_ipv6.h
+@@ -13,7 +13,7 @@
+ * the callback parameter needs to be in the form that older kernels accept.
+ * We don't backport the other ipv6_ops as they're currently unused by OVS. */
+ struct ovs_nf_ipv6_ops {
+- int (*fragment)(struct sock *sk, struct sk_buff *skb,
++ int (*fragment)(NET_ARG(net) struct sock *sk, struct sk_buff *skb,
+ int (*output)(OVS_VPORT_OUTPUT_PARAMS));
+ };
+ #define nf_ipv6_ops ovs_nf_ipv6_ops
+diff --git a/datapath/linux/compat/include/net/ip.h b/datapath/linux/compat/include/net/ip.h
+index cd87bcc..b749301 100644
+--- a/datapath/linux/compat/include/net/ip.h
++++ b/datapath/linux/compat/include/net/ip.h
+@@ -66,8 +66,20 @@ static inline unsigned int rpl_ip_skb_dst_mtu(const struct sk_buff *skb)
+ #define ip_skb_dst_mtu rpl_ip_skb_dst_mtu
+ #endif /* HAVE_IP_SKB_DST_MTU */
+
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++#define NET_PARAM(x) struct net *x,
++#define NET_ARG(x) x,
++#define NET_DEV_NET(x) dev_net(x)
++#define NET_DECLARE_INIT(x,y)
++#else
++#define NET_PARAM(x)
++#define NET_ARG(x)
++#define NET_DEV_NET(x)
++#define NET_DECLARE_INIT(x,y) struct net *x = y;
++#endif
++
+ #ifdef HAVE_IP_FRAGMENT_TAKES_SOCK
+-#define OVS_VPORT_OUTPUT_PARAMS struct sock *sock, struct sk_buff *skb
++#define OVS_VPORT_OUTPUT_PARAMS NET_PARAM(net) struct sock *sock, struct sk_buff *skb
+ #else
+ #define OVS_VPORT_OUTPUT_PARAMS struct sk_buff *skb
+ #endif
+@@ -89,12 +101,13 @@ static inline bool ip_defrag_user_in_between(u32 user,
+ #endif /* < v4.2 */
+
+ #ifndef HAVE_IP_DO_FRAGMENT
+-static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb,
++static inline int rpl_ip_do_fragment(NET_PARAM(net) struct sock *sk, struct sk_buff *skb,
+ int (*output)(OVS_VPORT_OUTPUT_PARAMS))
+ {
+ unsigned int mtu = ip_skb_dst_mtu(skb);
+ struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = skb_rtable(skb);
++ NET_DECLARE_INIT(net, dev_net(dev));
+ struct net_device *dev = rt->dst.dev;
+
+ if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) ||
+@@ -102,7 +115,7 @@ static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb,
+ IPCB(skb)->frag_max_size > mtu))) {
+
+ pr_warn("Dropping packet in ip_do_fragment()\n");
+- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
++ IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
+ kfree_skb(skb);
+ return -EMSGSIZE;
+ }
+@@ -116,8 +129,7 @@ static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb,
+ #define ip_do_fragment rpl_ip_do_fragment
+ #endif /* IP_DO_FRAGMENT */
+
+-int rpl_ip_defrag(struct sk_buff *skb, u32 user);
+-#define ip_defrag rpl_ip_defrag
++int rpl_ip_defrag(NET_PARAM(net) struct sk_buff *skb, u32 user);
+
+ int __init rpl_ipfrag_init(void);
+ void rpl_ipfrag_fini(void);
+@@ -127,14 +139,15 @@ void rpl_ipfrag_fini(void);
+ * ("inet: frag: Always orphan skbs inside ip_defrag()"), but it should be
+ * always included in kernels 4.5+. */
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
+-static inline int rpl_ip_defrag(struct sk_buff *skb, u32 user)
++static inline int rpl_ip_defrag(NET_PARAM(net) struct sk_buff *skb, u32 user)
+ {
+ skb_orphan(skb);
+- return ip_defrag(skb, user);
++ return ip_defrag(NET_ARG(net) skb, user);
+ }
+-#define ip_defrag rpl_ip_defrag
+ #endif
+
++#define ip_defrag rpl_ip_defrag
++
+ static inline int rpl_ipfrag_init(void) { return 0; }
+ static inline void rpl_ipfrag_fini(void) { }
+ #endif /* HAVE_CORRECT_MRU_HANDLING && OVS_FRAGMENT_BACKPORT */
+diff --git a/datapath/linux/compat/include/net/ip6_tunnel.h b/datapath/linux/compat/include/net/ip6_tunnel.h
+index ce65087..eacf9ca 100644
+--- a/datapath/linux/compat/include/net/ip6_tunnel.h
++++ b/datapath/linux/compat/include/net/ip6_tunnel.h
+@@ -17,11 +17,15 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
+
+ pkt_len = skb->len - skb_inner_network_offset(skb);
+ /* TODO: Fix GSO for ipv6 */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++ err = ip6_local_out(dev_net(dev), sk, skb);
++#else
+ #ifdef HAVE_IP6_LOCAL_OUT_SK
+ err = ip6_local_out_sk(sk, skb);
+ #else
+ err = ip6_local_out(skb);
+ #endif
++#endif /* >= kernel 4.4 */
+ if (net_xmit_eval(err) != 0)
+ pkt_len = net_xmit_eval(err);
+ else
+diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
+index b50cd17..230f3ad 100644
+--- a/datapath/linux/compat/include/net/vxlan.h
++++ b/datapath/linux/compat/include/net/vxlan.h
+@@ -218,10 +218,20 @@ struct vxlan_dev {
+ struct net_device *rpl_vxlan_dev_create(struct net *net, const char *name,
+ u8 name_assign_type, struct vxlan_config *conf);
+
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++static inline __be16 vxlan_dev_dst_port(struct vxlan_dev *vxlan,
++ unsigned short family)
++{
++ if (family == AF_INET6)
++ return inet_sk(vxlan->vn6_sock->sock->sk)->inet_sport;
++ return inet_sk(vxlan->vn4_sock->sock->sk)->inet_sport;
++}
++#else
+ static inline __be16 vxlan_dev_dst_port(struct vxlan_dev *vxlan)
+ {
+ return inet_sport(vxlan->vn_sock->sock->sk);
+ }
++#endif
+
+ static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
+ netdev_features_t features)
+diff --git a/datapath/linux/compat/ip_fragment.c b/datapath/linux/compat/ip_fragment.c
+index cf2daaa..e168196 100644
+--- a/datapath/linux/compat/ip_fragment.c
++++ b/datapath/linux/compat/ip_fragment.c
+@@ -674,11 +674,11 @@ out_fail:
+ }
+
+ /* Process an incoming IP datagram fragment. */
+-int rpl_ip_defrag(struct sk_buff *skb, u32 user)
++int rpl_ip_defrag(NET_ARG(net) struct sk_buff *skb, u32 user)
+ {
+ struct net_device *dev = skb->dev ? : skb_dst(skb)->dev;
+ int vif = vrf_master_ifindex_rcu(dev);
+- struct net *net = dev_net(dev);
++ NET_DECLARE_INIT(net, dev_net(dev));
+ struct ipq *qp;
+
+ IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
+diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c
+index eb397e8..5ea3c52 100644
+--- a/datapath/linux/compat/stt.c
++++ b/datapath/linux/compat/stt.c
+@@ -1450,7 +1450,11 @@ static void clean_percpu(struct work_struct *work)
+ }
+
+ #ifdef HAVE_NF_HOOKFN_ARG_OPS
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++#define FIRST_PARAM void *priv
++#else
+ #define FIRST_PARAM const struct nf_hook_ops *ops
++#endif /* >= kernel 4.4 */
+ #else
+ #define FIRST_PARAM unsigned int hooknum
+ #endif
+@@ -1498,7 +1502,9 @@ static unsigned int nf_ip_hook(FIRST_PARAM, struct sk_buff *skb, LAST_PARAM)
+
+ static struct nf_hook_ops nf_hook_ops __read_mostly = {
+ .hook = nf_ip_hook,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0)
+ .owner = THIS_MODULE,
++#endif
+ .pf = NFPROTO_IPV4,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = INT_MAX,
+diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
+index c05f5d4..3cbb568 100644
+--- a/datapath/vport-vxlan.c
++++ b/datapath/vport-vxlan.c
+@@ -153,7 +153,12 @@ static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ {
+ struct vxlan_dev *vxlan = netdev_priv(vport->dev);
+ struct net *net = ovs_dp_get_net(vport->dp);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++ unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info);
++ __be16 dst_port = vxlan_dev_dst_port(vxlan, family);
++#else
+ __be16 dst_port = vxlan_dev_dst_port(vxlan);
++#endif
+ __be16 src_port;
+ int port_min;
+ int port_max;