├── 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 | 
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 |
--------------------------------------------------------------------------------