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 29 /* IPv4 ops */ 30 struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, 31 const struct flowi4 *fl4); 32 int (*l3mdev_get_saddr)(struct net_device *dev, 33 struct flowi4 *fl4); 34 35 /* IPv6 ops */ 36 struct dst_entry * (*l3mdev_get_rt6_dst)(const struct net_device *dev, 37 const struct flowi6 *fl6); 38 }; 39 40 #ifdef CONFIG_NET_L3_MASTER_DEV 41 42 int l3mdev_master_ifindex_rcu(struct net_device *dev); 43 static inline int l3mdev_master_ifindex(struct net_device *dev) 44 { 45 int ifindex; 46 47 rcu_read_lock(); 48 ifindex = l3mdev_master_ifindex_rcu(dev); 49 rcu_read_unlock(); 50 51 return ifindex; 52 } 53 54 /* get index of an interface to use for FIB lookups. For devices 55 * enslaved to an L3 master device FIB lookups are based on the 56 * master index 57 */ 58 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 59 { 60 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; 61 } 62 63 static inline int l3mdev_fib_oif(struct net_device *dev) 64 { 65 int oif; 66 67 rcu_read_lock(); 68 oif = l3mdev_fib_oif_rcu(dev); 69 rcu_read_unlock(); 70 71 return oif; 72 } 73 74 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 75 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 76 static inline u32 l3mdev_fib_table(const struct net_device *dev) 77 { 78 u32 tb_id; 79 80 rcu_read_lock(); 81 tb_id = l3mdev_fib_table_rcu(dev); 82 rcu_read_unlock(); 83 84 return tb_id; 85 } 86 87 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 88 const struct flowi4 *fl4) 89 { 90 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) 91 return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); 92 93 return NULL; 94 } 95 96 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 97 { 98 struct net_device *dev; 99 bool rc = false; 100 101 if (ifindex == 0) 102 return false; 103 104 rcu_read_lock(); 105 106 dev = dev_get_by_index_rcu(net, ifindex); 107 if (dev) 108 rc = netif_is_l3_master(dev); 109 110 rcu_read_unlock(); 111 112 return rc; 113 } 114 115 static inline int l3mdev_get_saddr(struct net *net, int ifindex, 116 struct flowi4 *fl4) 117 { 118 struct net_device *dev; 119 int rc = 0; 120 121 if (ifindex) { 122 123 rcu_read_lock(); 124 125 dev = dev_get_by_index_rcu(net, ifindex); 126 if (dev && netif_is_l3_master(dev) && 127 dev->l3mdev_ops->l3mdev_get_saddr) { 128 rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); 129 } 130 131 rcu_read_unlock(); 132 } 133 134 return rc; 135 } 136 137 static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 138 const struct flowi6 *fl6) 139 { 140 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rt6_dst) 141 return dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6); 142 143 return NULL; 144 } 145 146 static inline 147 struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net, 148 const struct flowi6 *fl6) 149 { 150 struct dst_entry *dst = NULL; 151 struct net_device *dev; 152 153 dev = dev_get_by_index(net, fl6->flowi6_oif); 154 if (dev) { 155 dst = l3mdev_get_rt6_dst(dev, fl6); 156 dev_put(dev); 157 } 158 159 return dst; 160 } 161 162 #else 163 164 static inline int l3mdev_master_ifindex_rcu(struct net_device *dev) 165 { 166 return 0; 167 } 168 static inline int l3mdev_master_ifindex(struct net_device *dev) 169 { 170 return 0; 171 } 172 173 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 174 { 175 return dev ? dev->ifindex : 0; 176 } 177 static inline int l3mdev_fib_oif(struct net_device *dev) 178 { 179 return dev ? dev->ifindex : 0; 180 } 181 182 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 183 { 184 return 0; 185 } 186 static inline u32 l3mdev_fib_table(const struct net_device *dev) 187 { 188 return 0; 189 } 190 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 191 { 192 return 0; 193 } 194 195 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 196 const struct flowi4 *fl4) 197 { 198 return NULL; 199 } 200 201 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 202 { 203 return false; 204 } 205 206 static inline int l3mdev_get_saddr(struct net *net, int ifindex, 207 struct flowi4 *fl4) 208 { 209 return 0; 210 } 211 212 static inline 213 struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 214 const struct flowi6 *fl6) 215 { 216 return NULL; 217 } 218 static inline 219 struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net, 220 const struct flowi6 *fl6) 221 { 222 return NULL; 223 } 224 #endif 225 226 #endif /* _NET_L3MDEV_H_ */ 227