├── pics └── sim_topology.png ├── Thesis └── 17Mar_Lukaszewski_Daniel.pdf ├── shell ├── bridge │ ├── network_start.conf │ ├── tc_param.sh │ ├── bridge_tcp_dump.sh │ ├── tc_qdisc.sh │ └── network_start.sh ├── web │ ├── web_tcp_dump.sh │ ├── directory_sym.sh │ └── directory_asym.sh ├── client │ ├── download.sh │ └── vpnstart.sh ├── server │ ├── tcp_dump.sh │ ├── asym_test.sh │ ├── symm_test.sh │ ├── asym_supertest.sh │ └── supertest.sh └── README.md ├── Usenix └── CSET-17 ├── c_files ├── Makefile ├── README.md ├── MPUDP_recv.c ├── MPUDP_send.c └── udp.c ├── config ├── README.md ├── client.ovpn └── server.ovpn ├── python_scripts ├── README.md ├── parser_asym.py ├── parser_cubic_balia_mpudp.py ├── parser_ndiff_norm.py └── parser_fullmesh_norm.py └── README.md /pics/sim_topology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danluke2/mpudp_vpn_thesis/HEAD/pics/sim_topology.png -------------------------------------------------------------------------------- /Thesis/17Mar_Lukaszewski_Daniel.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danluke2/mpudp_vpn_thesis/HEAD/Thesis/17Mar_Lukaszewski_Daniel.pdf -------------------------------------------------------------------------------- /shell/bridge/network_start.conf: -------------------------------------------------------------------------------- 1 | description "Initialize network bridge on startup" 2 | 3 | start on startup 4 | task 5 | exec /home/bridge0/Documents/network_start.sh 6 | -------------------------------------------------------------------------------- /Usenix/CSET-17: -------------------------------------------------------------------------------- 1 | For a follow on paper with additional testing, please see my Usenix CSET-17 paper. 2 | 3 | https://www.usenix.org/system/files/conference/cset17/cset17-paper-lukaszewski.pdf 4 | 5 | 6 | -------------------------------------------------------------------------------- /shell/web/web_tcp_dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #start tcpdump and capture the first 150 bytes to minimize PCAP size 4 | 5 | 6 | nohup tcpdump -s 150 -i eth4 -w $1_Web_eth4.pcap &>/dev/null & sleep 5 7 | 8 | 9 | -------------------------------------------------------------------------------- /c_files/Makefile: -------------------------------------------------------------------------------- 1 | obj-m+=MPUDP_send.o 2 | obj-m+=MPUDP_recv.o 3 | 4 | 5 | all: 6 | make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules 7 | 8 | clean: 9 | make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean 10 | -------------------------------------------------------------------------------- /shell/web/directory_sym.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Purpose: create the directories needed for the symmetric tests 4 | 5 | mkdir run 6 | chmod +777 run 7 | cd test/ 8 | for dir in 0% 0.1% 0.5% 1% 9 | do 10 | mkdir $dir 11 | chmod +777 $dir 12 | done 13 | 14 | 15 | -------------------------------------------------------------------------------- /shell/client/download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | #Purpose: perform 10 downloads of test file 5 | #could change 10 to be shell variable 6 | 7 | 8 | 9 | echo starting downloads 10 | 11 | for i in {1..10}; do 12 | wget -q http://10.8.3.3/test/test16.txt -O /dev/null; 13 | 14 | done 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /shell/bridge/tc_param.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #set loss and delay on specified interface 4 | # $1 is add, change, del 5 | # $2 is interface id (ex: eth0) 6 | # $3 is packet delay (ex: 5ms) 7 | # $4 is loss rate (ex: 1%) 8 | 9 | echo Setting Loss and Delay on interface 10 | 11 | tc qdisc $1 dev $2 root netem delay $3 loss $4 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /shell/server/tcp_dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Purpose: start tcpdump capturing on all interfaces with size of 150 to limit PCAP size 4 | #Note: may need to adjust to capture specific interface(s) depending on test running 5 | #Note: could make “any” a shell variable to allow changing easily 6 | 7 | 8 | tcpdump -i any -s 150 -w $1_any.pcap& 9 | 10 | 11 | -------------------------------------------------------------------------------- /shell/web/directory_asym.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Purpose: create the directories needed for the asymmetric tests 4 | 5 | mkdir test 6 | chmod +777 test 7 | cd test/ 8 | for dir in $1_0_even $1_P1_even $1_P5_even $1_1P_even $1_0_mod $1_P1_mod $1_P5_mod $1_1P_mod $1_0_sev $1_P1_sev $1_P5_sev $1_1P_sev 9 | do 10 | mkdir $dir 11 | chmod +777 $dir 12 | done 13 | 14 | 15 | -------------------------------------------------------------------------------- /shell/client/vpnstart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Purpose: start up the VPN connection to the server and capture one download to verify proper operation 4 | 5 | 6 | tcpdump -i any -w $1_Init.pcap& 7 | 8 | nohup openvpn --config /etc/openvpn/client.ovpn& 9 | 10 | sleep 15 11 | 12 | wget -q http://10.8.3.3/test/test16.txt -O /dev/null; 13 | 14 | sleep 5 15 | 16 | pkill tcpdump 17 | 18 | -------------------------------------------------------------------------------- /shell/bridge/bridge_tcp_dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #start tcpdump on each bridge and capture first 150 Bytes to keep PCAP size smaller 4 | #may want to adjust size to ensure all data is encrypted over tunnel for familiarization testing 5 | 6 | 7 | nohup tcpdump -s 150 -i br1 -w $1_Bridge_br1.pcap &>/dev/null & sleep 5 8 | 9 | 10 | nohup tcpdump -s 150 -i br0 -w $1_Bridge_br0.pcap &>/dev/null & sleep 5 11 | -------------------------------------------------------------------------------- /config/README.md: -------------------------------------------------------------------------------- 1 | This folder holds the OpenVPN config files used for the tests. You need to generate the necessary certificates between the client and 2 | server and add them to the files or provide the path to them. 3 | 4 | I used this website to quickly set up OpenVPN and generate the certs: 5 | https://www.tinfoilsecurity.com/blog/dont-get-pwned-on-public-wifi-use-your-own-vpn-tutorial-guide-how-to 6 | 7 | 8 | Also, make sure your OpenVPN is up to date: 9 | https://feliciano.tech/blog/install-recent-openvpn-on-ubuntu-14-04/ 10 | -------------------------------------------------------------------------------- /config/client.ovpn: -------------------------------------------------------------------------------- 1 | client 2 | nobind 3 | dev tun 4 | #redirect-gateway def1 bypass-dhcp 5 | remote 10.8.1.11 1000 udp 6 | #remote 10.8.1.11 443 tcp 7 | 8 | 9 | 10 | #extra stuff, adjust how you want 11 | #comp-lzo yes 12 | cipher none 13 | 14 | 15 | 16 | 17 | 18 | -----BEGIN RSA PRIVATE KEY----- 19 | 20 | 21 | #add you key here 22 | 23 | 24 | -----END RSA PRIVATE KEY----- 25 | 26 | 27 | 28 | 29 | -----BEGIN CERTIFICATE----- 30 | 31 | 32 | #add your cert here 33 | 34 | 35 | -----END CERTIFICATE----- 36 | 37 | 38 | 39 | 40 | -----BEGIN CERTIFICATE----- 41 | 42 | 43 | #add your cert here 44 | 45 | 46 | -----END CERTIFICATE----- 47 | 48 | 49 | #daemon 50 | -------------------------------------------------------------------------------- /python_scripts/README.md: -------------------------------------------------------------------------------- 1 | This folder has the various Python scripts used to analyze 2 | the tests and generate the graphs used. These scripts 3 | could be optimized further since they have a lot of repeated 4 | code. If you would like to submit new code, I would be happy 5 | to update. Here is a brief overview of the 6 | scripts: 7 | 8 | * **parser\_cubic\_balia\_mpudp.py:** Python script used to 9 | parse csv files and produce bar graphs from Sections 10 | 3.1.4, 3.1.5, and 4.2. 11 | 12 | * **parser\_fullmesh\_norm.py** and **parser\_ndiff\_norm.py:** 13 | Python script used for producing the subflow 14 | Figures 3.7 and 3.8. 15 | 16 | * **parser\_asym.py:** Python script used for producing 17 | asymmetric Figure 3.9. 18 | 19 | -------------------------------------------------------------------------------- /shell/bridge/tc_qdisc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Purpose: echo to status file the current settings on each interface to allow debugging 4 | 5 | echo ***** START ***** $1 ***** >> /home/bridge0/Documents/log/status_$2 6 | 7 | echo ETH2 Qdisc >> /home/bridge0/Documents/log/status_$2 8 | tc qdisc show dev eth2 >> /home/bridge0/Documents/log/status_$2 9 | 10 | echo ETH3 Qdisc >> /home/bridge0/Documents/log/status_$2 11 | tc qdisc show dev eth3 >> /home/bridge0/Documents/log/status_$2 12 | 13 | echo ETH9 Qdisc >> /home/bridge0/Documents/log/status_$2 14 | tc qdisc show dev eth9 >> /home/bridge0/Documents/log/status_$2 15 | 16 | echo ETH10 Qdisc >> /home/bridge0/Documents/log/status_$2 17 | tc qdisc show dev eth10 >> /home/bridge0/Documents/log/status_$2 18 | 19 | echo ***** $1 ***** FINISH ***** >> /home/bridge0/Documents/log/status_$2 20 | 21 | echo >> /home/bridge0/Documents/log/status_$2 22 | 23 | 24 | -------------------------------------------------------------------------------- /shell/bridge/network_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #sets up the required bridges for testing 4 | #depending on the interfaces used (i.e. physical, usb ethernet, etc.), may need to adjust 5 | #script to ensure speeds are set properly and bridges are set up correctly 6 | #sleep timers inserted to allow interfaces to be recongnized prior to configuring bridges 7 | 8 | #bridges need an IP address to allow SSH connections and starting/stopping TCP dumps 9 | 10 | 11 | sleep 10 12 | 13 | ifconfig eth2 0.0.0.0 up 14 | ifconfig eth3 0.0.0.0 up 15 | brctl addbr br0 16 | brctl addif br0 eth2 17 | brctl addif br0 eth3 18 | ifconfig br0 up 19 | ifconfig br0 10.8.2.220 netmask 255.255.255.0 20 | 21 | sleep 10 22 | 23 | ifconfig eth9 0.0.0.0 up 24 | ifconfig eth10 0.0.0.0 up 25 | brctl addbr br1 26 | brctl addif br1 eth9 27 | brctl addif br1 eth10 28 | ifconfig br1 up 29 | ifconfig br1 10.8.1.110 netmask 255.255.255.0 30 | 31 | 32 | ethtool -s eth2 speed 10 duplex full autoneg on 33 | ethtool -s eth3 speed 10 duplex full autoneg on 34 | ethtool -s eth9 speed 10 duplex full autoneg on 35 | ethtool -s eth10 speed 10 duplex full autoneg on 36 | -------------------------------------------------------------------------------- /config/server.ovpn: -------------------------------------------------------------------------------- 1 | server 10.8.0.0 255.255.255.0 2 | verb 3 3 | #duplicate-cn 4 | key server-key.pem 5 | ca ca-cert.pem 6 | cert server-cert.pem 7 | dh dh.pem 8 | keepalive 10 60 9 | persist-key yes 10 | persist-tun yes 11 | 12 | 13 | 14 | push "redirect-gateway def1" 15 | push "redirect-gateway bypass-dhcp" 16 | push "route-metric 512" 17 | push "route 0.0.0.0 0.0.0.0" 18 | 19 | #windows stuff 20 | user nobody 21 | group nogroup 22 | 23 | 24 | #proto tcp 25 | proto udp 26 | #port 443 27 | port 1000 28 | dev tun443 29 | log-append /etc/openvpn/thesis.log 30 | status openvpnS-status-443.log 31 | 32 | 33 | 34 | #extra stuff 35 | cipher none 36 | #comp-lzo yes 37 | #push "dhcp-option DNS 8.8.8.8" 38 | #push "dhcp-option DNS 8.8.4.4" 39 | 40 | 41 | # Normally, the following command is sufficient. 42 | # However, it doesn't assign a gateway when using 43 | # VMware guest-only networking. 44 | # 45 | #push "redirect-gateway def1 bypass-dhcp" 46 | #push "redirect-gateway local def1" 47 | -------------------------------------------------------------------------------- /c_files/README.md: -------------------------------------------------------------------------------- 1 | To implement the MPUDP protocol, we chose to use two 2 | Linux kernel modules in conjunction with a modification 3 | to the UDP kernel file. This method is similar to the 4 | MPTCP implementation. We used multiple kernel modules 5 | in order to simplify the design and clearly delineate the 6 | purpose of each module. We will now provide a description 7 | of the C files used for implementing the MPUDP protocol. 8 | 9 | __MPUDP C Files:__ 10 | 11 | * **udp.c:** ORIGINAL FILE THAT NO LONGER WORKS FOR COMPILING: 12 | The udp.c file is found in directory 13 | \net\ipv4\ . This file was modified to include branches 14 | in the udp\_recmsg and udp\_sendmsg functions. Code was 15 | also added to export symbols of functions used in the 16 | kernel modules. 17 | 18 | * **udp_updated.c:** Rename to udp.c when inserting: 19 | The udp.c file is found in directory 20 | \net\ipv4\ . This file was modified to include branches 21 | in the udp\_recmsg and udp\_sendmsg functions. Code was 22 | also added to export symbols of functions used in the 23 | kernel modules. 24 | 25 | * **MPUDP\_send.c:** This was the kernel module used to 26 | implement the MPUDP send function called in the 27 | udp\_sendmsg function. 28 | 29 | * **MPUDP\_recv.c:** This was the kernel module used to 30 | implement the MPUDP receive function called in the 31 | udp\_recmsg function. 32 | 33 | * **Makefile:** Creates the kernel object files from the 34 | MPUDP\_send.c and MPUDP\_recv.c files. The ".ko" files 35 | are the kernel files inserted to allow for the MPUDP 36 | functions to work. 37 | -------------------------------------------------------------------------------- /shell/server/asym_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | #Parameters: 5 | #$1 is primary link delay (includes ms) 6 | #$2 is sec link delay (includes ms) 7 | #$3 is pri link loss 8 | #$4 is sec link loss 9 | #$5 is folder label 10 | 11 | 12 | 13 | 14 | #test with $1, $2 delays and $3,$4 loss******************************************************************************* 15 | echo Test Starting with $1 and $2 Delays $3 and $4 Loss >> /home/vpnserver/Documents/log/status_asym 16 | 17 | 18 | 19 | #Bridge: make changes to delay rate 20 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridge0/Documents/tc_param.sh change eth2 $2 $4; /home/bridge0/Documents/tc_param.sh change eth3 $2 $4; /home/bridge0/Documents/tc_param.sh change eth9 $1 $3; /home/bridge0/Documents/tc_param.sh change eth10 $1 $3; /home/bridge0/Documents/tc_qdisc.sh $1 $3; exit" 21 | 22 | 23 | cd /home/vpnserver/Documents/test/$5/ 24 | #start tcpdump on each interface 25 | tcpdump -i any -s 150 -w $1_$delay_any_$i.pcap& 26 | 27 | 28 | sleep 2 29 | 30 | 31 | #start tcpdumps on Web 32 | sshpass -p "mptcp11" ssh -p 22 root@10.8.3.3 "cd /home/web/Documents/test/$5/; /home/web/Documents/web_tcp_dump.sh asym; exit" 33 | 34 | 35 | #perform downloads on Client 36 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "/home/client/Documents/download.sh; exit" 37 | 38 | 39 | 40 | sleep 2 41 | 42 | 43 | #kill local tcpdump 44 | pkill tcpdump 45 | 46 | 47 | sleep 2 48 | 49 | #kill tcpdump on web and run t-shark analysis 50 | sshpass -p "mptcp11" ssh -p 22 root@10.8.3.3 "pkill tcpdump; sleep 2; cd /home/web/Documents/test/$5/; tshark -r asym_Web_eth4.pcap -q -z conv,tcp > $5.csv; wait; exit" 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /c_files/MPUDP_recv.c: -------------------------------------------------------------------------------- 1 | /* MPUDP_recv.c 2 | * Author: Daniel Lukaszewski 3 | * Date Last Modified: 2/16/17 4 | * 5 | * This program provides functions for the MPUDP kernel testing. Comment 6 | * out client and server code depending on machine. 7 | * 8 | * path_recv_manager: ensures packets coming in arrive with proper dest 9 | * ip for OpenVPN to recognize as same connection 10 | * (kind of like MPTCP joining subflows) 11 | */ 12 | 13 | #define MODULE 14 | 15 | #include 16 | #include /* for struct sockaddr_in */ 17 | 18 | extern void (*mpudp_recv_function)(struct sockaddr_in *); /* calling function */ 19 | 20 | /************************************************************ path_manager*/ 21 | 22 | 23 | //replace vpn server address to master source address 24 | void path_recv_manager(struct sockaddr_in * sin) { 25 | //printk("<1> $$ calling new in function\n"); 26 | //client code: 27 | if (sin->sin_addr.s_addr==0x0B01080A) { 28 | sin->sin_addr.s_addr=0x1602080A; 29 | } 30 | //server code: 31 | //if (sin->sin_addr.s_addr==0x0101080A) { 32 | //sin->sin_addr.s_addr=0x0202080A; 33 | //} 34 | } 35 | 36 | /*************************************************************** init_module 37 | * this function replaces the null pointer with a real one */ 38 | int init_module() { 39 | mpudp_recv_function = path_recv_manager; 40 | printk("<1> $$ recv module created\n"); 41 | return 0; 42 | } /* init_module */ 43 | 44 | /************************************************************ cleanup_module 45 | * this function resets the function pointer back to null */ 46 | void cleanup_module() { 47 | mpudp_recv_function = 0; 48 | printk("<1> $$ recv module removed\n"); 49 | } /* cleanup_module */ 50 | -------------------------------------------------------------------------------- /c_files/MPUDP_send.c: -------------------------------------------------------------------------------- 1 | /* MPUDP_send.c 2 | * Author: Daniel Lukaszewski 3 | * Date Last Modified: 2/16/17 4 | * 5 | * This program provides functions for the MPUDP kernel testing. Comment 6 | * out client and server code depending on machine. 7 | * 8 | * path_manager: checks address and changes to alternate 50% of time 9 | */ 10 | 11 | #define MODULE 12 | #define MAX_UNSIGNED_SHORT 65535 13 | 14 | #include 15 | #include /* for struct sockaddr_in */ 16 | 17 | extern int (*mpudp_send_function)(struct sockaddr_in *); /* calling function */ 18 | extern void get_random_bytes(void *buf, int nbytes); /* random function */ 19 | 20 | /************************************************************ path_manager*/ 21 | int path_manager(struct sockaddr_in * usin) { 22 | unsigned short t; 23 | //printk("<1> $$ calling new function\n"); 24 | //client code: 25 | if (usin->sin_addr.s_addr==0x1602080A) { 26 | get_random_bytes(&t,2); 27 | if (t<=16383) { 28 | usin->sin_addr.s_addr=0x0B01080A; 29 | return 1; /* read dest addr after change */ 30 | } 31 | //server code: 32 | //if (usin->sin_addr.s_addr==0x0202080A) { 33 | //get_random_bytes(&t,2); 34 | //if (t<=16383) { 35 | //usin->sin_addr.s_addr=0x0101080A; 36 | //return 1; /* read dest addr after change */ 37 | //} 38 | } 39 | return 0; 40 | } 41 | 42 | 43 | /*************************************************************** init_module 44 | * this function replaces the null pointer with a real one */ 45 | int init_module() { 46 | mpudp_send_function = path_manager; 47 | printk("<1> $$ send module created\n"); 48 | return 0; 49 | } /* init_module */ 50 | 51 | /************************************************************ cleanup_module 52 | * this function resets the function pointer back to null */ 53 | void cleanup_module() { 54 | mpudp_send_function = 0; 55 | printk("<1> $$ send module removed\n"); 56 | } /* cleanup_module */ 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mpudp_vpn_thesis 2 | This project is a result of my Master's thesis from Naval Postgraduate School. This thesis involved adding a simplified MPUDP protocol to the existing MPTCP Linux kernel and testing MPTCP and MPUDP performance with OpenVPN. I have provided the shell scripts, code, and my thesis to allow anyone to replicate my work as well as contribute to the MPUDP protocol. 3 | 4 | 5 | This project relies on the MPTCP kernel available here:https://github.com/multipath-tcp/mptcp 6 | 7 | I changed the udp.c file to allow for MPUDP between the VPN client and server. Simply replace the \net\ipv4\udp.c file with my file and compile the kernel as described by the MPTCP page. 8 | 9 | There are 2 Linux kernel modules needed to allow for MPUDP testing (located in c_files): 10 | 11 | * **MPUDP_recv:** allows for changing the source address of incoming packets to the "master" flow address. This is needed for OpenVPN to prevent dropping packets from an unknown source. 12 | 13 | * **MPUDP_send:** allows for probabilistically changing the destination of outgoing packets. By changing the destination to an alternate address, the packets will be routed over each path available. 14 | 15 | 16 | The topology used for testing can be built physically or through VM's. All shell code provided is from the physical testbed. You can modify the code to work better in a virtual environment since you can use a centralized shared folder to hold the test files and results. The topology used is as follows: 17 | 18 | ![Alt text](/pics/sim_topology.png?raw=true) 19 | 20 | 21 | The IP addresses used during the testing were as follows: 22 | 23 | * **Client:** 24 | * Primary Link: 10.8.1.1 25 | * Secondary Link: 10.8.2.2 26 | * VPN Link: 10.8.0.6 27 | 28 | 29 | * **Server:** 30 | * Primary Link: 10.8.1.11 31 | * Secondary Link: 10.8.2.22 32 | * Web Link: 10.8.3.33 33 | * VPN Link: 10.8.0.1 34 | 35 | 36 | * **Web:** 10.8.3.3 37 | 38 | * **Primary Bridge:** 10.8.1.110 39 | 40 | * **Secondary Bridge:** 10.8.2.220 41 | -------------------------------------------------------------------------------- /shell/README.md: -------------------------------------------------------------------------------- 1 | This is where you find the necessary shell scripts to run the tests used 2 | in my thesis. Here is a breakdown of what each script does: 3 | 4 | 5 | __VPN Client Scripts:__ 6 | 7 | * item **vpnstart.sh:** Allows for starting the client side VPN 8 | remotely from the server using an SSH connection. 9 | The script will start a Wireshark capture, initiate 10 | the tunnel connection, and then conduct a test download. 11 | The Wireshark capture allows for verifying the VPN tunnel 12 | behaves as expected for the desired test. 13 | 14 | 15 | * item **download.sh:** Allows for initiating the 10 downloads 16 | using *wget* in quiet mode. This script could easily be 17 | adjusted to perform any number of downloads required. 18 | Quiet mode was used to prevent unnecessary download 19 | statistics being reported to the server via the SSH connection. 20 | 21 | 22 | 23 | __VPN Server Scripts:__ 24 | 25 | 26 | * **supertest.sh:** This was the master script for conducting 27 | the symmetric tests of Sections 3.1.4, 3.1.5, and 4.2. 28 | The script allowed for command line arguments to test 29 | MPTCP, MPUDP, TCP, or UDP. The user must also specify 30 | the desired TCP congestion control algorithm to use. This 31 | script allowed for ensuring each test had the same starting 32 | parameters and was conducted properly. 33 | 34 | 35 | * **symm_test.sh:** Called by the supertest.sh script to 36 | conduct the required tests. 37 | 38 | * **asym_supertest.sh:** Similar to the symmetric 39 | supertest, but for conducting asymmetric testing of 40 | Section 3.1.6. 41 | 42 | 43 | * **asym\_test.sh:** Called by the asym_supertest.sh script 44 | to conduct the required tests. 45 | 46 | 47 | * **subflow_supertest.sh:** This is the master script for 48 | conducting the subflow tests of Section 3.1.5. 49 | 50 | 51 | * **sub_test.sh** Called by the subflow_supertest.sh script 52 | to conduct the required tests. 53 | 54 | * **tcp_dump.sh:** Starts the required Wireshark captures 55 | for the test. 56 | 57 | 58 | 59 | __Web Server Scripts:__ 60 | 61 | 62 | * **directory_sym.sh** and **directory_asym.sh:** Creates the 63 | required directories automatically for storing the test data. 64 | This could be done by the user manually, but problems 65 | result if the user forgets to build all required directories. 66 | 67 | 68 | * **web_tcp_dump.sh:** Starts the required Wireshark captures 69 | for the test. 70 | 71 | 72 | 73 | __Bridge Machine Scripts:__ 74 | 75 | 76 | * **network_start.sh:** This script was run on machine 77 | start-up in order to initialize the required bridges 78 | between the interfaces. This script also set the 79 | required speed limits for the interfaces. To run this 80 | script at start-up, a configuration file was used. 81 | 82 | * **tc\_qdisc.sh:** Show and record the traffic control 83 | settings on each interface. Allowed for verifying the 84 | proper settings were in place during each round of testing. 85 | 86 | 87 | * **tc\_param.sh:** Used to add, change, or delete traffic 88 | control loss rates or delay rates for each interface. 89 | 90 | 91 | * **bridge\_tcp\_dump.sh:** Starts the required Wireshark 92 | captures for the test. These Wireshark captures were 93 | primarily used during initial testing to verify traffic 94 | was using the VPN tunnel as desired. 95 | 96 | -------------------------------------------------------------------------------- /shell/server/symm_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | #Parameters: 5 | #1 is test type: fullmesh, ndiffports, etc. 6 | #2 is packet loss rate 7 | 8 | 9 | 10 | #Bridge: ensure tc is set up prior to conducting tests 11 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridge0/Documents/tc_param.sh add eth2 0ms $2; /home/bridge0/Documents/tc_param.sh add eth3 0ms $2; /home/bridge0/Documents/tc_param.sh add eth9 0ms $2; /home/bridge0/Documents/tc_param.sh add eth10 0ms $2; /home/bridge0/Documents/tc_qdisc.sh 0ms $1; exit" 12 | 13 | 14 | 15 | #$1 test with $2 loss******************************************************************************* 16 | echo $1 Test Starting with $2 Loss >> /home/vpnserver/Documents/log/status_$1 17 | 18 | 19 | cd /home/vpnserver/Documents/run/$2/ 20 | 21 | 22 | #print tc status for reference 23 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "cd /home/bridge0/Documents/$2/; /home/bridge0/Documents/tc_qdisc.sh 0ms $1; exit" 24 | 25 | 26 | #start tcpdump on each interface 27 | /home/vpnserver/Documents/tcp_dump.sh $1 28 | 29 | sleep 2 30 | 31 | 32 | #uncomment if you want to capture traffic for ensuring traffic encrypted 33 | #sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridg0/Documents/bridge_tcp_dump.sh $1; exit" 34 | 35 | 36 | #start tcpdumps on Web, ensure no_metrics_save set on web server 37 | sshpass -p "mptcp11" ssh -p 22 root@10.8.3.3 "sysctl -w net.ipv4.tcp_no_metrics_save=1; cd /home/web/Documents/run/$2/; /home/web/Documents/web_tcp_dump.sh $1; exit" 38 | 39 | sleep 5 40 | 41 | 42 | #start loop to run tests for all delays 43 | #note: RTT is double the dalay 44 | for delay in 0ms 0.5ms 5ms 10ms 20ms 30ms 40ms 50ms 45 | do 46 | 47 | 48 | echo **********$delay************** >> /home/vpnserver/Documents/log/status_$1 49 | 50 | 51 | #Bridge: make changes to delay rate 52 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridge0/Documents/tc_param.sh change eth2 $delay $2; /home/bridge0/Documents/tc_param.sh change eth3 $delay $2; /home/bridge0/Documents/tc_param.sh change eth9 $delay $2; /home/bridge0/Documents/tc_param.sh change eth10 $delay $2; /home/bridge0/Documents/tc_qdisc.sh $delay $1; exit" 53 | 54 | 55 | #ping test parameters to verify loss rate 56 | #Note: this can be commented out once you are comfortable that delay/loss rates are as expected 57 | ping -c 2000 -f 10.8.1.1 >> ping.txt 58 | cat ping.txt | grep "10.8\|2000\|rtt" >> /home/vpnserver/Documents/log/status_$1 59 | rm ping.txt 60 | 61 | ping -c 2000 -f 10.8.2.2 >> ping.txt 62 | cat ping.txt | grep "10.8\|2000\|rtt" >> /home/vpnserver/Documents/log/status_$1 63 | rm ping.txt 64 | 65 | 66 | #perform downloads on Client 67 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "/home/client/Documents/downloads.sh; wait; exit" 68 | 69 | done 70 | 71 | 72 | 73 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridge0/Documents/tc_param.sh del eth2 50ms $2; /home/bridge0/Documents/tc_param.sh del eth3 50ms $2; /home/bridge0/Documents/tc_param.sh del eth9 50ms $2; /home/bridge0/Documents/tc_param.sh del eth10 50ms $2; kill tcpdump; exit" 74 | 75 | 76 | 77 | #kill local tcpdump 78 | pkill tcpdump 79 | 80 | sleep 10 81 | 82 | #kill tcpdump on web and run t-shark analysis 83 | sshpass -p "mptcp11" ssh -p 22 root@10.8.3.3 "pkill tcpdump; sleep 1; cd /home/web/Documents/run/$2/; tshark -r $1_Web_eth4.pcap -q -z conv,tcp > $1.csv; wait; exit" 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /shell/server/asym_supertest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Settings: 4 | #set desired mem parameters before test 5 | #ensure iptables set for server and client 6 | 7 | #Parameters: 8 | #$1=congestion control 9 | #$2=20 or 40ms 10 | #$3=10 or 20ms 11 | #$4=8 or 15ms 12 | #$5=12 or 25ms 13 | #$6=5ms or 10ms 14 | #$7= 15 or 30ms 15 | 16 | 17 | 18 | #log openvpn files 19 | #we don't want to cache info on tcp sessions since we are running repeated tests 20 | 21 | cd /home/vpnserver/Documents/log/ 22 | sudo cp /etc/openvpn/tcp443.conf . 23 | sysctl -w net.ipv4.tcp_no_metrics_save=1 24 | 25 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "sysctl -w net.ipv4.tcp_no_metrics_save=1; cd /home/client/Documents/log/; cp /etc/openvpn/client.ovpn .; exit" 26 | 27 | 28 | 29 | #set testing variables for client and then server 30 | 31 | sysctl -w net.ipv4.tcp_congestion_control=$1 32 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "sysctl -w net.ipv4.tcp_no_metrics_save=1; sysctl -w net.ipv4.tcp_congestion_control=$1; cd /home/client/Documents/log/ ; echo MP Asym Parameters >> status_asym; sysctl -w net.mptcp.mptcp_enabled=1 >> status_asym; sysctl -w net.mptcp.mptcp_path_manager=fullmesh >> status_asym; sysctl net.ipv4.tcp_congestion_control >> status_asym; exit" 33 | 34 | 35 | cd /home/vpnserver/Documents/log/ 36 | echo CS Parameters >> status_asym 37 | sysctl -w net.mptcp.mptcp_enabled=1 >> status_asym 38 | sysctl -w net.mptcp.mptcp_path_manager=fullmesh >>status_asym 39 | sysctl net.ipv4.tcp_congestion_control >> status_asym 40 | service openvpn restart 41 | 42 | 43 | #start tcpdump, start openvpn connection, warmup download, kill tcpdump 44 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/ ; nohup /home/client/Documents/vpnstart.sh $test; exit" 45 | 46 | 47 | cd /home/vpnserver/Documents/ 48 | mkdir test 49 | chmod +777 test 50 | cd test/ 51 | for dir in $2_0_even $2_P1_even $2_P5_even $2_1P_even $2_0_mod $2_P1_mod $2_P5_mod $2_1P_mod $2_0_sev $2_P1_sev $2_P5_sev $2_1P_sev 52 | do 53 | mkdir $dir 54 | chmod +777 $dir 55 | done 56 | 57 | #create folders on web 58 | sshpass -p "mptcp11" ssh -p 22 root@10.8.3.3 "cd /home/web/Documents/;./directory_asym.sh $2 exit" 59 | 60 | 61 | 62 | #Bridge: set up tc for tests 63 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridge0/Documents/tc_param.sh add eth2 0ms 0%; /home/bridge0/Documents/tc_param.sh add eth3 0ms 0%; /home/bridge0/Documents/tc_param.sh add eth9 0ms 0%; /home/bridge0/Documents/tc_param.sh add eth10 0ms 0%; /home/bridge0/Documents/tc_qdisc.sh 0ms 0%; exit" 64 | 65 | 66 | 67 | 68 | #run various tests and repeat 69 | /home/vpnserver/Documents/asym_test.sh $3 $3 0% 0% $2_0_even 70 | /home/vpnserver/Documents/asym_test.sh $3 $3 0.05% 0.05% $2_P1_even 71 | /home/vpnserver/Documents/asym_test.sh $3 $3 0.25% 0.25% $2_P5_even 72 | /home/vpnserver/Documents/asym_test.sh $3 $3 0.5% 0.5% $2_1P_even 73 | 74 | /home/vpnserver/Documents/asym_test.sh $4 $5 0% 0% $2_0_mod 75 | /home/vpnserver/Documents/asym_test.sh $4 $5 0.03% 0.07% $2_P1_mod 76 | /home/vpnserver/Documents/asym_test.sh $4 $5 0.15% 0.35% $2_P5_mod 77 | /home/vpnserver/Documents/asym_test.sh $4 $5 0.3% 0.7% $2_1P_mod 78 | 79 | /home/vpnserver/Documents/asym_test.sh $6 $7 0% 0% $2_0_sev 80 | /home/vpnserver/Documents/asym_test.sh $6 $7 0% 0.1% $2_P1_sev 81 | /home/vpnserver/Documents/asym_test.sh $6 $7 0% 0.5% $2_P5_sev 82 | /home/vpnserver/Documents/asym_test.sh $6 $7 0% 1% $2_1P_sev 83 | 84 | 85 | #Bridge: delete tc settings 86 | sshpass -p "mptcp11" ssh -p 22 root@10.8.1.110 "/home/bridge0/Documents/tc_param.sh del eth2 $7 1%; /home/bridge0/Documents/tc_param.sh del eth3 $7 1%; /home/bridge0/Documents/tc_param.sh del eth9 $6 0%; /home/bridge0/Documents/tc_param.sh del eth10 $6 0%; exit" 87 | 88 | 89 | #kill openvpn on client in preperation for next test 90 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "pkill openvpn" 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /shell/server/supertest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Settings: 4 | #set desired mem parameters before test 5 | #ensure iptables set for server and client 6 | 7 | 8 | #Parameters: 9 | # 1: balia or cubic 10 | # 2+: fullmesh, ndiffports, TCP, UDP, MPUDP 11 | # can start over at 1 at any point (ex: balia fullmesh cubic ndiffports) 12 | 13 | 14 | #log openvpn files 15 | #we don't want to cache info on tcp sessions since we are running repeated tests 16 | 17 | cd /home/vpnserver/Documents/log/ 18 | sudo cp /etc/openvpn/tcp443.conf . 19 | sysctl -w net.ipv4.tcp_no_metrics_save=1; 20 | 21 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "sysctl -w net.ipv4.tcp_no_metrics_save=1; cd /home/client/Documents/log/; cp /etc/openvpn/client.ovpn .; exit" 22 | 23 | 24 | #create folders on server for test 25 | cd /home/vpnserver/Documents/ 26 | mkdir run 27 | chmod +777 run 28 | cd run/ 29 | 30 | for dir in 0% 0.1% 0.5% 1% 31 | do 32 | mkdir $dir 33 | chmod +777 $dir 34 | done 35 | 36 | #create folders on web 37 | sshpass -p "mptcp11" ssh -p 22 root@10.8.3.3 "cd /home/web/Documents/;./directory_sym.sh exit" 38 | 39 | 40 | 41 | 42 | 43 | #start testing, use parameters specified when calling this script 44 | for test 45 | do 46 | if [ "$test" = "balia" ] || [ "$test" = "cubic" ] 47 | then 48 | sysctl -w net.ipv4.tcp_congestion_control=$test 49 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "sysctl -w net.ipv4.tcp_congestion_control=$test; exit" 50 | continue 51 | 52 | elif [ "$test" = "fullmesh" ] || [ "$test" = "ndiffports" ] 53 | then 54 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/ ; echo MP $test Parameters >> status; sysctl -w net.mptcp.mptcp_enabled=1 >> status; sysctl -w net.mptcp.mptcp_path_manager=$test >> status; sysctl net.ipv4.tcp_congestion_control >> status; exit" 55 | cd /home/vpnserver/Documents/log/ 56 | echo CS $test Parameters >> status_$test 57 | sysctl -w net.mptcp.mptcp_enabled=1 >> status_$test 58 | sysctl -w net.mptcp.mptcp_path_manager=$test >>status_$test 59 | sysctl net.ipv4.tcp_congestion_control >> status_$test 60 | service openvpn restart 61 | 62 | #start tcpdump, start openvpn connection, warmup download, kill tcpdump 63 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/ ; nohup /home/client/Documents/vpnstart.sh $test; exit" 64 | 65 | 66 | elif [ "$test" = "MPUDP" ] 67 | then 68 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/ ; echo MP $test Parameters >> status; sysctl -w net.mptcp.mptcp_enabled=0 >> status; sysctl net.ipv4.tcp_congestion_control >> status; exit" 69 | cd /home/vpnserver/Documents/log/ 70 | echo CS $test Parameters >> status_$test 71 | sysctl -w net.mptcp.mptcp_enabled=0 >> status_$test 72 | sysctl net.ipv4.tcp_congestion_control >> status_$test 73 | service openvpn restart 74 | 75 | #start tcpdump, start openvpn connection, warmup download, kill tcpdump 76 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/ ; nohup /home/client/Documents/vpnstart.sh $test; exit" 77 | 78 | 79 | elif [ "$test" = "TCP" ] || [ "$test" = "UDP" ] 80 | then 81 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/; echo MP $test Parameters >> status; sysctl -w net.mptcp.mptcp_enabled=0 >> status; sysctl net.ipv4.tcp_congestion_control >> status; exit" 82 | cd /home/vpnserver/Documents/log/ 83 | echo CS $test Parameters >> status_$test 84 | sysctl -w net.mptcp.mptcp_enabled=0 >> status_$test 85 | sysctl net.ipv4.tcp_congestion_control >> status_$test 86 | service openvpn restart 87 | 88 | #start tcpdump, start openvpn connection, warmup download, kill tcpdump 89 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "cd /home/client/Documents/log/ ; nohup /home/client/Documents/vpnstart.sh $test; exit" 90 | 91 | else 92 | exit 1 93 | fi 94 | 95 | #run various test for current $test value 96 | for i in 0% 0.1% 0.5% 1% 97 | do 98 | /home/vpnserver/Documents/symm_test.sh $test $i 99 | done 100 | 101 | #kill openvpn on client in preperation for next test 102 | sshpass -p "mptcp11" ssh -p 22 root@10.8.2.2 "pkill openvpn" 103 | done 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /python_scripts/parser_asym.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: LT Lukaszewski 3 | 4 | Purpose: This will parse a directory that has the following csv files for each 5 | packet loss rate (0, 0.1, 0.5, 1%): 6 | - even 7 | - mod 8 | - severe 9 | - 1% 10 | The parser will enter each csv file, parse the csv and add values to 11 | appropriate list for graphing. 12 | 13 | Sections Covered: 3.1.6 (assym testing) 14 | 15 | Assumes: This script worked for thesis testing and uses these assumptions: 16 | - folder setup is described as above 17 | - Testing parameters per Table 3.3 18 | - Address of web server is 10.8.3.3 19 | 20 | Last Modified: 2/2/2017 21 | ''' 22 | 23 | 24 | 25 | #Assisted by 2LT Warren Barksdale 26 | 27 | 28 | 29 | 30 | #Access CSV DONE 31 | #Parse the single line into columns DONE 32 | #Sort by start time DONE 33 | #Get Duration DONE 34 | #Compute Goodput DONE 35 | #Crawl through all subdirectories and analyze files DONE 36 | #In each directory generate a plot 37 | 38 | 39 | import math 40 | import numpy as np 41 | import scipy as sp 42 | import scipy.stats 43 | import os 44 | import matplotlib.pyplot as plt 45 | 46 | 47 | 48 | 49 | #List of File Calulations [Filename, Base Directory, [[List of Means] , [List of Conf]]] 50 | fileList = [] 51 | 52 | even=[0,0,0,0] 53 | even_err=[0,0,0,0] 54 | weak=[0,0,0,0] 55 | weak_err=[0,0,0,0] 56 | strong=[0,0,0,0] 57 | strong_err=[0,0,0,0] 58 | 59 | 60 | #gets the mean and confidence interval and returns to caller 61 | def mean_confidence_interval(data, confidence=0.95): 62 | 63 | a = 1.0*np.array(data) 64 | n = len(a) 65 | m, se = np.mean(a), scipy.stats.sem(a) 66 | h = se * sp.stats.t._ppf((1+confidence)/2., n-1) 67 | return m, h 68 | 69 | 70 | #Navigate to main directory 71 | path = os.getcwd() 72 | 73 | #Testing folder and subdirectory walking 74 | for root, dirs, files in os.walk(path): 75 | for name in files: 76 | #change current directory to the location of the "name" file 77 | os.chdir(root) 78 | if name.endswith((".csv")): 79 | 80 | results_Tuple = () 81 | list1 = [] 82 | refinedList = [] # List of individual row lists 83 | 84 | with open(name, newline='') as csvfile: 85 | #read line and split by whitespace 86 | list1=[line.split() for line in csvfile] 87 | 88 | #remove rows that contain useless data 89 | for x in range(len(list1)): 90 | if ((len(list1[x]) != 11) or (list1[x][2] != "10.8.3.3:http")): 91 | continue 92 | else: 93 | refinedList.append(list1[x]) 94 | 95 | #Sorting by second to last column 96 | refinedList.sort(key=lambda x: float(x[9])) 97 | 98 | download=[] 99 | mean_List = [] 100 | conf_List = [] 101 | results=[] 102 | 103 | #average to Mbps 104 | for x in range(len(refinedList)): 105 | filesize = 0 106 | filesize = ((16331410*8)/float(refinedList[x][10]))/math.pow(10,6) 107 | download.append(filesize) 108 | 109 | #each file has 10 downloads. Need to determine which 110 | #file they came from to put in correct list 111 | mean, conf = mean_confidence_interval(download,0.95) 112 | if name.endswith(("0_even.csv")): 113 | even[0]=mean 114 | even_err[0]=conf 115 | elif name.endswith(("1_even.csv")): 116 | even[1]=mean 117 | even_err[1]=conf 118 | elif name.endswith(("5_even.csv")): 119 | even[2]=mean 120 | even_err[2]=conf 121 | elif name.endswith(("1P_even.csv")): 122 | even[3]=mean 123 | even_err[3]=conf 124 | 125 | if name.endswith(("0_mod.csv")): 126 | weak[0]=mean 127 | weak_err[0]=conf 128 | elif name.endswith(("1_mod.csv")): 129 | weak[1]=mean 130 | weak_err[1]=conf 131 | elif name.endswith(("5_mod.csv")): 132 | weak[2]=mean 133 | weak_err[2]=conf 134 | elif name.endswith(("1P_mod.csv")): 135 | weak[3]=mean 136 | weak_err[3]=conf 137 | 138 | if name.endswith(("0_sev.csv")): 139 | strong[0]=mean 140 | strong_err[0]=conf 141 | elif name.endswith(("1_sev.csv")): 142 | strong[1]=mean 143 | strong_err[1]=conf 144 | elif name.endswith(("5_sev.csv")): 145 | strong[2]=mean 146 | strong_err[2]=conf 147 | elif name.endswith(("1P_sev.csv")): 148 | strong[3]=mean 149 | strong_err[3]=conf 150 | 151 | 152 | csvfile.close() 153 | 154 | 155 | x=[0,0.1,0.5,1.0] 156 | y=even[:] 157 | y2=weak[:] 158 | y3=strong[:] 159 | yerr1=even_err[:] 160 | yerr2=weak_err[:] 161 | yerr3=strong_err[:] 162 | 163 | 164 | 165 | 166 | N = len(y) 167 | ind = np.arange(N) 168 | 169 | plt.errorbar(x,y3,yerr=yerr1,fmt='-rd',ecolor='k', label='Severe') 170 | plt.errorbar(x,y2,yerr=yerr2,fmt='--gv',ecolor='k', label='Moderate') 171 | plt.errorbar(x,y,yerr=yerr3,fmt='-.b^',ecolor='k', label='Even') 172 | #plt.errorbar(x,y3[1],yerr=yerr3[1],fmt='-d',ecolor='k',color='darkolivegreen') 173 | #plt.errorbar(x,y3[2],yerr=yerr3[2],fmt='--mv',ecolor='k') 174 | #plt.errorbar(x,y3[3],yerr=yerr3[3],fmt='-.c^',ecolor='k') 175 | 176 | 177 | axes = plt.gca() 178 | axes.set_ylim([0, 17]) 179 | axes.set_yticks([0, 5, 10, 15]) 180 | 181 | axes.set_xticks([0.0, 0.1, 0.5, 1]) 182 | axes.axhline(10,linestyle='--', color='k') 183 | 184 | plt.axis([-0.1, 1.1, 0, 17]) 185 | plt.ylabel('GOODPUT (Mbps)') 186 | plt.xlabel('Loss Rate (%)') 187 | 188 | plt.legend(loc='lower left',prop={'size':15}) 189 | 190 | plt.savefig('_asym_balia.png') 191 | plt.clf() 192 | -------------------------------------------------------------------------------- /python_scripts/parser_cubic_balia_mpudp.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: LT Lukaszewski 3 | Assisted by: 2LT Warren Barksdale 4 | 5 | Purpose: This will parse a directory that has the following folders: 6 | - 0% 7 | - 0.1% 8 | - 0.5% 9 | - 1% 10 | Each folder needs a tcp.csv, ndiffports.csv, and fullmesh.csv file. 11 | The parser will enter each folder, parse the csv and add values to 12 | appropriate list for graphing. 13 | 14 | Sections Covered: 3.1.4 (cubic), 3.1.5 (balia), and 4.6 (MPUDP) 15 | 16 | Assumes: This script worked for thesis testing and uses these assumptions: 17 | - folder setup is described as above 18 | - Testing: 1,10,20,40,60,80,100ms with 10 trials each 19 | - Address of web server is 10.8.3.3 20 | 21 | Last Modified: 2/2/2017 22 | ''' 23 | 24 | import math 25 | import numpy as np 26 | import scipy as sp 27 | import scipy.stats 28 | import os 29 | import matplotlib.pyplot as plt 30 | 31 | 32 | 33 | #List of File Calulations [Filename, Base Directory, [[List of Means] , [List of Conf]]] 34 | fileList = [] 35 | 36 | 37 | 38 | #gets the mean and confidence interval and returns to caller 39 | def mean_confidence_interval(data, confidence=0.95): 40 | 41 | a = 1.0*np.array(data) 42 | n = len(a) 43 | m, se = np.mean(a), scipy.stats.sem(a) 44 | h = se * sp.stats.t._ppf((1+confidence)/2., n-1) 45 | return m, h 46 | 47 | 48 | 49 | #Navigate to main directory 50 | path = os.getcwd() 51 | 52 | #Testing folder and subdirectory walking 53 | for root, dirs, files in os.walk(path): 54 | for name in files: 55 | #change current directory to the location of the "name" file 56 | os.chdir(root) 57 | if name.endswith((".csv")): 58 | print("Working on file:\n",os.path.join(root, name)) 59 | print("Current Working Directory: ",os.getcwd()) 60 | print("Path to:",name," is \t",root) 61 | print("\n\n") 62 | 63 | results_Tuple = () 64 | list1 = [] 65 | refinedList = [] # List of individual row lists 66 | 67 | with open(name, newline='') as csvfile: 68 | #read line and split by whitespace 69 | list1=[line.split() for line in csvfile] 70 | 71 | #remove rows that contain useless data 72 | for x in range(len(list1)): 73 | if ((len(list1[x]) != 11) or (list1[x][2] != "10.8.3.3:http")): 74 | continue 75 | else: 76 | refinedList.append(list1[x]) 77 | 78 | #Sorting by second to last column, start time 79 | refinedList.sort(key=lambda x: float(x[9])) 80 | 81 | download=[[],[],[],[],[],[],[]] 82 | mean_List = [] 83 | conf_List = [] 84 | results=[] 85 | 86 | #average to Mbps 87 | for x in range(len(refinedList)): 88 | filesize = 0 89 | filesize = ((16331410*8)/float(refinedList[x][10]))/math.pow(10,6) 90 | #1ms RTT 91 | if x<10: 92 | download[0].append(filesize) 93 | #10ms RTT 94 | elif x<20: 95 | download[1].append(filesize) 96 | #20ms RTT 97 | elif x<30: 98 | download[2].append(filesize) 99 | #40ms RTT 100 | elif x<40: 101 | download[3].append(filesize) 102 | #60ms RTT 103 | elif x<50: 104 | download[4].append(filesize) 105 | #80ms RTT 106 | elif x<60: 107 | download[5].append(filesize) 108 | #100ms RTT 109 | elif x<70: 110 | download[6].append(filesize) 111 | 112 | #calculate all the means and confidence intervals 113 | for downl in download: 114 | mean, conf = mean_confidence_interval(downl,0.95) 115 | mean_List.append(mean) 116 | conf_List.append(conf) 117 | 118 | results.append(mean_List) 119 | results.append(conf_List) 120 | results_Tuple = (name, os.path.basename(root), results) 121 | fileList.append(list(results_Tuple)) 122 | csvfile.close() 123 | 124 | #i should have 3 files now and graph them 125 | if len(fileList) == 3: 126 | print("3 Files added") 127 | 128 | while len(fileList)>0: 129 | #print the list for detecting errors 130 | for x in range(len(fileList)): 131 | print("File:",fileList[x][0],"\nFrom:",fileList[x][1]) 132 | print("\nMean List(X)\t Conf List(Y)") 133 | 134 | for z in range(len(fileList[x][2][0])): 135 | print(fileList[x][2][0][z],"\t",fileList[x][2][1][z]) 136 | print("\n") 137 | 138 | #get data for plotting, ecpecting: 139 | # TCP, ndiffports, and fullmesh for 3.1.4, 3.1.5 140 | # UDP, mptcp, MPUDP for 4.6 (mptcp is fullmesh MPTCP) 141 | mpudp_case = 0; 142 | for x in fileList: 143 | if (x[0]=="TCP.csv" or x[0]=="UDP.csv"): 144 | y3 = x[2][0] 145 | yerr3 = x[2][1] 146 | if x[0]=="UDP.csv": 147 | mpudp_case = 1 148 | elif (x[0]=="ndiffports.csv" or x[0]=="mptcp.csv"): 149 | y2 = x[2][0] 150 | yerr2 = x[2][1] 151 | elif (x[0]=="fullmesh.csv" or x[0]=="MPUDP.csv"): 152 | y = x[2][0] 153 | yerr1 = x[2][1] 154 | 155 | N = len(y) 156 | ind = np.arange(N) 157 | margin = 0.2 158 | width = 0.25 159 | fig, ax = plt.subplots() 160 | 161 | bar1 = ax.bar(ind-0.25, y, width, color='b', yerr=yerr1, 162 | error_kw={'ecolor':'k', 'linewidth':2}) 163 | 164 | bar2 = ax.bar(ind, y2, width, color='r', yerr=yerr2, 165 | error_kw={'ecolor':'k', 'linewidth':2}) 166 | 167 | bar3 = ax.bar(ind + 0.25, y3, width, color='g', yerr=yerr3, 168 | error_kw={'ecolor':'k', 'linewidth':2}) 169 | 170 | axes = plt.gca() 171 | axes.set_yticks([0, 3, 6, 9, 12, 15, 18, 21]) 172 | #put a line at single path max 173 | ax.axhline(10,linestyle='--', color='k') 174 | ax.set_ylabel('GOODPUT (Mbps)') 175 | ax.set_xlabel('Link Propagation RTT (ms)') 176 | ax.set_xticks(ind+.125) 177 | ax.set_xticklabels([1,10,20,40,60,80,100]) 178 | if mpudp_case: 179 | ax.legend((bar1[0], bar2[0], bar3[0]), 180 | ('MPUDP', 'MPTCP', 'UDP'),prop={'size':15}) 181 | else: 182 | ax.legend((bar1[0], bar2[0], bar3[0]), 183 | ('fullmesh', 'ndiffports', 'TCP'),prop={'size':15}) 184 | 185 | plt.savefig(fileList[0][1] +'_loss.png') 186 | plt.clf() 187 | fileList.pop(0) 188 | fileList.pop(0) 189 | fileList.pop(0) 190 | print("3 Files Graphed and removed from fileList") 191 | 192 | 193 | # 194 | -------------------------------------------------------------------------------- /python_scripts/parser_ndiff_norm.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: LT Lukaszewski 3 | Assisted by: 2LT Warren Barksdale 4 | 5 | Purpose: This will parse a directory that has the following folders: 6 | - 0% 7 | - 0.1% 8 | - 0.5% 9 | - 1% 10 | Each folder needs a tcp.csv, ndiffports.csv, and ndiffports_3-5 files. 11 | The parser will enter each folder, parse the csv and add values to 12 | appropriate list for normalization and then graphing. 13 | 14 | Figure Covered: 3.8 (ndiff subflows) 15 | 16 | Assumes: This script worked for thesis testing and uses these assumptions: 17 | - folder setup is described as above 18 | - Testing: 1,10,20,40,60,80,100ms with 10 trials each 19 | - Address of web server is 10.8.3.3 20 | 21 | Last Modified: 2/2/2017 22 | ''' 23 | 24 | 25 | 26 | import math 27 | import numpy as np 28 | import scipy as sp 29 | import scipy.stats 30 | import os 31 | import matplotlib.pyplot as plt 32 | 33 | 34 | #List of File Calulations [Filename, Base Directory, [[List of Means] , [List of Conf]]] 35 | fileList = [] 36 | 37 | 38 | 39 | #gets the mean and confidence interval and returns to caller 40 | def mean_confidence_interval(data, confidence=0.95): 41 | 42 | a = 1.0*np.array(data) 43 | n = len(a) 44 | m, se = np.mean(a), scipy.stats.sem(a) 45 | h = se * sp.stats.t._ppf((1+confidence)/2., n-1) 46 | return m, h 47 | 48 | 49 | 50 | #Navigate to main directory 51 | path = os.getcwd() 52 | 53 | #Testing folder and subdirectory walking 54 | for root, dirs, files in os.walk(path): 55 | for name in files: 56 | #change current directory to the location of the "name" file 57 | os.chdir(root) 58 | if name.endswith((".csv")): 59 | print("Working on file:\n",os.path.join(root, name)) 60 | print("Current Working Directory: ",os.getcwd()) 61 | print("Path to:",name," is \t",root) 62 | print("\n\n") 63 | 64 | results_Tuple = () 65 | list1 = [] 66 | refinedList = [] # List of individual row lists 67 | 68 | with open(name, newline='') as csvfile: 69 | #read line and split by whitespace 70 | list1=[line.split() for line in csvfile] 71 | 72 | #remove rows that contain useless data 73 | for x in range(len(list1)): 74 | if ((len(list1[x]) != 11) or (list1[x][2] != "10.8.3.3:http")): 75 | continue 76 | else: 77 | refinedList.append(list1[x]) 78 | 79 | #Sorting by second to last column, start time 80 | refinedList.sort(key=lambda x: float(x[9])) 81 | 82 | download=[[],[],[],[],[],[],[]] 83 | mean_List = [] 84 | conf_List = [] 85 | results=[] 86 | 87 | #average to Mbps 88 | for x in range(len(refinedList)): 89 | filesize = 0 90 | filesize = ((16331410*8)/float(refinedList[x][10]))/math.pow(10,6) 91 | #1ms RTT 92 | if x<10: 93 | download[0].append(filesize) 94 | #10ms RTT 95 | elif x<20: 96 | download[1].append(filesize) 97 | #20ms RTT 98 | elif x<30: 99 | download[2].append(filesize) 100 | #40ms RTT 101 | elif x<40: 102 | download[3].append(filesize) 103 | #60ms RTT 104 | elif x<50: 105 | download[4].append(filesize) 106 | #80ms RTT 107 | elif x<60: 108 | download[5].append(filesize) 109 | #100ms RTT 110 | elif x<70: 111 | download[6].append(filesize) 112 | 113 | #calculate all the means and confidence intervals 114 | for downl in download: 115 | mean, conf = mean_confidence_interval(downl,0.95) 116 | mean_List.append(mean) 117 | conf_List.append(conf) 118 | 119 | results.append(mean_List) 120 | results.append(conf_List) 121 | results_Tuple = (name, os.path.basename(root), results) 122 | fileList.append(list(results_Tuple)) 123 | csvfile.close() 124 | 125 | #i should have 6 files now and graph them 126 | if len(fileList) == 5: 127 | print("5 Files added") 128 | 129 | while len(fileList)>0: 130 | #print the list for detecting errors 131 | for x in range(len(fileList)): 132 | print("File:",fileList[x][0],"\nFrom:",fileList[x][1]) 133 | print("\nMean List(X)\t Conf List(Y)") 134 | 135 | for z in range(len(fileList[x][2][0])): 136 | print(fileList[x][2][0][z],"\t",fileList[x][2][1][z]) 137 | print("\n") 138 | 139 | #get data for plotting, ecpecting: 140 | # TCP, ndiffports, and ndiffports_3-5 for Figure 3.8 141 | for x in fileList: 142 | if x[0]=="tcp.csv": 143 | yTcp = x[2][0] 144 | yerrTcp = x[2][1] 145 | elif x[0]=="ndiffports_3.csv": 146 | y2 = x[2][0] 147 | yerr2 = x[2][1] 148 | elif x[0]=="ndiffports_4.csv": 149 | y3 = x[2][0] 150 | yerr3 = x[2][1] 151 | elif x[0]=="ndiffports_5.csv": 152 | y4 = x[2][0] 153 | yerr4 = x[2][1] 154 | else: 155 | y = x[2][0] 156 | yerr1 = x[2][1] 157 | 158 | #[[data],[up error], [down error]] 159 | ndiff = [[],[],[]] 160 | ndiff3 = [[],[],[]] 161 | ndiff4 = [[],[],[]] 162 | ndiff5 = [[],[],[]] 163 | 164 | 165 | #copy error data into lists so can be normalized 166 | for x in range(len(yerr1)): 167 | ndiff[1].append(yerr1[x]+y[x]) 168 | ndiff[2].append(y[x]-yerr1[x]) 169 | 170 | ndiff3[1].append(yerr3[x]+y3[x]) 171 | ndiff3[2].append(y3[x]-yerr3[x]) 172 | ndiff4[1].append(yerr4[x]+y4[x]) 173 | ndiff4[2].append(y4[x]-yerr4[x]) 174 | ndiff5[1].append(yerr5[x]+y5[x]) 175 | ndiff5[2].append(y5[x]-yerr5[x]) 176 | 177 | #normalize the data 178 | for x in range(len(y)): 179 | imp = (float(y[x]/yTcp[x])-1)*100 180 | ndiff[1][x] = ((float(ndiff[1][x]/yTcp[x])-1)*100)-imp 181 | ndiff[2][x] = imp-((float(ndiff[2][x]/yTcp[x])-1)*100) 182 | ndiff[0].append(imp) 183 | 184 | 185 | imp = (float(y3[x]/yTcp[x])-1)*100 186 | ndiff3[1][x] = ((float(ndiff3[1][x]/yTcp[x])-1)*100)-imp 187 | ndiff3[2][x] = imp-((float(ndiff3[2][x]/yTcp[x])-1)*100) 188 | ndiff3[0].append(imp) 189 | 190 | imp = (float(y4[x]/yTcp[x])-1)*100 191 | ndiff4[1][x] = ((float(ndiff4[1][x]/yTcp[x])-1)*100)-imp 192 | ndiff4[2][x] = imp-((float(ndiff4[2][x]/yTcp[x])-1)*100) 193 | ndiff4[0].append(imp) 194 | 195 | imp = (float(y5[x]/yTcp[x])-1)*100 196 | ndiff5[1][x] = ((float(ndiff5[1][x]/yTcp[x])-1)*100)-imp 197 | ndiff5[2][x] = imp-((float(ndiff5[2][x]/yTcp[x])-1)*100) 198 | ndiff5[0].append(imp) 199 | 200 | 201 | 202 | N = len(y) 203 | ind = np.arange(N) 204 | 205 | x=[1,10,20,40,60,80,100] 206 | plt.errorbar(x,ndiff5[0],yerr=[ndiff5[2],ndiff5[1]],fmt='-rd', 207 | ecolor='k', label='ndiff_5') 208 | plt.errorbar(x,ndiff4[0],yerr=[ndiff4[2],ndiff4[1]],fmt='--gv', 209 | ecolor='k', label='ndiff_4') 210 | plt.errorbar(x,ndiff3[0],yerr=[ndiff3[2],ndiff3[1]],fmt='-.b^', 211 | ecolor='k', label='ndiff_3') 212 | 213 | plt.errorbar(x,ndiff[0],yerr=[ndiff[2],ndiff[1]],fmt='--mv', 214 | ecolor='k', label='ndiff_Default') 215 | 216 | axes = plt.gca() 217 | axes.set_ylim([0,200]) 218 | axes.set_yticks([0,50,100,150,200]) 219 | 220 | axes.axhline(100,linestyle='--', color='k') 221 | 222 | plt.ylabel('Percent Difference From TCP (%)') 223 | plt.xlabel('Link Propagation RTT (ms)') 224 | 225 | 226 | plt.axis([0,101,0,250]) 227 | plt.legend() 228 | 229 | plt.savefig(fileList[0][1] +'_loss.png') 230 | plt.clf(loc='upper left') 231 | 232 | #romove files from list so can plot next set of 6 233 | i=0 234 | while (i<5): 235 | fileList.pop(0) 236 | i+=1 237 | 238 | print("5 Files Graphed and removed from fileList") 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /python_scripts/parser_fullmesh_norm.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: LT Lukaszewski 3 | Assisted by: 2LT Warren Barksdale 4 | 5 | Purpose: This will parse a directory that has the following folders: 6 | - 0% 7 | - 0.1% 8 | - 0.5% 9 | - 1% 10 | Each folder needs a tcp.csv, fullmesh.csv, and fullmesh_2-5 files. 11 | The parser will enter each folder, parse the csv and add values to 12 | appropriate list for normalization and then graphing. 13 | 14 | Figure Covered: 3.7 (fullmesh subflows) 15 | 16 | Assumes: This script worked for thesis testing and uses these assumptions: 17 | - folder setup is described as above 18 | - Testing: 1,10,20,40,60,80,100ms with 10 trials each 19 | - Address of web server is 10.8.3.3 20 | 21 | Last Modified: 2/2/2017 22 | ''' 23 | 24 | 25 | 26 | import math 27 | import numpy as np 28 | import scipy as sp 29 | import scipy.stats 30 | import os 31 | import matplotlib.pyplot as plt 32 | 33 | 34 | #List of File Calulations [Filename, Base Directory, [[List of Means] , [List of Conf]]] 35 | fileList = [] 36 | 37 | 38 | 39 | #gets the mean and confidence interval and returns to caller 40 | def mean_confidence_interval(data, confidence=0.95): 41 | 42 | a = 1.0*np.array(data) 43 | n = len(a) 44 | m, se = np.mean(a), scipy.stats.sem(a) 45 | h = se * sp.stats.t._ppf((1+confidence)/2., n-1) 46 | return m, h 47 | 48 | 49 | 50 | #Navigate to main directory 51 | path = os.getcwd() 52 | 53 | #Testing folder and subdirectory walking 54 | for root, dirs, files in os.walk(path): 55 | for name in files: 56 | #change current directory to the location of the "name" file 57 | os.chdir(root) 58 | if name.endswith((".csv")): 59 | print("Working on file:\n",os.path.join(root, name)) 60 | print("Current Working Directory: ",os.getcwd()) 61 | print("Path to:",name," is \t",root) 62 | print("\n\n") 63 | 64 | results_Tuple = () 65 | list1 = [] 66 | refinedList = [] # List of individual row lists 67 | 68 | with open(name, newline='') as csvfile: 69 | #read line and split by whitespace 70 | list1=[line.split() for line in csvfile] 71 | 72 | #remove rows that contain useless data 73 | for x in range(len(list1)): 74 | if ((len(list1[x]) != 11) or (list1[x][2] != "10.8.3.3:http")): 75 | continue 76 | else: 77 | refinedList.append(list1[x]) 78 | 79 | #Sorting by second to last column, start time 80 | refinedList.sort(key=lambda x: float(x[9])) 81 | 82 | download=[[],[],[],[],[],[],[]] 83 | mean_List = [] 84 | conf_List = [] 85 | results=[] 86 | 87 | #average to Mbps 88 | for x in range(len(refinedList)): 89 | filesize = 0 90 | filesize = ((16331410*8)/float(refinedList[x][10]))/math.pow(10,6) 91 | #1ms RTT 92 | if x<10: 93 | download[0].append(filesize) 94 | #10ms RTT 95 | elif x<20: 96 | download[1].append(filesize) 97 | #20ms RTT 98 | elif x<30: 99 | download[2].append(filesize) 100 | #40ms RTT 101 | elif x<40: 102 | download[3].append(filesize) 103 | #60ms RTT 104 | elif x<50: 105 | download[4].append(filesize) 106 | #80ms RTT 107 | elif x<60: 108 | download[5].append(filesize) 109 | #100ms RTT 110 | elif x<70: 111 | download[6].append(filesize) 112 | 113 | #calculate all the means and confidence intervals 114 | for downl in download: 115 | mean, conf = mean_confidence_interval(downl,0.95) 116 | mean_List.append(mean) 117 | conf_List.append(conf) 118 | 119 | results.append(mean_List) 120 | results.append(conf_List) 121 | results_Tuple = (name, os.path.basename(root), results) 122 | fileList.append(list(results_Tuple)) 123 | csvfile.close() 124 | 125 | #i should have 6 files now and graph them 126 | if len(fileList) == 6: 127 | print("6 Files added") 128 | 129 | while len(fileList)>0: 130 | #print the list for detecting errors 131 | for x in range(len(fileList)): 132 | print("File:",fileList[x][0],"\nFrom:",fileList[x][1]) 133 | print("\nMean List(X)\t Conf List(Y)") 134 | 135 | for z in range(len(fileList[x][2][0])): 136 | print(fileList[x][2][0][z],"\t",fileList[x][2][1][z]) 137 | print("\n") 138 | 139 | #get data for plotting, ecpecting: 140 | # TCP, fullmesh, and fullmesh_2-5 for Figure 3.7 141 | for x in fileList: 142 | if x[0]=="tcp.csv": 143 | yTcp = x[2][0] 144 | yerrTcp = x[2][1] 145 | elif x[0]=="fullmesh_2.csv": 146 | y2 = x[2][0] 147 | yerr2 = x[2][1] 148 | elif x[0]=="fullmesh_3.csv": 149 | y3 = x[2][0] 150 | yerr3 = x[2][1] 151 | elif x[0]=="fullmesh_4.csv": 152 | y4 = x[2][0] 153 | yerr4 = x[2][1] 154 | elif x[0]=="fullmesh_5.csv": 155 | y5 = x[2][0] 156 | yerr5 = x[2][1] 157 | else: 158 | y = x[2][0] 159 | yerr1 = x[2][1] 160 | 161 | #[[data],[up error], [down error]] 162 | fm = [[],[],[]] 163 | fm2 = [[],[],[]] 164 | fm3 = [[],[],[]] 165 | fm4 = [[],[],[]] 166 | fm5 = [[],[],[]] 167 | 168 | #copy error data into lists so can be normalized 169 | for x in range(len(yerr1)): 170 | fm[1].append(yerr1[x]+y[x]) 171 | fm[2].append(y[x]-yerr1[x]) 172 | 173 | fm2[1].append(yerr2[x]+y2[x]) 174 | fm2[2].append(y2[x]-yerr2[x]) 175 | fm3[1].append(yerr3[x]+y3[x]) 176 | fm3[2].append(y3[x]-yerr3[x]) 177 | fm4[1].append(yerr4[x]+y4[x]) 178 | fm4[2].append(y4[x]-yerr4[x]) 179 | fm5[1].append(yerr5[x]+y5[x]) 180 | fm5[2].append(y5[x]-yerr5[x]) 181 | 182 | #normalize the data 183 | for x in range(len(y)): 184 | imp = (float(y[x]/yTcp[x])-1)*100 185 | fm[1][x] = ((float(fm[1][x]/yTcp[x])-1)*100)-imp 186 | fm[2][x] = imp-((float(fm[2][x]/yTcp[x])-1)*100) 187 | fm[0].append(imp) 188 | 189 | imp = (float(y2[x]/yTcp[x])-1)*100 190 | fm2[1][x] = ((float(fm2[1][x]/yTcp[x])-1)*100)-imp 191 | fm2[2][x] = imp-((float(fm2[2][x]/yTcp[x])-1)*100) 192 | fm2[0].append(imp) 193 | 194 | imp = (float(y3[x]/yTcp[x])-1)*100 195 | fm3[1][x] = ((float(fm3[1][x]/yTcp[x])-1)*100)-imp 196 | fm3[2][x] = imp-((float(fm3[2][x]/yTcp[x])-1)*100) 197 | fm3[0].append(imp) 198 | 199 | imp = (float(y4[x]/yTcp[x])-1)*100 200 | fm4[1][x] = ((float(fm4[1][x]/yTcp[x])-1)*100)-imp 201 | fm4[2][x] = imp-((float(fm4[2][x]/yTcp[x])-1)*100) 202 | fm4[0].append(imp) 203 | 204 | imp = (float(y5[x]/yTcp[x])-1)*100 205 | fm5[1][x] = ((float(fm5[1][x]/yTcp[x])-1)*100)-imp 206 | fm5[2][x] = imp-((float(fm5[2][x]/yTcp[x])-1)*100) 207 | fm5[0].append(imp) 208 | 209 | 210 | 211 | N = len(y) 212 | ind = np.arange(N) 213 | 214 | x=[1,10,20,40,60,80,100] 215 | plt.errorbar(x,fm5[0],yerr=[fm5[2],fm5[1]],fmt='-rd', 216 | ecolor='k', label='FM_5') 217 | plt.errorbar(x,fm4[0],yerr=[fm4[2],fm4[1]],fmt='--gv', 218 | ecolor='k', label='FM_4') 219 | plt.errorbar(x,fm3[0],yerr=[fm3[2],fm3[1]],fmt='-.b^', 220 | ecolor='k', label='FM_3') 221 | plt.errorbar(x,fm2[0],yerr=[fm2[2],fm2[1]],fmt='-d', 222 | ecolor='k', color='darkolivegreen', label='FM_2') 223 | plt.errorbar(x,fm[0],yerr=[fm[2],fm[1]],fmt='--mv', 224 | ecolor='k', label='FM_Default') 225 | 226 | axes = plt.gca() 227 | axes.set_ylim([0,200]) 228 | axes.set_yticks([0,50,100,150,200]) 229 | 230 | axes.axhline(100,linestyle='--', color='k') 231 | 232 | plt.ylabel('Percent Difference From TCP (%)') 233 | plt.xlabel('Link Propagation RTT (ms)') 234 | 235 | 236 | plt.axis([0,101,0,250]) 237 | plt.legend() 238 | 239 | plt.savefig(fileList[0][1] +'_loss.png') 240 | plt.clf() 241 | 242 | #romove files from list so can plot next set of 6 243 | i=0 244 | while (i<6): 245 | fileList.pop(0) 246 | i+=1 247 | 248 | print("6 Files Graphed and removed from fileList") 249 | 250 | 251 | -------------------------------------------------------------------------------- /c_files/udp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * INET An implementation of the TCP/IP protocol suite for the LINUX 3 | * operating system. INET is implemented using the BSD Socket 4 | * interface as the means of communication with the user level. 5 | * 6 | * The User Datagram Protocol (UDP). 7 | * 8 | * Authors: Ross Biro 9 | * Fred N. van Kempen, 10 | * Arnt Gulbrandsen, 11 | * Alan Cox, 12 | * Hirokazu Takahashi, 13 | * 14 | * Fixes: 15 | * Alan Cox : verify_area() calls 16 | * Alan Cox : stopped close while in use off icmp 17 | * messages. Not a fix but a botch that 18 | * for udp at least is 'valid'. 19 | * Alan Cox : Fixed icmp handling properly 20 | * Alan Cox : Correct error for oversized datagrams 21 | * Alan Cox : Tidied select() semantics. 22 | * Alan Cox : udp_err() fixed properly, also now 23 | * select and read wake correctly on errors 24 | * Alan Cox : udp_send verify_area moved to avoid mem leak 25 | * Alan Cox : UDP can count its memory 26 | * Alan Cox : send to an unknown connection causes 27 | * an ECONNREFUSED off the icmp, but 28 | * does NOT close. 29 | * Alan Cox : Switched to new sk_buff handlers. No more backlog! 30 | * Alan Cox : Using generic datagram code. Even smaller and the PEEK 31 | * bug no longer crashes it. 32 | * Fred Van Kempen : Net2e support for sk->broadcast. 33 | * Alan Cox : Uses skb_free_datagram 34 | * Alan Cox : Added get/set sockopt support. 35 | * Alan Cox : Broadcasting without option set returns EACCES. 36 | * Alan Cox : No wakeup calls. Instead we now use the callbacks. 37 | * Alan Cox : Use ip_tos and ip_ttl 38 | * Alan Cox : SNMP Mibs 39 | * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. 40 | * Matt Dillon : UDP length checks. 41 | * Alan Cox : Smarter af_inet used properly. 42 | * Alan Cox : Use new kernel side addressing. 43 | * Alan Cox : Incorrect return on truncated datagram receive. 44 | * Arnt Gulbrandsen : New udp_send and stuff 45 | * Alan Cox : Cache last socket 46 | * Alan Cox : Route cache 47 | * Jon Peatfield : Minor efficiency fix to sendto(). 48 | * Mike Shaver : RFC1122 checks. 49 | * Alan Cox : Nonblocking error fix. 50 | * Willy Konynenberg : Transparent proxying support. 51 | * Mike McLagan : Routing by source 52 | * David S. Miller : New socket lookup architecture. 53 | * Last socket cache retained as it 54 | * does have a high hit rate. 55 | * Olaf Kirch : Don't linearise iovec on sendmsg. 56 | * Andi Kleen : Some cleanups, cache destination entry 57 | * for connect. 58 | * Vitaly E. Lavrov : Transparent proxy revived after year coma. 59 | * Melvin Smith : Check msg_name not msg_namelen in sendto(), 60 | * return ENOTCONN for unconnected sockets (POSIX) 61 | * Janos Farkas : don't deliver multi/broadcasts to a different 62 | * bound-to-device socket 63 | * Hirokazu Takahashi : HW checksumming for outgoing UDP 64 | * datagrams. 65 | * Hirokazu Takahashi : sendfile() on UDP works now. 66 | * Arnaldo C. Melo : convert /proc/net/udp to seq_file 67 | * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which 68 | * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind 69 | * a single port at the same time. 70 | * Derek Atkins : Add Encapulation Support 71 | * James Chapman : Add L2TP encapsulation type. 72 | * 73 | * 74 | * This program is free software; you can redistribute it and/or 75 | * modify it under the terms of the GNU General Public License 76 | * as published by the Free Software Foundation; either version 77 | * 2 of the License, or (at your option) any later version. 78 | */ 79 | 80 | #define pr_fmt(fmt) "UDP: " fmt 81 | 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include "udp_impl.h" 117 | 118 | struct udp_table udp_table __read_mostly; 119 | EXPORT_SYMBOL(udp_table); 120 | 121 | long sysctl_udp_mem[3] __read_mostly; 122 | EXPORT_SYMBOL(sysctl_udp_mem); 123 | 124 | int sysctl_udp_rmem_min __read_mostly; 125 | EXPORT_SYMBOL(sysctl_udp_rmem_min); 126 | 127 | int sysctl_udp_wmem_min __read_mostly; 128 | EXPORT_SYMBOL(sysctl_udp_wmem_min); 129 | 130 | atomic_long_t udp_memory_allocated; 131 | EXPORT_SYMBOL(udp_memory_allocated); 132 | 133 | #define MAX_UDP_PORTS 65536 134 | #define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN) 135 | 136 | static int udp_lib_lport_inuse(struct net *net, __u16 num, 137 | const struct udp_hslot *hslot, 138 | unsigned long *bitmap, 139 | struct sock *sk, 140 | int (*saddr_comp)(const struct sock *sk1, 141 | const struct sock *sk2), 142 | unsigned int log) 143 | { 144 | struct sock *sk2; 145 | struct hlist_nulls_node *node; 146 | kuid_t uid = sock_i_uid(sk); 147 | 148 | sk_nulls_for_each(sk2, node, &hslot->head) 149 | if (net_eq(sock_net(sk2), net) && 150 | sk2 != sk && 151 | (bitmap || udp_sk(sk2)->udp_port_hash == num) && 152 | (!sk2->sk_reuse || !sk->sk_reuse) && 153 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || 154 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && 155 | (!sk2->sk_reuseport || !sk->sk_reuseport || 156 | !uid_eq(uid, sock_i_uid(sk2))) && 157 | (*saddr_comp)(sk, sk2)) { 158 | if (bitmap) 159 | __set_bit(udp_sk(sk2)->udp_port_hash >> log, 160 | bitmap); 161 | else 162 | return 1; 163 | } 164 | return 0; 165 | } 166 | 167 | /* 168 | * Note: we still hold spinlock of primary hash chain, so no other writer 169 | * can insert/delete a socket with local_port == num 170 | */ 171 | static int udp_lib_lport_inuse2(struct net *net, __u16 num, 172 | struct udp_hslot *hslot2, 173 | struct sock *sk, 174 | int (*saddr_comp)(const struct sock *sk1, 175 | const struct sock *sk2)) 176 | { 177 | struct sock *sk2; 178 | struct hlist_nulls_node *node; 179 | kuid_t uid = sock_i_uid(sk); 180 | int res = 0; 181 | 182 | spin_lock(&hslot2->lock); 183 | udp_portaddr_for_each_entry(sk2, node, &hslot2->head) 184 | if (net_eq(sock_net(sk2), net) && 185 | sk2 != sk && 186 | (udp_sk(sk2)->udp_port_hash == num) && 187 | (!sk2->sk_reuse || !sk->sk_reuse) && 188 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || 189 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && 190 | (!sk2->sk_reuseport || !sk->sk_reuseport || 191 | !uid_eq(uid, sock_i_uid(sk2))) && 192 | (*saddr_comp)(sk, sk2)) { 193 | res = 1; 194 | break; 195 | } 196 | spin_unlock(&hslot2->lock); 197 | return res; 198 | } 199 | 200 | /** 201 | * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 202 | * 203 | * @sk: socket struct in question 204 | * @snum: port number to look up 205 | * @saddr_comp: AF-dependent comparison of bound local IP addresses 206 | * @hash2_nulladdr: AF-dependent hash value in secondary hash chains, 207 | * with NULL address 208 | */ 209 | int udp_lib_get_port(struct sock *sk, unsigned short snum, 210 | int (*saddr_comp)(const struct sock *sk1, 211 | const struct sock *sk2), 212 | unsigned int hash2_nulladdr) 213 | { 214 | struct udp_hslot *hslot, *hslot2; 215 | struct udp_table *udptable = sk->sk_prot->h.udp_table; 216 | int error = 1; 217 | struct net *net = sock_net(sk); 218 | 219 | if (!snum) { 220 | int low, high, remaining; 221 | unsigned int rand; 222 | unsigned short first, last; 223 | DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN); 224 | 225 | inet_get_local_port_range(net, &low, &high); 226 | remaining = (high - low) + 1; 227 | 228 | rand = prandom_u32(); 229 | first = reciprocal_scale(rand, remaining) + low; 230 | /* 231 | * force rand to be an odd multiple of UDP_HTABLE_SIZE 232 | */ 233 | rand = (rand | 1) * (udptable->mask + 1); 234 | last = first + udptable->mask + 1; 235 | do { 236 | hslot = udp_hashslot(udptable, net, first); 237 | bitmap_zero(bitmap, PORTS_PER_CHAIN); 238 | spin_lock_bh(&hslot->lock); 239 | udp_lib_lport_inuse(net, snum, hslot, bitmap, sk, 240 | saddr_comp, udptable->log); 241 | 242 | snum = first; 243 | /* 244 | * Iterate on all possible values of snum for this hash. 245 | * Using steps of an odd multiple of UDP_HTABLE_SIZE 246 | * give us randomization and full range coverage. 247 | */ 248 | do { 249 | if (low <= snum && snum <= high && 250 | !test_bit(snum >> udptable->log, bitmap) && 251 | !inet_is_local_reserved_port(net, snum)) 252 | goto found; 253 | snum += rand; 254 | } while (snum != first); 255 | spin_unlock_bh(&hslot->lock); 256 | } while (++first != last); 257 | goto fail; 258 | } else { 259 | hslot = udp_hashslot(udptable, net, snum); 260 | spin_lock_bh(&hslot->lock); 261 | if (hslot->count > 10) { 262 | int exist; 263 | unsigned int slot2 = udp_sk(sk)->udp_portaddr_hash ^ snum; 264 | 265 | slot2 &= udptable->mask; 266 | hash2_nulladdr &= udptable->mask; 267 | 268 | hslot2 = udp_hashslot2(udptable, slot2); 269 | if (hslot->count < hslot2->count) 270 | goto scan_primary_hash; 271 | 272 | exist = udp_lib_lport_inuse2(net, snum, hslot2, 273 | sk, saddr_comp); 274 | if (!exist && (hash2_nulladdr != slot2)) { 275 | hslot2 = udp_hashslot2(udptable, hash2_nulladdr); 276 | exist = udp_lib_lport_inuse2(net, snum, hslot2, 277 | sk, saddr_comp); 278 | } 279 | if (exist) 280 | goto fail_unlock; 281 | else 282 | goto found; 283 | } 284 | scan_primary_hash: 285 | if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, 286 | saddr_comp, 0)) 287 | goto fail_unlock; 288 | } 289 | found: 290 | inet_sk(sk)->inet_num = snum; 291 | udp_sk(sk)->udp_port_hash = snum; 292 | udp_sk(sk)->udp_portaddr_hash ^= snum; 293 | if (sk_unhashed(sk)) { 294 | sk_nulls_add_node_rcu(sk, &hslot->head); 295 | hslot->count++; 296 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 297 | 298 | hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); 299 | spin_lock(&hslot2->lock); 300 | hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, 301 | &hslot2->head); 302 | hslot2->count++; 303 | spin_unlock(&hslot2->lock); 304 | } 305 | error = 0; 306 | fail_unlock: 307 | spin_unlock_bh(&hslot->lock); 308 | fail: 309 | return error; 310 | } 311 | EXPORT_SYMBOL(udp_lib_get_port); 312 | 313 | static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) 314 | { 315 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); 316 | 317 | return (!ipv6_only_sock(sk2) && 318 | (!inet1->inet_rcv_saddr || !inet2->inet_rcv_saddr || 319 | inet1->inet_rcv_saddr == inet2->inet_rcv_saddr)); 320 | } 321 | 322 | static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr, 323 | unsigned int port) 324 | { 325 | return jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port; 326 | } 327 | 328 | int udp_v4_get_port(struct sock *sk, unsigned short snum) 329 | { 330 | unsigned int hash2_nulladdr = 331 | udp4_portaddr_hash(sock_net(sk), htonl(INADDR_ANY), snum); 332 | unsigned int hash2_partial = 333 | udp4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0); 334 | 335 | /* precompute partial secondary hash */ 336 | udp_sk(sk)->udp_portaddr_hash = hash2_partial; 337 | return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr); 338 | } 339 | 340 | static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, 341 | unsigned short hnum, 342 | __be16 sport, __be32 daddr, __be16 dport, int dif) 343 | { 344 | int score = -1; 345 | 346 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && 347 | !ipv6_only_sock(sk)) { 348 | struct inet_sock *inet = inet_sk(sk); 349 | 350 | score = (sk->sk_family == PF_INET ? 2 : 1); 351 | if (inet->inet_rcv_saddr) { 352 | if (inet->inet_rcv_saddr != daddr) 353 | return -1; 354 | score += 4; 355 | } 356 | if (inet->inet_daddr) { 357 | if (inet->inet_daddr != saddr) 358 | return -1; 359 | score += 4; 360 | } 361 | if (inet->inet_dport) { 362 | if (inet->inet_dport != sport) 363 | return -1; 364 | score += 4; 365 | } 366 | if (sk->sk_bound_dev_if) { 367 | if (sk->sk_bound_dev_if != dif) 368 | return -1; 369 | score += 4; 370 | } 371 | } 372 | return score; 373 | } 374 | 375 | /* 376 | * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num) 377 | */ 378 | static inline int compute_score2(struct sock *sk, struct net *net, 379 | __be32 saddr, __be16 sport, 380 | __be32 daddr, unsigned int hnum, int dif) 381 | { 382 | int score = -1; 383 | 384 | if (net_eq(sock_net(sk), net) && !ipv6_only_sock(sk)) { 385 | struct inet_sock *inet = inet_sk(sk); 386 | 387 | if (inet->inet_rcv_saddr != daddr) 388 | return -1; 389 | if (inet->inet_num != hnum) 390 | return -1; 391 | 392 | score = (sk->sk_family == PF_INET ? 2 : 1); 393 | if (inet->inet_daddr) { 394 | if (inet->inet_daddr != saddr) 395 | return -1; 396 | score += 4; 397 | } 398 | if (inet->inet_dport) { 399 | if (inet->inet_dport != sport) 400 | return -1; 401 | score += 4; 402 | } 403 | if (sk->sk_bound_dev_if) { 404 | if (sk->sk_bound_dev_if != dif) 405 | return -1; 406 | score += 4; 407 | } 408 | } 409 | return score; 410 | } 411 | 412 | static unsigned int udp_ehashfn(struct net *net, const __be32 laddr, 413 | const __u16 lport, const __be32 faddr, 414 | const __be16 fport) 415 | { 416 | static u32 udp_ehash_secret __read_mostly; 417 | 418 | net_get_random_once(&udp_ehash_secret, sizeof(udp_ehash_secret)); 419 | 420 | return __inet_ehashfn(laddr, lport, faddr, fport, 421 | udp_ehash_secret + net_hash_mix(net)); 422 | } 423 | 424 | 425 | /* called with read_rcu_lock() */ 426 | static struct sock *udp4_lib_lookup2(struct net *net, 427 | __be32 saddr, __be16 sport, 428 | __be32 daddr, unsigned int hnum, int dif, 429 | struct udp_hslot *hslot2, unsigned int slot2) 430 | { 431 | struct sock *sk, *result; 432 | struct hlist_nulls_node *node; 433 | int score, badness, matches = 0, reuseport = 0; 434 | u32 hash = 0; 435 | 436 | begin: 437 | result = NULL; 438 | badness = 0; 439 | udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) { 440 | score = compute_score2(sk, net, saddr, sport, 441 | daddr, hnum, dif); 442 | if (score > badness) { 443 | result = sk; 444 | badness = score; 445 | reuseport = sk->sk_reuseport; 446 | if (reuseport) { 447 | hash = udp_ehashfn(net, daddr, hnum, 448 | saddr, sport); 449 | matches = 1; 450 | } 451 | } else if (score == badness && reuseport) { 452 | matches++; 453 | if (reciprocal_scale(hash, matches) == 0) 454 | result = sk; 455 | hash = next_pseudo_random32(hash); 456 | } 457 | } 458 | /* 459 | * if the nulls value we got at the end of this lookup is 460 | * not the expected one, we must restart lookup. 461 | * We probably met an item that was moved to another chain. 462 | */ 463 | if (get_nulls_value(node) != slot2) 464 | goto begin; 465 | if (result) { 466 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) 467 | result = NULL; 468 | else if (unlikely(compute_score2(result, net, saddr, sport, 469 | daddr, hnum, dif) < badness)) { 470 | sock_put(result); 471 | goto begin; 472 | } 473 | } 474 | return result; 475 | } 476 | 477 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try 478 | * harder than this. -DaveM 479 | */ 480 | struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, 481 | __be16 sport, __be32 daddr, __be16 dport, 482 | int dif, struct udp_table *udptable) 483 | { 484 | struct sock *sk, *result; 485 | struct hlist_nulls_node *node; 486 | unsigned short hnum = ntohs(dport); 487 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); 488 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; 489 | int score, badness, matches = 0, reuseport = 0; 490 | u32 hash = 0; 491 | 492 | rcu_read_lock(); 493 | if (hslot->count > 10) { 494 | hash2 = udp4_portaddr_hash(net, daddr, hnum); 495 | slot2 = hash2 & udptable->mask; 496 | hslot2 = &udptable->hash2[slot2]; 497 | if (hslot->count < hslot2->count) 498 | goto begin; 499 | 500 | result = udp4_lib_lookup2(net, saddr, sport, 501 | daddr, hnum, dif, 502 | hslot2, slot2); 503 | if (!result) { 504 | hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum); 505 | slot2 = hash2 & udptable->mask; 506 | hslot2 = &udptable->hash2[slot2]; 507 | if (hslot->count < hslot2->count) 508 | goto begin; 509 | 510 | result = udp4_lib_lookup2(net, saddr, sport, 511 | htonl(INADDR_ANY), hnum, dif, 512 | hslot2, slot2); 513 | } 514 | rcu_read_unlock(); 515 | return result; 516 | } 517 | begin: 518 | result = NULL; 519 | badness = 0; 520 | sk_nulls_for_each_rcu(sk, node, &hslot->head) { 521 | score = compute_score(sk, net, saddr, hnum, sport, 522 | daddr, dport, dif); 523 | if (score > badness) { 524 | result = sk; 525 | badness = score; 526 | reuseport = sk->sk_reuseport; 527 | if (reuseport) { 528 | hash = udp_ehashfn(net, daddr, hnum, 529 | saddr, sport); 530 | matches = 1; 531 | } 532 | } else if (score == badness && reuseport) { 533 | matches++; 534 | if (reciprocal_scale(hash, matches) == 0) 535 | result = sk; 536 | hash = next_pseudo_random32(hash); 537 | } 538 | } 539 | /* 540 | * if the nulls value we got at the end of this lookup is 541 | * not the expected one, we must restart lookup. 542 | * We probably met an item that was moved to another chain. 543 | */ 544 | if (get_nulls_value(node) != slot) 545 | goto begin; 546 | 547 | if (result) { 548 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) 549 | result = NULL; 550 | else if (unlikely(compute_score(result, net, saddr, hnum, sport, 551 | daddr, dport, dif) < badness)) { 552 | sock_put(result); 553 | goto begin; 554 | } 555 | } 556 | rcu_read_unlock(); 557 | return result; 558 | } 559 | EXPORT_SYMBOL_GPL(__udp4_lib_lookup); 560 | 561 | static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, 562 | __be16 sport, __be16 dport, 563 | struct udp_table *udptable) 564 | { 565 | const struct iphdr *iph = ip_hdr(skb); 566 | 567 | return __udp4_lib_lookup(dev_net(skb_dst(skb)->dev), iph->saddr, sport, 568 | iph->daddr, dport, inet_iif(skb), 569 | udptable); 570 | } 571 | 572 | struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, 573 | __be32 daddr, __be16 dport, int dif) 574 | { 575 | return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table); 576 | } 577 | EXPORT_SYMBOL_GPL(udp4_lib_lookup); 578 | 579 | static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, 580 | __be16 loc_port, __be32 loc_addr, 581 | __be16 rmt_port, __be32 rmt_addr, 582 | int dif, unsigned short hnum) 583 | { 584 | struct inet_sock *inet = inet_sk(sk); 585 | 586 | if (!net_eq(sock_net(sk), net) || 587 | udp_sk(sk)->udp_port_hash != hnum || 588 | (inet->inet_daddr && inet->inet_daddr != rmt_addr) || 589 | (inet->inet_dport != rmt_port && inet->inet_dport) || 590 | (inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) || 591 | ipv6_only_sock(sk) || 592 | (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) 593 | return false; 594 | if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif)) 595 | return false; 596 | return true; 597 | } 598 | 599 | /* 600 | * This routine is called by the ICMP module when it gets some 601 | * sort of error condition. If err < 0 then the socket should 602 | * be closed and the error returned to the user. If err > 0 603 | * it's just the icmp type << 8 | icmp code. 604 | * Header points to the ip header of the error packet. We move 605 | * on past this. Then (as it used to claim before adjustment) 606 | * header points to the first 8 bytes of the udp header. We need 607 | * to find the appropriate port. 608 | */ 609 | 610 | void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) 611 | { 612 | struct inet_sock *inet; 613 | const struct iphdr *iph = (const struct iphdr *)skb->data; 614 | struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2)); 615 | const int type = icmp_hdr(skb)->type; 616 | const int code = icmp_hdr(skb)->code; 617 | struct sock *sk; 618 | int harderr; 619 | int err; 620 | struct net *net = dev_net(skb->dev); 621 | 622 | sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, 623 | iph->saddr, uh->source, skb->dev->ifindex, udptable); 624 | if (sk == NULL) { 625 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); 626 | return; /* No socket for error */ 627 | } 628 | 629 | err = 0; 630 | harderr = 0; 631 | inet = inet_sk(sk); 632 | 633 | switch (type) { 634 | default: 635 | case ICMP_TIME_EXCEEDED: 636 | err = EHOSTUNREACH; 637 | break; 638 | case ICMP_SOURCE_QUENCH: 639 | goto out; 640 | case ICMP_PARAMETERPROB: 641 | err = EPROTO; 642 | harderr = 1; 643 | break; 644 | case ICMP_DEST_UNREACH: 645 | if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ 646 | ipv4_sk_update_pmtu(skb, sk, info); 647 | if (inet->pmtudisc != IP_PMTUDISC_DONT) { 648 | err = EMSGSIZE; 649 | harderr = 1; 650 | break; 651 | } 652 | goto out; 653 | } 654 | err = EHOSTUNREACH; 655 | if (code <= NR_ICMP_UNREACH) { 656 | harderr = icmp_err_convert[code].fatal; 657 | err = icmp_err_convert[code].errno; 658 | } 659 | break; 660 | case ICMP_REDIRECT: 661 | ipv4_sk_redirect(skb, sk); 662 | goto out; 663 | } 664 | 665 | /* 666 | * RFC1122: OK. Passes ICMP errors back to application, as per 667 | * 4.1.3.3. 668 | */ 669 | if (!inet->recverr) { 670 | if (!harderr || sk->sk_state != TCP_ESTABLISHED) 671 | goto out; 672 | } else 673 | ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1)); 674 | 675 | sk->sk_err = err; 676 | sk->sk_error_report(sk); 677 | out: 678 | sock_put(sk); 679 | } 680 | 681 | void udp_err(struct sk_buff *skb, u32 info) 682 | { 683 | __udp4_lib_err(skb, info, &udp_table); 684 | } 685 | 686 | /* 687 | * Throw away all pending data and cancel the corking. Socket is locked. 688 | */ 689 | void udp_flush_pending_frames(struct sock *sk) 690 | { 691 | struct udp_sock *up = udp_sk(sk); 692 | 693 | if (up->pending) { 694 | up->len = 0; 695 | up->pending = 0; 696 | ip_flush_pending_frames(sk); 697 | } 698 | } 699 | EXPORT_SYMBOL(udp_flush_pending_frames); 700 | 701 | /** 702 | * udp4_hwcsum - handle outgoing HW checksumming 703 | * @skb: sk_buff containing the filled-in UDP header 704 | * (checksum field must be zeroed out) 705 | * @src: source IP address 706 | * @dst: destination IP address 707 | */ 708 | void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst) 709 | { 710 | struct udphdr *uh = udp_hdr(skb); 711 | int offset = skb_transport_offset(skb); 712 | int len = skb->len - offset; 713 | int hlen = len; 714 | __wsum csum = 0; 715 | 716 | if (!skb_has_frag_list(skb)) { 717 | /* 718 | * Only one fragment on the socket. 719 | */ 720 | skb->csum_start = skb_transport_header(skb) - skb->head; 721 | skb->csum_offset = offsetof(struct udphdr, check); 722 | uh->check = ~csum_tcpudp_magic(src, dst, len, 723 | IPPROTO_UDP, 0); 724 | } else { 725 | struct sk_buff *frags; 726 | 727 | /* 728 | * HW-checksum won't work as there are two or more 729 | * fragments on the socket so that all csums of sk_buffs 730 | * should be together 731 | */ 732 | skb_walk_frags(skb, frags) { 733 | csum = csum_add(csum, frags->csum); 734 | hlen -= frags->len; 735 | } 736 | 737 | csum = skb_checksum(skb, offset, hlen, csum); 738 | skb->ip_summed = CHECKSUM_NONE; 739 | 740 | uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); 741 | if (uh->check == 0) 742 | uh->check = CSUM_MANGLED_0; 743 | } 744 | } 745 | EXPORT_SYMBOL_GPL(udp4_hwcsum); 746 | 747 | /* Function to set UDP checksum for an IPv4 UDP packet. This is intended 748 | * for the simple case like when setting the checksum for a UDP tunnel. 749 | */ 750 | void udp_set_csum(bool nocheck, struct sk_buff *skb, 751 | __be32 saddr, __be32 daddr, int len) 752 | { 753 | struct udphdr *uh = udp_hdr(skb); 754 | 755 | if (nocheck) 756 | uh->check = 0; 757 | else if (skb_is_gso(skb)) 758 | uh->check = ~udp_v4_check(len, saddr, daddr, 0); 759 | else if (skb_dst(skb) && skb_dst(skb)->dev && 760 | (skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { 761 | 762 | BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 763 | 764 | skb->ip_summed = CHECKSUM_PARTIAL; 765 | skb->csum_start = skb_transport_header(skb) - skb->head; 766 | skb->csum_offset = offsetof(struct udphdr, check); 767 | uh->check = ~udp_v4_check(len, saddr, daddr, 0); 768 | } else { 769 | __wsum csum; 770 | 771 | BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 772 | 773 | uh->check = 0; 774 | csum = skb_checksum(skb, 0, len, 0); 775 | uh->check = udp_v4_check(len, saddr, daddr, csum); 776 | if (uh->check == 0) 777 | uh->check = CSUM_MANGLED_0; 778 | 779 | skb->ip_summed = CHECKSUM_UNNECESSARY; 780 | } 781 | } 782 | EXPORT_SYMBOL(udp_set_csum); 783 | 784 | static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) 785 | { 786 | struct sock *sk = skb->sk; 787 | struct inet_sock *inet = inet_sk(sk); 788 | struct udphdr *uh; 789 | int err = 0; 790 | int is_udplite = IS_UDPLITE(sk); 791 | int offset = skb_transport_offset(skb); 792 | int len = skb->len - offset; 793 | __wsum csum = 0; 794 | 795 | /* 796 | * Create a UDP header 797 | */ 798 | uh = udp_hdr(skb); 799 | uh->source = inet->inet_sport; 800 | uh->dest = fl4->fl4_dport; 801 | uh->len = htons(len); 802 | uh->check = 0; 803 | 804 | if (is_udplite) /* UDP-Lite */ 805 | csum = udplite_csum(skb); 806 | 807 | else if (sk->sk_no_check_tx) { /* UDP csum disabled */ 808 | 809 | skb->ip_summed = CHECKSUM_NONE; 810 | goto send; 811 | 812 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ 813 | 814 | udp4_hwcsum(skb, fl4->saddr, fl4->daddr); 815 | goto send; 816 | 817 | } else 818 | csum = udp_csum(skb); 819 | 820 | /* add protocol-dependent pseudo-header */ 821 | uh->check = csum_tcpudp_magic(fl4->saddr, fl4->daddr, len, 822 | sk->sk_protocol, csum); 823 | if (uh->check == 0) 824 | uh->check = CSUM_MANGLED_0; 825 | 826 | send: 827 | err = ip_send_skb(sock_net(sk), skb); 828 | if (err) { 829 | if (err == -ENOBUFS && !inet->recverr) { 830 | UDP_INC_STATS_USER(sock_net(sk), 831 | UDP_MIB_SNDBUFERRORS, is_udplite); 832 | err = 0; 833 | } 834 | } else 835 | UDP_INC_STATS_USER(sock_net(sk), 836 | UDP_MIB_OUTDATAGRAMS, is_udplite); 837 | return err; 838 | } 839 | 840 | /* 841 | * Push out all pending data as one UDP datagram. Socket is locked. 842 | */ 843 | int udp_push_pending_frames(struct sock *sk) 844 | { 845 | struct udp_sock *up = udp_sk(sk); 846 | struct inet_sock *inet = inet_sk(sk); 847 | struct flowi4 *fl4 = &inet->cork.fl.u.ip4; 848 | struct sk_buff *skb; 849 | int err = 0; 850 | 851 | skb = ip_finish_skb(sk, fl4); 852 | if (!skb) 853 | goto out; 854 | 855 | err = udp_send_skb(skb, fl4); 856 | 857 | out: 858 | up->len = 0; 859 | up->pending = 0; 860 | return err; 861 | } 862 | EXPORT_SYMBOL(udp_push_pending_frames); 863 | 864 | 865 | /*MPUDP: Module code*/ 866 | int (*mpudp_send_function)(struct sockaddr_in *) = 0; 867 | void (*mpudp_recv_function)(struct sockaddr_in *) = 0; 868 | 869 | EXPORT_SYMBOL(mpudp_send_function); 870 | EXPORT_SYMBOL(mpudp_recv_function); 871 | /*MPUDP: Module code*/ 872 | 873 | 874 | int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 875 | size_t len) 876 | { 877 | struct inet_sock *inet = inet_sk(sk); 878 | struct udp_sock *up = udp_sk(sk); 879 | struct flowi4 fl4_stack; 880 | struct flowi4 *fl4; 881 | int ulen = len; 882 | struct ipcm_cookie ipc; 883 | struct rtable *rt = NULL; 884 | int free = 0; 885 | int connected = 0; 886 | __be32 daddr, faddr, saddr; 887 | __be16 dport; 888 | u8 tos; 889 | int err, is_udplite = IS_UDPLITE(sk); 890 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; 891 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); 892 | struct sk_buff *skb; 893 | struct ip_options_data opt_copy; 894 | 895 | if (len > 0xFFFF) 896 | return -EMSGSIZE; 897 | 898 | /* 899 | * Check the flags. 900 | */ 901 | 902 | if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ 903 | return -EOPNOTSUPP; 904 | 905 | ipc.opt = NULL; 906 | ipc.tx_flags = 0; 907 | ipc.ttl = 0; 908 | ipc.tos = -1; 909 | 910 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; 911 | 912 | fl4 = &inet->cork.fl.u.ip4; 913 | if (up->pending) { 914 | /* 915 | * There are pending frames. 916 | * The socket lock must be held while it's corked. 917 | */ 918 | lock_sock(sk); 919 | if (likely(up->pending)) { 920 | if (unlikely(up->pending != AF_INET)) { 921 | release_sock(sk); 922 | return -EINVAL; 923 | } 924 | goto do_append_data; 925 | } 926 | release_sock(sk); 927 | } 928 | ulen += sizeof(struct udphdr); 929 | 930 | /* 931 | * Get and verify the address. 932 | */ 933 | if (msg->msg_name) { 934 | DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); 935 | if (msg->msg_namelen < sizeof(*usin)) 936 | return -EINVAL; 937 | if (usin->sin_family != AF_INET) { 938 | if (usin->sin_family != AF_UNSPEC) 939 | return -EAFNOSUPPORT; 940 | } 941 | 942 | daddr = usin->sin_addr.s_addr; 943 | dport = usin->sin_port; 944 | 945 | /*MPUDP*/ 946 | if (mpudp_send_function && (*mpudp_send_function)(usin)){ 947 | daddr = usin->sin_addr.s_addr; 948 | } 949 | /*MPUDP*/ 950 | 951 | if (dport == 0) 952 | return -EINVAL; 953 | } else { 954 | if (sk->sk_state != TCP_ESTABLISHED) 955 | return -EDESTADDRREQ; 956 | daddr = inet->inet_daddr; 957 | dport = inet->inet_dport; 958 | /* Open fast path for connected socket. 959 | Route will not be used, if at least one option is set. 960 | */ 961 | 962 | /*MPUDP*/ 963 | //this did not get called during my testing 964 | if (mpudp_send_function && (*mpudp_send_function)(usin)){ 965 | daddr = usin->sin_addr.s_addr; 966 | } 967 | /*MPUDP*/ 968 | 969 | connected = 1; 970 | } 971 | ipc.addr = inet->inet_saddr; 972 | 973 | ipc.oif = sk->sk_bound_dev_if; 974 | 975 | sock_tx_timestamp(sk, &ipc.tx_flags); 976 | 977 | if (msg->msg_controllen) { 978 | err = ip_cmsg_send(sock_net(sk), msg, &ipc, 979 | sk->sk_family == AF_INET6); 980 | if (err) 981 | return err; 982 | if (ipc.opt) 983 | free = 1; 984 | connected = 0; 985 | } 986 | if (!ipc.opt) { 987 | struct ip_options_rcu *inet_opt; 988 | 989 | rcu_read_lock(); 990 | inet_opt = rcu_dereference(inet->inet_opt); 991 | if (inet_opt) { 992 | memcpy(&opt_copy, inet_opt, 993 | sizeof(*inet_opt) + inet_opt->opt.optlen); 994 | ipc.opt = &opt_copy.opt; 995 | } 996 | rcu_read_unlock(); 997 | } 998 | 999 | saddr = ipc.addr; 1000 | ipc.addr = faddr = daddr; 1001 | 1002 | if (ipc.opt && ipc.opt->opt.srr) { 1003 | if (!daddr) 1004 | return -EINVAL; 1005 | faddr = ipc.opt->opt.faddr; 1006 | connected = 0; 1007 | } 1008 | tos = get_rttos(&ipc, inet); 1009 | if (sock_flag(sk, SOCK_LOCALROUTE) || 1010 | (msg->msg_flags & MSG_DONTROUTE) || 1011 | (ipc.opt && ipc.opt->opt.is_strictroute)) { 1012 | tos |= RTO_ONLINK; 1013 | connected = 0; 1014 | } 1015 | 1016 | if (ipv4_is_multicast(daddr)) { 1017 | if (!ipc.oif) 1018 | ipc.oif = inet->mc_index; 1019 | if (!saddr) 1020 | saddr = inet->mc_addr; 1021 | connected = 0; 1022 | } else if (!ipc.oif) 1023 | ipc.oif = inet->uc_index; 1024 | 1025 | if (connected) 1026 | rt = (struct rtable *)sk_dst_check(sk, 0); 1027 | 1028 | if (rt == NULL) { 1029 | struct net *net = sock_net(sk); 1030 | 1031 | fl4 = &fl4_stack; 1032 | flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, 1033 | RT_SCOPE_UNIVERSE, sk->sk_protocol, 1034 | inet_sk_flowi_flags(sk), 1035 | faddr, saddr, dport, inet->inet_sport); 1036 | 1037 | security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); 1038 | rt = ip_route_output_flow(net, fl4, sk); 1039 | if (IS_ERR(rt)) { 1040 | err = PTR_ERR(rt); 1041 | rt = NULL; 1042 | if (err == -ENETUNREACH) 1043 | IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); 1044 | goto out; 1045 | } 1046 | 1047 | err = -EACCES; 1048 | if ((rt->rt_flags & RTCF_BROADCAST) && 1049 | !sock_flag(sk, SOCK_BROADCAST)) 1050 | goto out; 1051 | if (connected) 1052 | sk_dst_set(sk, dst_clone(&rt->dst)); 1053 | } 1054 | 1055 | if (msg->msg_flags&MSG_CONFIRM) 1056 | goto do_confirm; 1057 | back_from_confirm: 1058 | 1059 | saddr = fl4->saddr; 1060 | if (!ipc.addr) 1061 | daddr = ipc.addr = fl4->daddr; 1062 | 1063 | /* Lockless fast path for the non-corking case. */ 1064 | if (!corkreq) { 1065 | skb = ip_make_skb(sk, fl4, getfrag, msg->msg_iov, ulen, 1066 | sizeof(struct udphdr), &ipc, &rt, 1067 | msg->msg_flags); 1068 | err = PTR_ERR(skb); 1069 | if (!IS_ERR_OR_NULL(skb)) 1070 | err = udp_send_skb(skb, fl4); 1071 | goto out; 1072 | } 1073 | 1074 | lock_sock(sk); 1075 | if (unlikely(up->pending)) { 1076 | /* The socket is already corked while preparing it. */ 1077 | /* ... which is an evident application bug. --ANK */ 1078 | release_sock(sk); 1079 | 1080 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("cork app bug 2\n")); 1081 | err = -EINVAL; 1082 | goto out; 1083 | } 1084 | /* 1085 | * Now cork the socket to pend data. 1086 | */ 1087 | fl4 = &inet->cork.fl.u.ip4; 1088 | fl4->daddr = daddr; 1089 | fl4->saddr = saddr; 1090 | fl4->fl4_dport = dport; 1091 | fl4->fl4_sport = inet->inet_sport; 1092 | up->pending = AF_INET; 1093 | 1094 | do_append_data: 1095 | up->len += ulen; 1096 | err = ip_append_data(sk, fl4, getfrag, msg->msg_iov, ulen, 1097 | sizeof(struct udphdr), &ipc, &rt, 1098 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); 1099 | if (err) 1100 | udp_flush_pending_frames(sk); 1101 | else if (!corkreq) 1102 | err = udp_push_pending_frames(sk); 1103 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) 1104 | up->pending = 0; 1105 | release_sock(sk); 1106 | 1107 | out: 1108 | ip_rt_put(rt); 1109 | if (free) 1110 | kfree(ipc.opt); 1111 | if (!err) 1112 | return len; 1113 | /* 1114 | * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting 1115 | * ENOBUFS might not be good (it's not tunable per se), but otherwise 1116 | * we don't have a good statistic (IpOutDiscards but it can be too many 1117 | * things). We could add another new stat but at least for now that 1118 | * seems like overkill. 1119 | */ 1120 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { 1121 | UDP_INC_STATS_USER(sock_net(sk), 1122 | UDP_MIB_SNDBUFERRORS, is_udplite); 1123 | } 1124 | return err; 1125 | 1126 | do_confirm: 1127 | dst_confirm(&rt->dst); 1128 | if (!(msg->msg_flags&MSG_PROBE) || len) 1129 | goto back_from_confirm; 1130 | err = 0; 1131 | goto out; 1132 | } 1133 | EXPORT_SYMBOL(udp_sendmsg); 1134 | 1135 | int udp_sendpage(struct sock *sk, struct page *page, int offset, 1136 | size_t size, int flags) 1137 | { 1138 | struct inet_sock *inet = inet_sk(sk); 1139 | struct udp_sock *up = udp_sk(sk); 1140 | int ret; 1141 | 1142 | if (flags & MSG_SENDPAGE_NOTLAST) 1143 | flags |= MSG_MORE; 1144 | 1145 | if (!up->pending) { 1146 | struct msghdr msg = { .msg_flags = flags|MSG_MORE }; 1147 | 1148 | /* Call udp_sendmsg to specify destination address which 1149 | * sendpage interface can't pass. 1150 | * This will succeed only when the socket is connected. 1151 | */ 1152 | ret = udp_sendmsg(NULL, sk, &msg, 0); 1153 | if (ret < 0) 1154 | return ret; 1155 | } 1156 | 1157 | lock_sock(sk); 1158 | 1159 | if (unlikely(!up->pending)) { 1160 | release_sock(sk); 1161 | 1162 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("udp cork app bug 3\n")); 1163 | return -EINVAL; 1164 | } 1165 | 1166 | ret = ip_append_page(sk, &inet->cork.fl.u.ip4, 1167 | page, offset, size, flags); 1168 | if (ret == -EOPNOTSUPP) { 1169 | release_sock(sk); 1170 | return sock_no_sendpage(sk->sk_socket, page, offset, 1171 | size, flags); 1172 | } 1173 | if (ret < 0) { 1174 | udp_flush_pending_frames(sk); 1175 | goto out; 1176 | } 1177 | 1178 | up->len += size; 1179 | if (!(up->corkflag || (flags&MSG_MORE))) 1180 | ret = udp_push_pending_frames(sk); 1181 | if (!ret) 1182 | ret = size; 1183 | out: 1184 | release_sock(sk); 1185 | return ret; 1186 | } 1187 | 1188 | 1189 | /** 1190 | * first_packet_length - return length of first packet in receive queue 1191 | * @sk: socket 1192 | * 1193 | * Drops all bad checksum frames, until a valid one is found. 1194 | * Returns the length of found skb, or 0 if none is found. 1195 | */ 1196 | static unsigned int first_packet_length(struct sock *sk) 1197 | { 1198 | struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue; 1199 | struct sk_buff *skb; 1200 | unsigned int res; 1201 | 1202 | __skb_queue_head_init(&list_kill); 1203 | 1204 | spin_lock_bh(&rcvq->lock); 1205 | while ((skb = skb_peek(rcvq)) != NULL && 1206 | udp_lib_checksum_complete(skb)) { 1207 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS, 1208 | IS_UDPLITE(sk)); 1209 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, 1210 | IS_UDPLITE(sk)); 1211 | atomic_inc(&sk->sk_drops); 1212 | __skb_unlink(skb, rcvq); 1213 | __skb_queue_tail(&list_kill, skb); 1214 | } 1215 | res = skb ? skb->len : 0; 1216 | spin_unlock_bh(&rcvq->lock); 1217 | 1218 | if (!skb_queue_empty(&list_kill)) { 1219 | bool slow = lock_sock_fast(sk); 1220 | 1221 | __skb_queue_purge(&list_kill); 1222 | sk_mem_reclaim_partial(sk); 1223 | unlock_sock_fast(sk, slow); 1224 | } 1225 | return res; 1226 | } 1227 | 1228 | /* 1229 | * IOCTL requests applicable to the UDP protocol 1230 | */ 1231 | 1232 | int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) 1233 | { 1234 | switch (cmd) { 1235 | case SIOCOUTQ: 1236 | { 1237 | int amount = sk_wmem_alloc_get(sk); 1238 | 1239 | return put_user(amount, (int __user *)arg); 1240 | } 1241 | 1242 | case SIOCINQ: 1243 | { 1244 | unsigned int amount = first_packet_length(sk); 1245 | 1246 | if (amount) 1247 | /* 1248 | * We will only return the amount 1249 | * of this packet since that is all 1250 | * that will be read. 1251 | */ 1252 | amount -= sizeof(struct udphdr); 1253 | 1254 | return put_user(amount, (int __user *)arg); 1255 | } 1256 | 1257 | default: 1258 | return -ENOIOCTLCMD; 1259 | } 1260 | 1261 | return 0; 1262 | } 1263 | EXPORT_SYMBOL(udp_ioctl); 1264 | 1265 | /* 1266 | * This should be easy, if there is something there we 1267 | * return it, otherwise we block. 1268 | */ 1269 | 1270 | int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 1271 | size_t len, int noblock, int flags, int *addr_len) 1272 | { 1273 | struct inet_sock *inet = inet_sk(sk); 1274 | DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); 1275 | struct sk_buff *skb; 1276 | unsigned int ulen, copied; 1277 | int peeked, off = 0; 1278 | int err; 1279 | int is_udplite = IS_UDPLITE(sk); 1280 | bool slow; 1281 | 1282 | if (flags & MSG_ERRQUEUE) 1283 | return ip_recv_error(sk, msg, len, addr_len); 1284 | 1285 | try_again: 1286 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), 1287 | &peeked, &off, &err); 1288 | if (!skb) 1289 | goto out; 1290 | 1291 | ulen = skb->len - sizeof(struct udphdr); 1292 | copied = len; 1293 | if (copied > ulen) 1294 | copied = ulen; 1295 | else if (copied < ulen) 1296 | msg->msg_flags |= MSG_TRUNC; 1297 | 1298 | /* 1299 | * If checksum is needed at all, try to do it while copying the 1300 | * data. If the data is truncated, or if we only want a partial 1301 | * coverage checksum (UDP-Lite), do it before the copy. 1302 | */ 1303 | 1304 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { 1305 | if (udp_lib_checksum_complete(skb)) 1306 | goto csum_copy_err; 1307 | } 1308 | 1309 | if (skb_csum_unnecessary(skb)) 1310 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), 1311 | msg->msg_iov, copied); 1312 | else { 1313 | err = skb_copy_and_csum_datagram_iovec(skb, 1314 | sizeof(struct udphdr), 1315 | msg->msg_iov); 1316 | 1317 | if (err == -EINVAL) 1318 | goto csum_copy_err; 1319 | } 1320 | 1321 | if (unlikely(err)) { 1322 | trace_kfree_skb(skb, udp_recvmsg); 1323 | if (!peeked) { 1324 | atomic_inc(&sk->sk_drops); 1325 | UDP_INC_STATS_USER(sock_net(sk), 1326 | UDP_MIB_INERRORS, is_udplite); 1327 | } 1328 | goto out_free; 1329 | } 1330 | 1331 | if (!peeked) 1332 | UDP_INC_STATS_USER(sock_net(sk), 1333 | UDP_MIB_INDATAGRAMS, is_udplite); 1334 | 1335 | sock_recv_ts_and_drops(msg, sk, skb); 1336 | 1337 | /* Copy the address. */ 1338 | if (sin) { 1339 | sin->sin_family = AF_INET; 1340 | sin->sin_port = udp_hdr(skb)->source; 1341 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; 1342 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 1343 | *addr_len = sizeof(*sin); 1344 | 1345 | /*MPUDP*/ 1346 | if (mpudp_recv_function) { 1347 | (*mpudp_recv_function)(sin); 1348 | } 1349 | /*MPUDP*/ 1350 | 1351 | 1352 | } 1353 | if (inet->cmsg_flags) 1354 | ip_cmsg_recv(msg, skb); 1355 | 1356 | err = copied; 1357 | if (flags & MSG_TRUNC) 1358 | err = ulen; 1359 | 1360 | out_free: 1361 | skb_free_datagram_locked(sk, skb); 1362 | out: 1363 | return err; 1364 | 1365 | csum_copy_err: 1366 | slow = lock_sock_fast(sk); 1367 | if (!skb_kill_datagram(sk, skb, flags)) { 1368 | UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); 1369 | UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 1370 | } 1371 | unlock_sock_fast(sk, slow); 1372 | 1373 | /* starting over for a new packet, but check if we need to yield */ 1374 | cond_resched(); 1375 | msg->msg_flags &= ~MSG_TRUNC; 1376 | goto try_again; 1377 | } 1378 | 1379 | 1380 | int udp_disconnect(struct sock *sk, int flags) 1381 | { 1382 | struct inet_sock *inet = inet_sk(sk); 1383 | /* 1384 | * 1003.1g - break association. 1385 | */ 1386 | 1387 | sk->sk_state = TCP_CLOSE; 1388 | inet->inet_daddr = 0; 1389 | inet->inet_dport = 0; 1390 | sock_rps_reset_rxhash(sk); 1391 | sk->sk_bound_dev_if = 0; 1392 | if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) 1393 | inet_reset_saddr(sk); 1394 | 1395 | if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) { 1396 | sk->sk_prot->unhash(sk); 1397 | inet->inet_sport = 0; 1398 | } 1399 | sk_dst_reset(sk); 1400 | return 0; 1401 | } 1402 | EXPORT_SYMBOL(udp_disconnect); 1403 | 1404 | void udp_lib_unhash(struct sock *sk) 1405 | { 1406 | if (sk_hashed(sk)) { 1407 | struct udp_table *udptable = sk->sk_prot->h.udp_table; 1408 | struct udp_hslot *hslot, *hslot2; 1409 | 1410 | hslot = udp_hashslot(udptable, sock_net(sk), 1411 | udp_sk(sk)->udp_port_hash); 1412 | hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); 1413 | 1414 | spin_lock_bh(&hslot->lock); 1415 | if (sk_nulls_del_node_init_rcu(sk)) { 1416 | hslot->count--; 1417 | inet_sk(sk)->inet_num = 0; 1418 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 1419 | 1420 | spin_lock(&hslot2->lock); 1421 | hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); 1422 | hslot2->count--; 1423 | spin_unlock(&hslot2->lock); 1424 | } 1425 | spin_unlock_bh(&hslot->lock); 1426 | } 1427 | } 1428 | EXPORT_SYMBOL(udp_lib_unhash); 1429 | 1430 | /* 1431 | * inet_rcv_saddr was changed, we must rehash secondary hash 1432 | */ 1433 | void udp_lib_rehash(struct sock *sk, u16 newhash) 1434 | { 1435 | if (sk_hashed(sk)) { 1436 | struct udp_table *udptable = sk->sk_prot->h.udp_table; 1437 | struct udp_hslot *hslot, *hslot2, *nhslot2; 1438 | 1439 | hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); 1440 | nhslot2 = udp_hashslot2(udptable, newhash); 1441 | udp_sk(sk)->udp_portaddr_hash = newhash; 1442 | if (hslot2 != nhslot2) { 1443 | hslot = udp_hashslot(udptable, sock_net(sk), 1444 | udp_sk(sk)->udp_port_hash); 1445 | /* we must lock primary chain too */ 1446 | spin_lock_bh(&hslot->lock); 1447 | 1448 | spin_lock(&hslot2->lock); 1449 | hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); 1450 | hslot2->count--; 1451 | spin_unlock(&hslot2->lock); 1452 | 1453 | spin_lock(&nhslot2->lock); 1454 | hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, 1455 | &nhslot2->head); 1456 | nhslot2->count++; 1457 | spin_unlock(&nhslot2->lock); 1458 | 1459 | spin_unlock_bh(&hslot->lock); 1460 | } 1461 | } 1462 | } 1463 | EXPORT_SYMBOL(udp_lib_rehash); 1464 | 1465 | static void udp_v4_rehash(struct sock *sk) 1466 | { 1467 | u16 new_hash = udp4_portaddr_hash(sock_net(sk), 1468 | inet_sk(sk)->inet_rcv_saddr, 1469 | inet_sk(sk)->inet_num); 1470 | udp_lib_rehash(sk, new_hash); 1471 | } 1472 | 1473 | static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 1474 | { 1475 | int rc; 1476 | 1477 | if (inet_sk(sk)->inet_daddr) { 1478 | sock_rps_save_rxhash(sk, skb); 1479 | sk_mark_napi_id(sk, skb); 1480 | } 1481 | 1482 | rc = sock_queue_rcv_skb(sk, skb); 1483 | if (rc < 0) { 1484 | int is_udplite = IS_UDPLITE(sk); 1485 | 1486 | /* Note that an ENOMEM error is charged twice */ 1487 | if (rc == -ENOMEM) 1488 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, 1489 | is_udplite); 1490 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 1491 | kfree_skb(skb); 1492 | trace_udp_fail_queue_rcv_skb(rc, sk); 1493 | return -1; 1494 | } 1495 | 1496 | return 0; 1497 | 1498 | } 1499 | 1500 | static struct static_key udp_encap_needed __read_mostly; 1501 | void udp_encap_enable(void) 1502 | { 1503 | if (!static_key_enabled(&udp_encap_needed)) 1504 | static_key_slow_inc(&udp_encap_needed); 1505 | } 1506 | EXPORT_SYMBOL(udp_encap_enable); 1507 | 1508 | /* returns: 1509 | * -1: error 1510 | * 0: success 1511 | * >0: "udp encap" protocol resubmission 1512 | * 1513 | * Note that in the success and error cases, the skb is assumed to 1514 | * have either been requeued or freed. 1515 | */ 1516 | int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 1517 | { 1518 | struct udp_sock *up = udp_sk(sk); 1519 | int rc; 1520 | int is_udplite = IS_UDPLITE(sk); 1521 | 1522 | /* 1523 | * Charge it to the socket, dropping if the queue is full. 1524 | */ 1525 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 1526 | goto drop; 1527 | nf_reset(skb); 1528 | 1529 | if (static_key_false(&udp_encap_needed) && up->encap_type) { 1530 | int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); 1531 | 1532 | /* 1533 | * This is an encapsulation socket so pass the skb to 1534 | * the socket's udp_encap_rcv() hook. Otherwise, just 1535 | * fall through and pass this up the UDP socket. 1536 | * up->encap_rcv() returns the following value: 1537 | * =0 if skb was successfully passed to the encap 1538 | * handler or was discarded by it. 1539 | * >0 if skb should be passed on to UDP. 1540 | * <0 if skb should be resubmitted as proto -N 1541 | */ 1542 | 1543 | /* if we're overly short, let UDP handle it */ 1544 | encap_rcv = ACCESS_ONCE(up->encap_rcv); 1545 | if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { 1546 | int ret; 1547 | 1548 | /* Verify checksum before giving to encap */ 1549 | if (udp_lib_checksum_complete(skb)) 1550 | goto csum_error; 1551 | 1552 | ret = encap_rcv(sk, skb); 1553 | if (ret <= 0) { 1554 | UDP_INC_STATS_BH(sock_net(sk), 1555 | UDP_MIB_INDATAGRAMS, 1556 | is_udplite); 1557 | return -ret; 1558 | } 1559 | } 1560 | 1561 | /* FALLTHROUGH -- it's a UDP Packet */ 1562 | } 1563 | 1564 | /* 1565 | * UDP-Lite specific tests, ignored on UDP sockets 1566 | */ 1567 | if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { 1568 | 1569 | /* 1570 | * MIB statistics other than incrementing the error count are 1571 | * disabled for the following two types of errors: these depend 1572 | * on the application settings, not on the functioning of the 1573 | * protocol stack as such. 1574 | * 1575 | * RFC 3828 here recommends (sec 3.3): "There should also be a 1576 | * way ... to ... at least let the receiving application block 1577 | * delivery of packets with coverage values less than a value 1578 | * provided by the application." 1579 | */ 1580 | if (up->pcrlen == 0) { /* full coverage was set */ 1581 | LIMIT_NETDEBUG(KERN_WARNING "UDPLite: partial coverage %d while full coverage %d requested\n", 1582 | UDP_SKB_CB(skb)->cscov, skb->len); 1583 | goto drop; 1584 | } 1585 | /* The next case involves violating the min. coverage requested 1586 | * by the receiver. This is subtle: if receiver wants x and x is 1587 | * greater than the buffersize/MTU then receiver will complain 1588 | * that it wants x while sender emits packets of smaller size y. 1589 | * Therefore the above ...()->partial_cov statement is essential. 1590 | */ 1591 | if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { 1592 | LIMIT_NETDEBUG(KERN_WARNING "UDPLite: coverage %d too small, need min %d\n", 1593 | UDP_SKB_CB(skb)->cscov, up->pcrlen); 1594 | goto drop; 1595 | } 1596 | } 1597 | 1598 | if (rcu_access_pointer(sk->sk_filter) && 1599 | udp_lib_checksum_complete(skb)) 1600 | goto csum_error; 1601 | 1602 | 1603 | if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { 1604 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, 1605 | is_udplite); 1606 | goto drop; 1607 | } 1608 | 1609 | rc = 0; 1610 | 1611 | ipv4_pktinfo_prepare(sk, skb); 1612 | bh_lock_sock(sk); 1613 | if (!sock_owned_by_user(sk)) 1614 | rc = __udp_queue_rcv_skb(sk, skb); 1615 | else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) { 1616 | bh_unlock_sock(sk); 1617 | goto drop; 1618 | } 1619 | bh_unlock_sock(sk); 1620 | 1621 | return rc; 1622 | 1623 | csum_error: 1624 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); 1625 | drop: 1626 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 1627 | atomic_inc(&sk->sk_drops); 1628 | kfree_skb(skb); 1629 | return -1; 1630 | } 1631 | 1632 | 1633 | static void flush_stack(struct sock **stack, unsigned int count, 1634 | struct sk_buff *skb, unsigned int final) 1635 | { 1636 | unsigned int i; 1637 | struct sk_buff *skb1 = NULL; 1638 | struct sock *sk; 1639 | 1640 | for (i = 0; i < count; i++) { 1641 | sk = stack[i]; 1642 | if (likely(skb1 == NULL)) 1643 | skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); 1644 | 1645 | if (!skb1) { 1646 | atomic_inc(&sk->sk_drops); 1647 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, 1648 | IS_UDPLITE(sk)); 1649 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, 1650 | IS_UDPLITE(sk)); 1651 | } 1652 | 1653 | if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0) 1654 | skb1 = NULL; 1655 | 1656 | sock_put(sk); 1657 | } 1658 | if (unlikely(skb1)) 1659 | kfree_skb(skb1); 1660 | } 1661 | 1662 | /* For TCP sockets, sk_rx_dst is protected by socket lock 1663 | * For UDP, we use xchg() to guard against concurrent changes. 1664 | */ 1665 | static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) 1666 | { 1667 | struct dst_entry *old; 1668 | 1669 | dst_hold(dst); 1670 | old = xchg(&sk->sk_rx_dst, dst); 1671 | dst_release(old); 1672 | } 1673 | 1674 | /* 1675 | * Multicasts and broadcasts go to each listener. 1676 | * 1677 | * Note: called only from the BH handler context. 1678 | */ 1679 | static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, 1680 | struct udphdr *uh, 1681 | __be32 saddr, __be32 daddr, 1682 | struct udp_table *udptable) 1683 | { 1684 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; 1685 | struct hlist_nulls_node *node; 1686 | unsigned short hnum = ntohs(uh->dest); 1687 | struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); 1688 | int dif = skb->dev->ifindex; 1689 | unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node); 1690 | unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); 1691 | 1692 | if (use_hash2) { 1693 | hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) & 1694 | udp_table.mask; 1695 | hash2 = udp4_portaddr_hash(net, daddr, hnum) & udp_table.mask; 1696 | start_lookup: 1697 | hslot = &udp_table.hash2[hash2]; 1698 | offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); 1699 | } 1700 | 1701 | spin_lock(&hslot->lock); 1702 | sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) { 1703 | if (__udp_is_mcast_sock(net, sk, 1704 | uh->dest, daddr, 1705 | uh->source, saddr, 1706 | dif, hnum)) { 1707 | if (unlikely(count == ARRAY_SIZE(stack))) { 1708 | flush_stack(stack, count, skb, ~0); 1709 | count = 0; 1710 | } 1711 | stack[count++] = sk; 1712 | sock_hold(sk); 1713 | } 1714 | } 1715 | 1716 | spin_unlock(&hslot->lock); 1717 | 1718 | /* Also lookup *:port if we are using hash2 and haven't done so yet. */ 1719 | if (use_hash2 && hash2 != hash2_any) { 1720 | hash2 = hash2_any; 1721 | goto start_lookup; 1722 | } 1723 | 1724 | /* 1725 | * do the slow work with no lock held 1726 | */ 1727 | if (count) { 1728 | flush_stack(stack, count, skb, count - 1); 1729 | } else { 1730 | kfree_skb(skb); 1731 | } 1732 | return 0; 1733 | } 1734 | 1735 | /* Initialize UDP checksum. If exited with zero value (success), 1736 | * CHECKSUM_UNNECESSARY means, that no more checks are required. 1737 | * Otherwise, csum completion requires chacksumming packet body, 1738 | * including udp header and folding it to skb->csum. 1739 | */ 1740 | static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, 1741 | int proto) 1742 | { 1743 | int err; 1744 | 1745 | UDP_SKB_CB(skb)->partial_cov = 0; 1746 | UDP_SKB_CB(skb)->cscov = skb->len; 1747 | 1748 | if (proto == IPPROTO_UDPLITE) { 1749 | err = udplite_checksum_init(skb, uh); 1750 | if (err) 1751 | return err; 1752 | } 1753 | 1754 | return skb_checksum_init_zero_check(skb, proto, uh->check, 1755 | inet_compute_pseudo); 1756 | } 1757 | 1758 | /* 1759 | * All we need to do is get the socket, and then do a checksum. 1760 | */ 1761 | 1762 | int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, 1763 | int proto) 1764 | { 1765 | struct sock *sk; 1766 | struct udphdr *uh; 1767 | unsigned short ulen; 1768 | struct rtable *rt = skb_rtable(skb); 1769 | __be32 saddr, daddr; 1770 | struct net *net = dev_net(skb->dev); 1771 | 1772 | /* 1773 | * Validate the packet. 1774 | */ 1775 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) 1776 | goto drop; /* No space for header. */ 1777 | 1778 | uh = udp_hdr(skb); 1779 | ulen = ntohs(uh->len); 1780 | saddr = ip_hdr(skb)->saddr; 1781 | daddr = ip_hdr(skb)->daddr; 1782 | 1783 | if (ulen > skb->len) 1784 | goto short_packet; 1785 | 1786 | if (proto == IPPROTO_UDP) { 1787 | /* UDP validates ulen. */ 1788 | if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) 1789 | goto short_packet; 1790 | uh = udp_hdr(skb); 1791 | } 1792 | 1793 | if (udp4_csum_init(skb, uh, proto)) 1794 | goto csum_error; 1795 | 1796 | sk = skb_steal_sock(skb); 1797 | if (sk) { 1798 | struct dst_entry *dst = skb_dst(skb); 1799 | int ret; 1800 | 1801 | if (unlikely(sk->sk_rx_dst != dst)) 1802 | udp_sk_rx_dst_set(sk, dst); 1803 | 1804 | ret = udp_queue_rcv_skb(sk, skb); 1805 | sock_put(sk); 1806 | /* a return value > 0 means to resubmit the input, but 1807 | * it wants the return to be -protocol, or 0 1808 | */ 1809 | if (ret > 0) 1810 | return -ret; 1811 | return 0; 1812 | } else { 1813 | if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) 1814 | return __udp4_lib_mcast_deliver(net, skb, uh, 1815 | saddr, daddr, udptable); 1816 | 1817 | sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); 1818 | } 1819 | 1820 | if (sk != NULL) { 1821 | int ret; 1822 | 1823 | if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk)) 1824 | skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check, 1825 | inet_compute_pseudo); 1826 | 1827 | ret = udp_queue_rcv_skb(sk, skb); 1828 | sock_put(sk); 1829 | 1830 | /* a return value > 0 means to resubmit the input, but 1831 | * it wants the return to be -protocol, or 0 1832 | */ 1833 | if (ret > 0) 1834 | return -ret; 1835 | return 0; 1836 | } 1837 | 1838 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 1839 | goto drop; 1840 | nf_reset(skb); 1841 | 1842 | /* No socket. Drop packet silently, if checksum is wrong */ 1843 | if (udp_lib_checksum_complete(skb)) 1844 | goto csum_error; 1845 | 1846 | UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); 1847 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 1848 | 1849 | /* 1850 | * Hmm. We got an UDP packet to a port to which we 1851 | * don't wanna listen. Ignore it. 1852 | */ 1853 | kfree_skb(skb); 1854 | return 0; 1855 | 1856 | short_packet: 1857 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", 1858 | proto == IPPROTO_UDPLITE ? "Lite" : "", 1859 | &saddr, ntohs(uh->source), 1860 | ulen, skb->len, 1861 | &daddr, ntohs(uh->dest)); 1862 | goto drop; 1863 | 1864 | csum_error: 1865 | /* 1866 | * RFC1122: OK. Discards the bad packet silently (as far as 1867 | * the network is concerned, anyway) as per 4.1.3.4 (MUST). 1868 | */ 1869 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", 1870 | proto == IPPROTO_UDPLITE ? "Lite" : "", 1871 | &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), 1872 | ulen); 1873 | UDP_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); 1874 | drop: 1875 | UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); 1876 | kfree_skb(skb); 1877 | return 0; 1878 | } 1879 | 1880 | /* We can only early demux multicast if there is a single matching socket. 1881 | * If more than one socket found returns NULL 1882 | */ 1883 | static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, 1884 | __be16 loc_port, __be32 loc_addr, 1885 | __be16 rmt_port, __be32 rmt_addr, 1886 | int dif) 1887 | { 1888 | struct sock *sk, *result; 1889 | struct hlist_nulls_node *node; 1890 | unsigned short hnum = ntohs(loc_port); 1891 | unsigned int count, slot = udp_hashfn(net, hnum, udp_table.mask); 1892 | struct udp_hslot *hslot = &udp_table.hash[slot]; 1893 | 1894 | /* Do not bother scanning a too big list */ 1895 | if (hslot->count > 10) 1896 | return NULL; 1897 | 1898 | rcu_read_lock(); 1899 | begin: 1900 | count = 0; 1901 | result = NULL; 1902 | sk_nulls_for_each_rcu(sk, node, &hslot->head) { 1903 | if (__udp_is_mcast_sock(net, sk, 1904 | loc_port, loc_addr, 1905 | rmt_port, rmt_addr, 1906 | dif, hnum)) { 1907 | result = sk; 1908 | ++count; 1909 | } 1910 | } 1911 | /* 1912 | * if the nulls value we got at the end of this lookup is 1913 | * not the expected one, we must restart lookup. 1914 | * We probably met an item that was moved to another chain. 1915 | */ 1916 | if (get_nulls_value(node) != slot) 1917 | goto begin; 1918 | 1919 | if (result) { 1920 | if (count != 1 || 1921 | unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) 1922 | result = NULL; 1923 | else if (unlikely(!__udp_is_mcast_sock(net, result, 1924 | loc_port, loc_addr, 1925 | rmt_port, rmt_addr, 1926 | dif, hnum))) { 1927 | sock_put(result); 1928 | result = NULL; 1929 | } 1930 | } 1931 | rcu_read_unlock(); 1932 | return result; 1933 | } 1934 | 1935 | /* For unicast we should only early demux connected sockets or we can 1936 | * break forwarding setups. The chains here can be long so only check 1937 | * if the first socket is an exact match and if not move on. 1938 | */ 1939 | static struct sock *__udp4_lib_demux_lookup(struct net *net, 1940 | __be16 loc_port, __be32 loc_addr, 1941 | __be16 rmt_port, __be32 rmt_addr, 1942 | int dif) 1943 | { 1944 | struct sock *sk, *result; 1945 | struct hlist_nulls_node *node; 1946 | unsigned short hnum = ntohs(loc_port); 1947 | unsigned int hash2 = udp4_portaddr_hash(net, loc_addr, hnum); 1948 | unsigned int slot2 = hash2 & udp_table.mask; 1949 | struct udp_hslot *hslot2 = &udp_table.hash2[slot2]; 1950 | INET_ADDR_COOKIE(acookie, rmt_addr, loc_addr); 1951 | const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum); 1952 | 1953 | rcu_read_lock(); 1954 | result = NULL; 1955 | udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) { 1956 | if (INET_MATCH(sk, net, acookie, 1957 | rmt_addr, loc_addr, ports, dif)) 1958 | result = sk; 1959 | /* Only check first socket in chain */ 1960 | break; 1961 | } 1962 | 1963 | if (result) { 1964 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) 1965 | result = NULL; 1966 | else if (unlikely(!INET_MATCH(sk, net, acookie, 1967 | rmt_addr, loc_addr, 1968 | ports, dif))) { 1969 | sock_put(result); 1970 | result = NULL; 1971 | } 1972 | } 1973 | rcu_read_unlock(); 1974 | return result; 1975 | } 1976 | 1977 | void udp_v4_early_demux(struct sk_buff *skb) 1978 | { 1979 | struct net *net = dev_net(skb->dev); 1980 | const struct iphdr *iph; 1981 | const struct udphdr *uh; 1982 | struct sock *sk; 1983 | struct dst_entry *dst; 1984 | int dif = skb->dev->ifindex; 1985 | int ours; 1986 | 1987 | /* validate the packet */ 1988 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr))) 1989 | return; 1990 | 1991 | iph = ip_hdr(skb); 1992 | uh = udp_hdr(skb); 1993 | 1994 | if (skb->pkt_type == PACKET_BROADCAST || 1995 | skb->pkt_type == PACKET_MULTICAST) { 1996 | struct in_device *in_dev = __in_dev_get_rcu(skb->dev); 1997 | 1998 | if (!in_dev) 1999 | return; 2000 | 2001 | /* we are supposed to accept bcast packets */ 2002 | if (skb->pkt_type == PACKET_MULTICAST) { 2003 | ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr, 2004 | iph->protocol); 2005 | if (!ours) 2006 | return; 2007 | } 2008 | 2009 | sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, 2010 | uh->source, iph->saddr, dif); 2011 | } else if (skb->pkt_type == PACKET_HOST) { 2012 | sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr, 2013 | uh->source, iph->saddr, dif); 2014 | } else { 2015 | return; 2016 | } 2017 | 2018 | if (!sk) 2019 | return; 2020 | 2021 | skb->sk = sk; 2022 | skb->destructor = sock_efree; 2023 | dst = READ_ONCE(sk->sk_rx_dst); 2024 | 2025 | if (dst) 2026 | dst = dst_check(dst, 0); 2027 | if (dst) { 2028 | /* DST_NOCACHE can not be used without taking a reference */ 2029 | if (dst->flags & DST_NOCACHE) { 2030 | if (likely(atomic_inc_not_zero(&dst->__refcnt))) 2031 | skb_dst_set(skb, dst); 2032 | } else { 2033 | skb_dst_set_noref(skb, dst); 2034 | } 2035 | } 2036 | } 2037 | 2038 | int udp_rcv(struct sk_buff *skb) 2039 | { 2040 | return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP); 2041 | } 2042 | 2043 | void udp_destroy_sock(struct sock *sk) 2044 | { 2045 | struct udp_sock *up = udp_sk(sk); 2046 | bool slow = lock_sock_fast(sk); 2047 | udp_flush_pending_frames(sk); 2048 | unlock_sock_fast(sk, slow); 2049 | if (static_key_false(&udp_encap_needed) && up->encap_type) { 2050 | void (*encap_destroy)(struct sock *sk); 2051 | encap_destroy = ACCESS_ONCE(up->encap_destroy); 2052 | if (encap_destroy) 2053 | encap_destroy(sk); 2054 | } 2055 | } 2056 | 2057 | /* 2058 | * Socket option code for UDP 2059 | */ 2060 | int udp_lib_setsockopt(struct sock *sk, int level, int optname, 2061 | char __user *optval, unsigned int optlen, 2062 | int (*push_pending_frames)(struct sock *)) 2063 | { 2064 | struct udp_sock *up = udp_sk(sk); 2065 | int val, valbool; 2066 | int err = 0; 2067 | int is_udplite = IS_UDPLITE(sk); 2068 | 2069 | if (optlen < sizeof(int)) 2070 | return -EINVAL; 2071 | 2072 | if (get_user(val, (int __user *)optval)) 2073 | return -EFAULT; 2074 | 2075 | valbool = val ? 1 : 0; 2076 | 2077 | switch (optname) { 2078 | case UDP_CORK: 2079 | if (val != 0) { 2080 | up->corkflag = 1; 2081 | } else { 2082 | up->corkflag = 0; 2083 | lock_sock(sk); 2084 | (*push_pending_frames)(sk); 2085 | release_sock(sk); 2086 | } 2087 | break; 2088 | 2089 | case UDP_ENCAP: 2090 | switch (val) { 2091 | case 0: 2092 | case UDP_ENCAP_ESPINUDP: 2093 | case UDP_ENCAP_ESPINUDP_NON_IKE: 2094 | up->encap_rcv = xfrm4_udp_encap_rcv; 2095 | /* FALLTHROUGH */ 2096 | case UDP_ENCAP_L2TPINUDP: 2097 | up->encap_type = val; 2098 | udp_encap_enable(); 2099 | break; 2100 | default: 2101 | err = -ENOPROTOOPT; 2102 | break; 2103 | } 2104 | break; 2105 | 2106 | case UDP_NO_CHECK6_TX: 2107 | up->no_check6_tx = valbool; 2108 | break; 2109 | 2110 | case UDP_NO_CHECK6_RX: 2111 | up->no_check6_rx = valbool; 2112 | break; 2113 | 2114 | /* 2115 | * UDP-Lite's partial checksum coverage (RFC 3828). 2116 | */ 2117 | /* The sender sets actual checksum coverage length via this option. 2118 | * The case coverage > packet length is handled by send module. */ 2119 | case UDPLITE_SEND_CSCOV: 2120 | if (!is_udplite) /* Disable the option on UDP sockets */ 2121 | return -ENOPROTOOPT; 2122 | if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ 2123 | val = 8; 2124 | else if (val > USHRT_MAX) 2125 | val = USHRT_MAX; 2126 | up->pcslen = val; 2127 | up->pcflag |= UDPLITE_SEND_CC; 2128 | break; 2129 | 2130 | /* The receiver specifies a minimum checksum coverage value. To make 2131 | * sense, this should be set to at least 8 (as done below). If zero is 2132 | * used, this again means full checksum coverage. */ 2133 | case UDPLITE_RECV_CSCOV: 2134 | if (!is_udplite) /* Disable the option on UDP sockets */ 2135 | return -ENOPROTOOPT; 2136 | if (val != 0 && val < 8) /* Avoid silly minimal values. */ 2137 | val = 8; 2138 | else if (val > USHRT_MAX) 2139 | val = USHRT_MAX; 2140 | up->pcrlen = val; 2141 | up->pcflag |= UDPLITE_RECV_CC; 2142 | break; 2143 | 2144 | default: 2145 | err = -ENOPROTOOPT; 2146 | break; 2147 | } 2148 | 2149 | return err; 2150 | } 2151 | EXPORT_SYMBOL(udp_lib_setsockopt); 2152 | 2153 | int udp_setsockopt(struct sock *sk, int level, int optname, 2154 | char __user *optval, unsigned int optlen) 2155 | { 2156 | if (level == SOL_UDP || level == SOL_UDPLITE) 2157 | return udp_lib_setsockopt(sk, level, optname, optval, optlen, 2158 | udp_push_pending_frames); 2159 | return ip_setsockopt(sk, level, optname, optval, optlen); 2160 | } 2161 | 2162 | #ifdef CONFIG_COMPAT 2163 | int compat_udp_setsockopt(struct sock *sk, int level, int optname, 2164 | char __user *optval, unsigned int optlen) 2165 | { 2166 | if (level == SOL_UDP || level == SOL_UDPLITE) 2167 | return udp_lib_setsockopt(sk, level, optname, optval, optlen, 2168 | udp_push_pending_frames); 2169 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); 2170 | } 2171 | #endif 2172 | 2173 | int udp_lib_getsockopt(struct sock *sk, int level, int optname, 2174 | char __user *optval, int __user *optlen) 2175 | { 2176 | struct udp_sock *up = udp_sk(sk); 2177 | int val, len; 2178 | 2179 | if (get_user(len, optlen)) 2180 | return -EFAULT; 2181 | 2182 | len = min_t(unsigned int, len, sizeof(int)); 2183 | 2184 | if (len < 0) 2185 | return -EINVAL; 2186 | 2187 | switch (optname) { 2188 | case UDP_CORK: 2189 | val = up->corkflag; 2190 | break; 2191 | 2192 | case UDP_ENCAP: 2193 | val = up->encap_type; 2194 | break; 2195 | 2196 | case UDP_NO_CHECK6_TX: 2197 | val = up->no_check6_tx; 2198 | break; 2199 | 2200 | case UDP_NO_CHECK6_RX: 2201 | val = up->no_check6_rx; 2202 | break; 2203 | 2204 | /* The following two cannot be changed on UDP sockets, the return is 2205 | * always 0 (which corresponds to the full checksum coverage of UDP). */ 2206 | case UDPLITE_SEND_CSCOV: 2207 | val = up->pcslen; 2208 | break; 2209 | 2210 | case UDPLITE_RECV_CSCOV: 2211 | val = up->pcrlen; 2212 | break; 2213 | 2214 | default: 2215 | return -ENOPROTOOPT; 2216 | } 2217 | 2218 | if (put_user(len, optlen)) 2219 | return -EFAULT; 2220 | if (copy_to_user(optval, &val, len)) 2221 | return -EFAULT; 2222 | return 0; 2223 | } 2224 | EXPORT_SYMBOL(udp_lib_getsockopt); 2225 | 2226 | int udp_getsockopt(struct sock *sk, int level, int optname, 2227 | char __user *optval, int __user *optlen) 2228 | { 2229 | if (level == SOL_UDP || level == SOL_UDPLITE) 2230 | return udp_lib_getsockopt(sk, level, optname, optval, optlen); 2231 | return ip_getsockopt(sk, level, optname, optval, optlen); 2232 | } 2233 | 2234 | #ifdef CONFIG_COMPAT 2235 | int compat_udp_getsockopt(struct sock *sk, int level, int optname, 2236 | char __user *optval, int __user *optlen) 2237 | { 2238 | if (level == SOL_UDP || level == SOL_UDPLITE) 2239 | return udp_lib_getsockopt(sk, level, optname, optval, optlen); 2240 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); 2241 | } 2242 | #endif 2243 | /** 2244 | * udp_poll - wait for a UDP event. 2245 | * @file - file struct 2246 | * @sock - socket 2247 | * @wait - poll table 2248 | * 2249 | * This is same as datagram poll, except for the special case of 2250 | * blocking sockets. If application is using a blocking fd 2251 | * and a packet with checksum error is in the queue; 2252 | * then it could get return from select indicating data available 2253 | * but then block when reading it. Add special case code 2254 | * to work around these arguably broken applications. 2255 | */ 2256 | unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) 2257 | { 2258 | unsigned int mask = datagram_poll(file, sock, wait); 2259 | struct sock *sk = sock->sk; 2260 | 2261 | sock_rps_record_flow(sk); 2262 | 2263 | /* Check for false positives due to checksum errors */ 2264 | if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && 2265 | !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk)) 2266 | mask &= ~(POLLIN | POLLRDNORM); 2267 | 2268 | return mask; 2269 | 2270 | } 2271 | EXPORT_SYMBOL(udp_poll); 2272 | 2273 | struct proto udp_prot = { 2274 | .name = "UDP", 2275 | .owner = THIS_MODULE, 2276 | .close = udp_lib_close, 2277 | .connect = ip4_datagram_connect, 2278 | .disconnect = udp_disconnect, 2279 | .ioctl = udp_ioctl, 2280 | .destroy = udp_destroy_sock, 2281 | .setsockopt = udp_setsockopt, 2282 | .getsockopt = udp_getsockopt, 2283 | .sendmsg = udp_sendmsg, 2284 | .recvmsg = udp_recvmsg, 2285 | .sendpage = udp_sendpage, 2286 | .backlog_rcv = __udp_queue_rcv_skb, 2287 | .release_cb = ip4_datagram_release_cb, 2288 | .hash = udp_lib_hash, 2289 | .unhash = udp_lib_unhash, 2290 | .rehash = udp_v4_rehash, 2291 | .get_port = udp_v4_get_port, 2292 | .memory_allocated = &udp_memory_allocated, 2293 | .sysctl_mem = sysctl_udp_mem, 2294 | .sysctl_wmem = &sysctl_udp_wmem_min, 2295 | .sysctl_rmem = &sysctl_udp_rmem_min, 2296 | .obj_size = sizeof(struct udp_sock), 2297 | .slab_flags = SLAB_DESTROY_BY_RCU, 2298 | .h.udp_table = &udp_table, 2299 | #ifdef CONFIG_COMPAT 2300 | .compat_setsockopt = compat_udp_setsockopt, 2301 | .compat_getsockopt = compat_udp_getsockopt, 2302 | #endif 2303 | .clear_sk = sk_prot_clear_portaddr_nulls, 2304 | }; 2305 | EXPORT_SYMBOL(udp_prot); 2306 | 2307 | /* ------------------------------------------------------------------------ */ 2308 | #ifdef CONFIG_PROC_FS 2309 | 2310 | static struct sock *udp_get_first(struct seq_file *seq, int start) 2311 | { 2312 | struct sock *sk; 2313 | struct udp_iter_state *state = seq->private; 2314 | struct net *net = seq_file_net(seq); 2315 | 2316 | for (state->bucket = start; state->bucket <= state->udp_table->mask; 2317 | ++state->bucket) { 2318 | struct hlist_nulls_node *node; 2319 | struct udp_hslot *hslot = &state->udp_table->hash[state->bucket]; 2320 | 2321 | if (hlist_nulls_empty(&hslot->head)) 2322 | continue; 2323 | 2324 | spin_lock_bh(&hslot->lock); 2325 | sk_nulls_for_each(sk, node, &hslot->head) { 2326 | if (!net_eq(sock_net(sk), net)) 2327 | continue; 2328 | if (sk->sk_family == state->family) 2329 | goto found; 2330 | } 2331 | spin_unlock_bh(&hslot->lock); 2332 | } 2333 | sk = NULL; 2334 | found: 2335 | return sk; 2336 | } 2337 | 2338 | static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) 2339 | { 2340 | struct udp_iter_state *state = seq->private; 2341 | struct net *net = seq_file_net(seq); 2342 | 2343 | do { 2344 | sk = sk_nulls_next(sk); 2345 | } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); 2346 | 2347 | if (!sk) { 2348 | if (state->bucket <= state->udp_table->mask) 2349 | spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); 2350 | return udp_get_first(seq, state->bucket + 1); 2351 | } 2352 | return sk; 2353 | } 2354 | 2355 | static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) 2356 | { 2357 | struct sock *sk = udp_get_first(seq, 0); 2358 | 2359 | if (sk) 2360 | while (pos && (sk = udp_get_next(seq, sk)) != NULL) 2361 | --pos; 2362 | return pos ? NULL : sk; 2363 | } 2364 | 2365 | static void *udp_seq_start(struct seq_file *seq, loff_t *pos) 2366 | { 2367 | struct udp_iter_state *state = seq->private; 2368 | state->bucket = MAX_UDP_PORTS; 2369 | 2370 | return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN; 2371 | } 2372 | 2373 | static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2374 | { 2375 | struct sock *sk; 2376 | 2377 | if (v == SEQ_START_TOKEN) 2378 | sk = udp_get_idx(seq, 0); 2379 | else 2380 | sk = udp_get_next(seq, v); 2381 | 2382 | ++*pos; 2383 | return sk; 2384 | } 2385 | 2386 | static void udp_seq_stop(struct seq_file *seq, void *v) 2387 | { 2388 | struct udp_iter_state *state = seq->private; 2389 | 2390 | if (state->bucket <= state->udp_table->mask) 2391 | spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); 2392 | } 2393 | 2394 | int udp_seq_open(struct inode *inode, struct file *file) 2395 | { 2396 | struct udp_seq_afinfo *afinfo = PDE_DATA(inode); 2397 | struct udp_iter_state *s; 2398 | int err; 2399 | 2400 | err = seq_open_net(inode, file, &afinfo->seq_ops, 2401 | sizeof(struct udp_iter_state)); 2402 | if (err < 0) 2403 | return err; 2404 | 2405 | s = ((struct seq_file *)file->private_data)->private; 2406 | s->family = afinfo->family; 2407 | s->udp_table = afinfo->udp_table; 2408 | return err; 2409 | } 2410 | EXPORT_SYMBOL(udp_seq_open); 2411 | 2412 | /* ------------------------------------------------------------------------ */ 2413 | int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) 2414 | { 2415 | struct proc_dir_entry *p; 2416 | int rc = 0; 2417 | 2418 | afinfo->seq_ops.start = udp_seq_start; 2419 | afinfo->seq_ops.next = udp_seq_next; 2420 | afinfo->seq_ops.stop = udp_seq_stop; 2421 | 2422 | p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, 2423 | afinfo->seq_fops, afinfo); 2424 | if (!p) 2425 | rc = -ENOMEM; 2426 | return rc; 2427 | } 2428 | EXPORT_SYMBOL(udp_proc_register); 2429 | 2430 | void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) 2431 | { 2432 | remove_proc_entry(afinfo->name, net->proc_net); 2433 | } 2434 | EXPORT_SYMBOL(udp_proc_unregister); 2435 | 2436 | /* ------------------------------------------------------------------------ */ 2437 | static void udp4_format_sock(struct sock *sp, struct seq_file *f, 2438 | int bucket) 2439 | { 2440 | struct inet_sock *inet = inet_sk(sp); 2441 | __be32 dest = inet->inet_daddr; 2442 | __be32 src = inet->inet_rcv_saddr; 2443 | __u16 destp = ntohs(inet->inet_dport); 2444 | __u16 srcp = ntohs(inet->inet_sport); 2445 | 2446 | seq_printf(f, "%5d: %08X:%04X %08X:%04X" 2447 | " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", 2448 | bucket, src, srcp, dest, destp, sp->sk_state, 2449 | sk_wmem_alloc_get(sp), 2450 | sk_rmem_alloc_get(sp), 2451 | 0, 0L, 0, 2452 | from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)), 2453 | 0, sock_i_ino(sp), 2454 | atomic_read(&sp->sk_refcnt), sp, 2455 | atomic_read(&sp->sk_drops)); 2456 | } 2457 | 2458 | int udp4_seq_show(struct seq_file *seq, void *v) 2459 | { 2460 | seq_setwidth(seq, 127); 2461 | if (v == SEQ_START_TOKEN) 2462 | seq_puts(seq, " sl local_address rem_address st tx_queue " 2463 | "rx_queue tr tm->when retrnsmt uid timeout " 2464 | "inode ref pointer drops"); 2465 | else { 2466 | struct udp_iter_state *state = seq->private; 2467 | 2468 | udp4_format_sock(v, seq, state->bucket); 2469 | } 2470 | seq_pad(seq, '\n'); 2471 | return 0; 2472 | } 2473 | 2474 | static const struct file_operations udp_afinfo_seq_fops = { 2475 | .owner = THIS_MODULE, 2476 | .open = udp_seq_open, 2477 | .read = seq_read, 2478 | .llseek = seq_lseek, 2479 | .release = seq_release_net 2480 | }; 2481 | 2482 | /* ------------------------------------------------------------------------ */ 2483 | static struct udp_seq_afinfo udp4_seq_afinfo = { 2484 | .name = "udp", 2485 | .family = AF_INET, 2486 | .udp_table = &udp_table, 2487 | .seq_fops = &udp_afinfo_seq_fops, 2488 | .seq_ops = { 2489 | .show = udp4_seq_show, 2490 | }, 2491 | }; 2492 | 2493 | static int __net_init udp4_proc_init_net(struct net *net) 2494 | { 2495 | return udp_proc_register(net, &udp4_seq_afinfo); 2496 | } 2497 | 2498 | static void __net_exit udp4_proc_exit_net(struct net *net) 2499 | { 2500 | udp_proc_unregister(net, &udp4_seq_afinfo); 2501 | } 2502 | 2503 | static struct pernet_operations udp4_net_ops = { 2504 | .init = udp4_proc_init_net, 2505 | .exit = udp4_proc_exit_net, 2506 | }; 2507 | 2508 | int __init udp4_proc_init(void) 2509 | { 2510 | return register_pernet_subsys(&udp4_net_ops); 2511 | } 2512 | 2513 | void udp4_proc_exit(void) 2514 | { 2515 | unregister_pernet_subsys(&udp4_net_ops); 2516 | } 2517 | #endif /* CONFIG_PROC_FS */ 2518 | 2519 | static __initdata unsigned long uhash_entries; 2520 | static int __init set_uhash_entries(char *str) 2521 | { 2522 | ssize_t ret; 2523 | 2524 | if (!str) 2525 | return 0; 2526 | 2527 | ret = kstrtoul(str, 0, &uhash_entries); 2528 | if (ret) 2529 | return 0; 2530 | 2531 | if (uhash_entries && uhash_entries < UDP_HTABLE_SIZE_MIN) 2532 | uhash_entries = UDP_HTABLE_SIZE_MIN; 2533 | return 1; 2534 | } 2535 | __setup("uhash_entries=", set_uhash_entries); 2536 | 2537 | void __init udp_table_init(struct udp_table *table, const char *name) 2538 | { 2539 | unsigned int i; 2540 | 2541 | table->hash = alloc_large_system_hash(name, 2542 | 2 * sizeof(struct udp_hslot), 2543 | uhash_entries, 2544 | 21, /* one slot per 2 MB */ 2545 | 0, 2546 | &table->log, 2547 | &table->mask, 2548 | UDP_HTABLE_SIZE_MIN, 2549 | 64 * 1024); 2550 | 2551 | table->hash2 = table->hash + (table->mask + 1); 2552 | for (i = 0; i <= table->mask; i++) { 2553 | INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); 2554 | table->hash[i].count = 0; 2555 | spin_lock_init(&table->hash[i].lock); 2556 | } 2557 | for (i = 0; i <= table->mask; i++) { 2558 | INIT_HLIST_NULLS_HEAD(&table->hash2[i].head, i); 2559 | table->hash2[i].count = 0; 2560 | spin_lock_init(&table->hash2[i].lock); 2561 | } 2562 | } 2563 | 2564 | void __init udp_init(void) 2565 | { 2566 | unsigned long limit; 2567 | 2568 | udp_table_init(&udp_table, "UDP"); 2569 | limit = nr_free_buffer_pages() / 8; 2570 | limit = max(limit, 128UL); 2571 | sysctl_udp_mem[0] = limit / 4 * 3; 2572 | sysctl_udp_mem[1] = limit; 2573 | sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2; 2574 | 2575 | sysctl_udp_rmem_min = SK_MEM_QUANTUM; 2576 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; 2577 | } 2578 | --------------------------------------------------------------------------------