1 /* 2 * include/net/l3mdev.h - L3 master device API 3 * Copyright (c) 2015 Cumulus Networks 4 * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 #ifndef _NET_L3MDEV_H_ 12 #define _NET_L3MDEV_H_ 13 14 /** 15 * struct l3mdev_ops - l3mdev operations 16 * 17 * @l3mdev_fib_table: Get FIB table id to use for lookups 18 * 19 * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device 20 * 21 * @l3mdev_get_saddr: Get source address for a flow 22 * 23 * @l3mdev_get_rt6_dst: Get cached IPv6 rt6_info (dst_entry) for device 24 */ 25 26 struct l3mdev_ops { 27 u32 (*l3mdev_fib_table)(const struct net_device *dev); 28 struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev, 29 struct sk_buff *skb, u16 proto); 30 31 /* IPv4 ops */ 32 struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, 33 const struct flowi4 *fl4); 34 int (*l3mdev_get_saddr)(struct net_device *dev, 35 struct flowi4 *fl4); 36 37 /* IPv6 ops */ 38 struct dst_entry * (*l3mdev_get_rt6_dst)(const struct net_device *dev, 39 const struct flowi6 *fl6); 40 }; 41 42 #ifdef CONFIG_NET_L3_MASTER_DEV 43 44 int l3mdev_master_ifindex_rcu(const struct net_device *dev); 45 static inline int l3mdev_master_ifindex(struct net_device *dev) 46 { 47 int ifindex; 48 49 rcu_read_lock(); 50 ifindex = l3mdev_master_ifindex_rcu(dev); 51 rcu_read_unlock(); 52 53 return ifindex; 54 } 55 56 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 57 { 58 struct net_device *dev; 59 int rc = 0; 60 61 if (likely(ifindex)) { 62 rcu_read_lock(); 63 64 dev = dev_get_by_index_rcu(net, ifindex); 65 if (dev) 66 rc = l3mdev_master_ifindex_rcu(dev); 67 68 rcu_read_unlock(); 69 } 70 71 return rc; 72 } 73 74 /* get index of an interface to use for FIB lookups. For devices 75 * enslaved to an L3 master device FIB lookups are based on the 76 * master index 77 */ 78 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 79 { 80 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; 81 } 82 83 static inline int l3mdev_fib_oif(struct net_device *dev) 84 { 85 int oif; 86 87 rcu_read_lock(); 88 oif = l3mdev_fib_oif_rcu(dev); 89 rcu_read_unlock(); 90 91 return oif; 92 } 93 94 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 95 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 96 static inline u32 l3mdev_fib_table(const struct net_device *dev) 97 { 98 u32 tb_id; 99 100 rcu_read_lock(); 101 tb_id = l3mdev_fib_table_rcu(dev); 102 rcu_read_unlock(); 103 104 return tb_id; 105 } 106 107 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 108 const struct flowi4 *fl4) 109 { 110 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) 111 return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); 112 113 return NULL; 114 } 115 116 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 117 { 118 struct net_device *dev; 119 bool rc = false; 120 121 if (ifindex == 0) 122 return false; 123 124 rcu_read_lock(); 125 126 dev = dev_get_by_index_rcu(net, ifindex); 127 if (dev) 128 rc = netif_is_l3_master(dev); 129 130 rcu_read_unlock(); 131 132 return rc; 133 } 134 135 int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4); 136 137 struct dst_entry *l3mdev_get_rt6_dst(struct net *net, const struct flowi6 *fl6); 138 139 static inline 140 struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) 141 { 142 struct net_device *master = NULL; 143 144 if (netif_is_l3_slave(skb->dev)) 145 master = netdev_master_upper_dev_get_rcu(skb->dev); 146 else if (netif_is_l3_master(skb->dev)) 147 master = skb->dev; 148 149 if (master && master->l3mdev_ops->l3mdev_l3_rcv) 150 skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); 151 152 return skb; 153 } 154 155 static inline 156 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 157 { 158 return l3mdev_l3_rcv(skb, AF_INET); 159 } 160 161 static inline 162 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 163 { 164 return l3mdev_l3_rcv(skb, AF_INET6); 165 } 166 167 #else 168 169 static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) 170 { 171 return 0; 172 } 173 static inline int l3mdev_master_ifindex(struct net_device *dev) 174 { 175 return 0; 176 } 177 178 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 179 { 180 return 0; 181 } 182 183 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 184 { 185 return dev ? dev->ifindex : 0; 186 } 187 static inline int l3mdev_fib_oif(struct net_device *dev) 188 { 189 return dev ? dev->ifindex : 0; 190 } 191 192 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 193 { 194 return 0; 195 } 196 static inline u32 l3mdev_fib_table(const struct net_device *dev) 197 { 198 return 0; 199 } 200 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 201 { 202 return 0; 203 } 204 205 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 206 const struct flowi4 *fl4) 207 { 208 return NULL; 209 } 210 211 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 212 { 213 return false; 214 } 215 216 static inline int l3mdev_get_saddr(struct net *net, int ifindex, 217 struct flowi4 *fl4) 218 { 219 return 0; 220 } 221 222 static inline 223 struct dst_entry *l3mdev_get_rt6_dst(struct net *net, const struct flowi6 *fl6) 224 { 225 return NULL; 226 } 227 228 static inline 229 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 230 { 231 return skb; 232 } 233 234 static inline 235 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 236 { 237 return skb; 238 } 239 #endif 240 241 #endif /* _NET_L3MDEV_H_ */ 242