1/* 2 ************************************************************************** 3 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all copies. 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 ************************************************************************** 15 */ 16 17/* 18 * nss_tun6rd.c 19 * 20 * This file is the NSS 6rd tunnel module 21 * ------------------------REVISION HISTORY----------------------------- 22 * Qualcomm Atheros 15/sep/2013 Created 23 */ 24 25#include <linux/version.h> 26#include <linux/types.h> 27#include <linux/ip.h> 28#include <linux/tcp.h> 29#include <linux/module.h> 30#include <linux/skbuff.h> 31#include <net/ipv6.h> 32#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,9,0)) 33#include <net/ipip.h> 34#else 35#include <net/ip_tunnels.h> 36#endif 37#include <linux/if_arp.h> 38#include <nss_api_if.h> 39#include <nss_dynamic_interface.h> 40 41/* 42 * NSS tun6rd debug macros 43 */ 44#if (NSS_TUN6RD_DEBUG_LEVEL < 1) 45#define nss_tun6rd_assert(fmt, args...) 46#else 47#define nss_tun6rd_assert(c) if (!(c)) { BUG_ON(!(c)); } 48#endif 49 50#if defined(CONFIG_DYNAMIC_DEBUG) 51/* 52 * Compile messages for dynamic enable/disable 53 */ 54#define nss_tun6rd_warning(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) 55#define nss_tun6rd_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) 56#define nss_tun6rd_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) 57#else 58 59/* 60 * Statically compile messages at different levels 61 */ 62#if (NSS_TUN6RD_DEBUG_LEVEL < 2) 63#define nss_tun6rd_warning(s, ...) 64#else 65#define nss_tun6rd_warning(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) 66#endif 67 68#if (NSS_TUN6RD_DEBUG_LEVEL < 3) 69#define nss_tun6rd_info(s, ...) 70#else 71#define nss_tun6rd_info(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) 72#endif 73 74#if (NSS_TUN6RD_DEBUG_LEVEL < 4) 75#define nss_tun6rd_trace(s, ...) 76#else 77#define nss_tun6rd_trace(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) 78#endif 79#endif 80 81/* 82 * 6rd tunnel stats 83 */ 84struct nss_tun6rd_stats { 85 uint32_t rx_packets; /* Number of received packets */ 86 uint32_t rx_bytes; /* Number of received bytes */ 87 uint32_t tx_packets; /* Number of transmitted packets */ 88 uint32_t tx_bytes; /* Number of transmitted bytes */ 89}; 90 91/* 92 * nss_tun6rd_update_dev_stats 93 * Update the Dev stats received from NetAp 94 */ 95static void nss_tun6rd_update_dev_stats(struct net_device *dev, 96 struct nss_tun6rd_sync_stats_msg *sync_stats) 97{ 98#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) 99 struct pcpu_sw_netstats stats; 100 101 u64_stats_init(&stats.syncp); 102 u64_stats_update_begin(&stats.syncp); 103 stats.rx_packets = sync_stats->node_stats.rx_packets; 104 stats.rx_bytes = sync_stats->node_stats.rx_bytes; 105 stats.tx_packets = sync_stats->node_stats.tx_packets; 106 stats.tx_bytes = sync_stats->node_stats.tx_bytes; 107 u64_stats_update_end(&stats.syncp); 108#else 109 struct nss_tun6rd_stats stats; 110 111 stats.rx_packets = sync_stats->node_stats.rx_packets; 112 stats.rx_bytes = sync_stats->node_stats.rx_bytes; 113 stats.tx_packets = sync_stats->node_stats.tx_packets; 114 stats.tx_bytes = sync_stats->node_stats.tx_bytes; 115#endif 116 117 ipip6_update_offload_stats(dev, (void *)&stats); 118} 119 120/* 121 * nss_tun6rd_event_receive() 122 * Event Callback to receive events from NSS 123 */ 124static void nss_tun6rd_event_receive(void *if_ctx, struct nss_tun6rd_msg *tnlmsg) 125{ 126 struct net_device *netdev = if_ctx; 127 128 switch (tnlmsg->cm.type) { 129 case NSS_TUN6RD_RX_STATS_SYNC: 130 nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_sync_stats_msg *)&tnlmsg->msg.stats); 131 break; 132 133 default: 134 nss_tun6rd_info("Unknown Event from NSS\n"); 135 break; 136 } 137} 138 139/* 140 * nss_tun6rd_exception() 141 * Exception handler registered to NSS driver 142 */ 143static void nss_tun6rd_exception(struct net_device *dev, struct sk_buff *skb, __attribute__((unused)) struct napi_struct *napi) 144{ 145 const struct iphdr *iph; 146 147 skb->dev = dev; 148 nss_tun6rd_info("received - %d bytes name %s ver %x\n", 149 skb->len,dev->name,skb->data[0]); 150 151 iph = (const struct iphdr *)skb->data; 152 153 /* 154 * Packet after Decap/Encap Did not find the Rule. 155 */ 156 if (iph->version != 4) { 157 skb->protocol = htons(ETH_P_IPV6); 158 } else { 159 if (iph->protocol == IPPROTO_IPV6) { 160 skb_pull(skb, sizeof(struct iphdr)); 161 skb->protocol = htons(ETH_P_IPV6); 162 skb_reset_network_header(skb); 163 skb->pkt_type = PACKET_HOST; 164 skb->ip_summed = CHECKSUM_NONE; 165 dev_queue_xmit(skb); 166 return; 167 } 168 skb->protocol = htons(ETH_P_IP); 169 } 170 171 skb_reset_network_header(skb); 172 skb->pkt_type = PACKET_HOST; 173 skb->skb_iif = dev->ifindex; 174 skb->ip_summed = CHECKSUM_NONE; 175 netif_receive_skb(skb); 176} 177 178/* 179 * nss_tun6rd_dev_up() 180 * 6RD Tunnel device i/f up handler 181 */ 182static int nss_tun6rd_dev_up(struct net_device *netdev) 183{ 184 struct ip_tunnel *tunnel; 185 struct ip_tunnel_6rd_parm *ip6rd; 186 const struct iphdr *tiph; 187 struct nss_tun6rd_msg tun6rdmsg; 188 struct nss_tun6rd_attach_tunnel_msg *tun6rdcfg; 189 uint32_t if_number; 190 nss_tx_status_t status; 191 struct nss_ctx_instance *nss_ctx; 192 uint32_t features = 0; /* features denote the skb types supported by this interface */ 193 194 /* 195 * Validate netdev for ipv6-in-ipv4 Tunnel 196 */ 197 if (netdev->type != ARPHRD_SIT) { 198 return NOTIFY_DONE; 199 } 200 201 tunnel = (struct ip_tunnel *)netdev_priv(netdev); 202 ip6rd = &tunnel->ip6rd; 203 204 /* 205 * Valid 6rd Tunnel Check 206 * 1. 6rd Prefix len should be non zero 207 * 2. Relay prefix length should not be greater then 32 208 * 3. To allow for stateless address auto-configuration on the CE LAN side, 209 * 6rd delegated prefix SHOULD be /64 or shorter. 210 */ 211 if ((ip6rd->prefixlen == 0 ) 212 || (ip6rd->relay_prefixlen > 32) 213 || (ip6rd->prefixlen 214 + (32 - ip6rd->relay_prefixlen) > 64)) { 215 216 nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n", 217 ip6rd->prefixlen,ip6rd->relay_prefixlen); 218 return NOTIFY_BAD; 219 } 220 221 nss_tun6rd_info("Valid 6rd Tunnel Prefix %x %x %x %x\n Prefix len %d relay_prefix %d relay_prefixlen %d \n", 222 ip6rd->prefix.s6_addr32[0],ip6rd->prefix.s6_addr32[1], 223 ip6rd->prefix.s6_addr32[2],ip6rd->prefix.s6_addr32[3], 224 ip6rd->prefixlen, ip6rd->relay_prefix, 225 ip6rd->relay_prefixlen); 226 227 /* 228 * Find the Tunnel device IP header info 229 */ 230 tiph = &tunnel->parms.iph ; 231 nss_tun6rd_trace("Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n", 232 tiph->saddr, tiph->daddr,tiph->ttl,tiph->tos); 233 234 if (tiph->saddr == 0) { 235 nss_tun6rd_warning("Tunnel src address not configured %x\n", 236 tiph->saddr); 237 return NOTIFY_BAD; 238 } 239 240 if_number = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD); 241 if (-1 == if_number) { 242 nss_tun6rd_warning("Request interface number failed\n"); 243 return NOTIFY_BAD; 244 } 245 246 /* 247 * Register 6rd tunnel with NSS 248 */ 249 nss_ctx = nss_register_tun6rd_if(if_number, 250 nss_tun6rd_exception, 251 nss_tun6rd_event_receive, 252 netdev, 253 features); 254 if (!nss_ctx) { 255 status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD); 256 if (status != NSS_TX_SUCCESS) { 257 nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number); 258 } 259 nss_tun6rd_trace("nss_register_tun6rd_if failed \n"); 260 return NOTIFY_BAD; 261 } 262 263 /* 264 * Prepare The Tunnel configuration parameter to send to nss 265 */ 266 memset(&tun6rdmsg, 0, sizeof(struct nss_tun6rd_msg)); 267 tun6rdcfg = &tun6rdmsg.msg.tunnel; 268 tun6rdcfg->prefixlen = ip6rd->prefixlen; 269 tun6rdcfg->relay_prefix = ip6rd->relay_prefix; 270 tun6rdcfg->relay_prefixlen = ip6rd->relay_prefixlen; 271 tun6rdcfg->saddr = ntohl(tiph->saddr); 272 tun6rdcfg->daddr = ntohl(tiph->daddr); 273 tun6rdcfg->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]); 274 tun6rdcfg->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]); 275 tun6rdcfg->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]); 276 tun6rdcfg->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]); 277 tun6rdcfg->ttl = tiph->ttl; 278 tun6rdcfg->tos = tiph->tos; 279 280 nss_tun6rd_trace(" 6rd Tunnel info\n"); 281 nss_tun6rd_trace(" saddr %x daddr %d ttl %x tos %x\n", 282 tiph->saddr, tiph->daddr, tiph->ttl, tiph->tos); 283 nss_tun6rd_trace(" Prefix %x:%x:%x:%x Prefix len %d\n", 284 ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1], 285 ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3], 286 ip6rd->prefixlen); 287 nss_tun6rd_trace("Relay Prefix %x Len %d\n", 288 ip6rd->relay_prefix, ip6rd->relay_prefixlen); 289 290 nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS %x\n", 291 (int)nss_ctx); 292 293 /* 294 * Send 6rd Tunnel UP command to NSS 295 */ 296 nss_tun6rd_msg_init(&tun6rdmsg, if_number, NSS_TUN6RD_ATTACH_PNODE, 297 sizeof(struct nss_tun6rd_attach_tunnel_msg), NULL, NULL); 298 299 status = nss_tun6rd_tx(nss_ctx, &tun6rdmsg); 300 if (status != NSS_TX_SUCCESS) { 301 nss_unregister_tun6rd_if(if_number); 302 status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD); 303 if (status != NSS_TX_SUCCESS) { 304 nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number); 305 } 306 nss_tun6rd_warning("Tunnel up command error %d\n", status); 307 return NOTIFY_BAD; 308 } 309 310 return NOTIFY_DONE; 311} 312 313/* 314 * nss_tun6rd_dev_down() 315 * 6RD Tunnel device i/f down handler 316 */ 317static int nss_tun6rd_dev_down(struct net_device *netdev) 318{ 319 struct ip_tunnel *tunnel; 320 struct ip_tunnel_6rd_parm *ip6rd; 321 int32_t if_number; 322 nss_tx_status_t status; 323 324 /* 325 * Validate netdev for ipv6-in-ipv4 Tunnel 326 */ 327 if (netdev->type != ARPHRD_SIT) { 328 return NOTIFY_DONE; 329 } 330 331 /* 332 * Check if tunnel 6rd is registered ? 333 */ 334 if_number = nss_cmn_get_interface_number_by_dev(netdev); 335 if (if_number < 0) { 336 nss_tun6rd_warning("Net device:%p is not registered \n",netdev); 337 return NOTIFY_BAD; 338 } 339 340 341 tunnel = (struct ip_tunnel *)netdev_priv(netdev); 342 ip6rd = &tunnel->ip6rd; 343 344 /* 345 * Valid 6rd Tunnel Check 346 */ 347 if ((ip6rd->prefixlen == 0 ) 348 || (ip6rd->relay_prefixlen > 32 ) 349 || (ip6rd->prefixlen 350 + (32 - ip6rd->relay_prefixlen) > 64)) { 351 352 nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n", 353 ip6rd->prefixlen,ip6rd->relay_prefixlen); 354 return NOTIFY_BAD; 355 } 356 357 /* 358 * Un-Register 6rd tunnel with NSS 359 */ 360 nss_unregister_tun6rd_if(if_number); 361 status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD); 362 if (status != NSS_TX_SUCCESS) { 363 nss_tun6rd_warning("Dealloc node failure\n"); 364 return NOTIFY_BAD; 365 } 366 367 return NOTIFY_DONE; 368} 369 370 371/* 372 * nss_tun6rd_dev_event() 373 * Net device notifier for 6rd module 374 */ 375static int nss_tun6rd_dev_event(struct notifier_block *nb, 376 unsigned long event, void *dev) 377{ 378#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0)) 379 struct net_device *netdev = (struct net_device *)dev; 380#else 381 struct net_device *netdev = netdev_notifier_info_to_dev(dev); 382#endif 383 384 switch (event) { 385 case NETDEV_UP: 386 nss_tun6rd_trace("NETDEV_UP: event %lu name %s\n", event, netdev->name); 387 return nss_tun6rd_dev_up(netdev); 388 389 case NETDEV_DOWN: 390 nss_tun6rd_trace("NETDEV_DOWN: event %lu name %s\n", event, netdev->name); 391 return nss_tun6rd_dev_down(netdev); 392 393 default: 394 nss_tun6rd_trace("Unhandled notifier event %lu name %s\n",event, netdev->name); 395 break; 396 } 397 398 return NOTIFY_DONE; 399} 400 401/* 402 * Linux Net device Notifier 403 */ 404struct notifier_block nss_tun6rd_notifier = { 405 .notifier_call = nss_tun6rd_dev_event, 406}; 407 408 409/* 410 * nss_tun6rd_init_module() 411 * Tunnel 6rd module init function 412 */ 413int __init nss_tun6rd_init_module(void) 414{ 415 nss_tun6rd_info("module (platform - IPQ806x , Build - %s:%s) loaded\n", 416 __DATE__, __TIME__); 417 418 register_netdevice_notifier(&nss_tun6rd_notifier); 419 nss_tun6rd_trace("Netdev Notifier registerd \n"); 420 421 return 0; 422} 423 424/* 425 * nss_tun6rd_exit_module() 426 * Tunnel 6rd module exit function 427 */ 428void __exit nss_tun6rd_exit_module(void) 429{ 430 unregister_netdevice_notifier(&nss_tun6rd_notifier); 431 nss_tun6rd_info("module unloaded\n"); 432} 433 434module_init(nss_tun6rd_init_module); 435module_exit(nss_tun6rd_exit_module); 436 437MODULE_LICENSE("Dual BSD/GPL"); 438MODULE_DESCRIPTION("NSS tun6rd offload manager"); 439